From e9aba8ffe0ac9f8737f4b0235c0c2e45b2944c1d Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 12 Dec 2017 15:52:57 +0100 Subject: Rename and move keys module to openpgp::tpk. --- src/ffi.rs | 2 +- src/keys.rs | 272 ----------------------------------------------------- src/lib.rs | 1 - src/net/mod.rs | 8 +- src/openpgp/mod.rs | 1 + src/openpgp/tpk.rs | 272 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 278 insertions(+), 278 deletions(-) delete mode 100644 src/keys.rs create mode 100644 src/openpgp/tpk.rs diff --git a/src/ffi.rs b/src/ffi.rs index 735b1186..0d73cbeb 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -6,8 +6,8 @@ use std::ptr; use std::slice; use std::str; -use keys::TPK; use net::KeyServer; +use openpgp::tpk::TPK; use openpgp::types::KeyId; use self::libc::{uint8_t, uint64_t, c_char, size_t}; use self::native_tls::Certificate; diff --git a/src/keys.rs b/src/keys.rs deleted file mode 100644 index ec31ac9a..00000000 --- a/src/keys.rs +++ /dev/null @@ -1,272 +0,0 @@ -use io; - -use super::openpgp; -use super::openpgp::Packet; - -/// A transferable public key (TPK). -/// -/// A TPK (see [RFC 4880, section 11.1]) can be used to verify -/// signatures and encrypt data. It can be stored in a keystore and -/// uploaded to keyservers. -/// -/// [RFC 4880, section 11.1]: https://tools.ietf.org/html/rfc4880#section-11.1 -#[derive(Debug)] -pub struct TPK { - primary: openpgp::Key, - userids: Vec, - subkeys: Vec, -} - -#[derive(Debug)] -pub struct SubkeyBinding { - subkey: openpgp::Key, - signatures: Vec, -} - -#[derive(Debug)] -pub struct UserIDBinding { - userid: openpgp::UserID, - signatures: Vec, -} - -#[derive(Debug)] -enum States { - Start, - TPK, - UserID(UserIDBinding), - Subkey(SubkeyBinding), - End, -} - -impl TPK { - /// Returns the first TPK found in `m`. - pub fn from_message(m: openpgp::Message) -> Result { - let mut state = States::Start; - let mut primary = None; - let mut userids = vec![]; - let mut subkeys = vec![]; - for p in m.into_iter() { - state = match state { - States::Start => { - /* Find the first public key packet. */ - match p { - Packet::PublicKey(pk) => { - primary = Some(pk); - States::TPK - }, - _ => States::Start, - } - }, - States::TPK => { - /* Find user id, or subkey packets. */ - match p { - Packet::PublicKey(_pk) => { - States::End - }, - Packet::UserID(uid) => { - States::UserID(UserIDBinding{userid: uid, signatures: vec![]}) - }, - Packet::PublicSubkey(key) => { - States::Subkey(SubkeyBinding{subkey: key, signatures: vec![]}) - }, - _ => States::TPK, - } - }, - States::UserID(mut u) => { - /* Find signature packets. */ - match p { - Packet::PublicKey(_pk) => { - States::End - }, - Packet::UserID(uid) => { - userids.push(u); - States::UserID(UserIDBinding{userid: uid, signatures: vec![]}) - }, - Packet::PublicSubkey(key) => { - userids.push(u); - States::Subkey(SubkeyBinding{subkey: key, signatures: vec![]}) - }, - Packet::Signature(sig) => { - u.signatures.push(sig); - States::UserID(u) - }, - _ => States::UserID(u), - } - }, - States::Subkey(mut s) => { - /* Find signature packets. */ - match p { - Packet::PublicKey(_pk) => { - States::End - }, - Packet::UserID(uid) => { - subkeys.push(s); - States::UserID(UserIDBinding{userid: uid, signatures: vec![]}) - }, - Packet::PublicSubkey(key) => { - subkeys.push(s); - States::Subkey(SubkeyBinding{subkey: key, signatures: vec![]}) - }, - Packet::Signature(sig) => { - s.signatures.push(sig); - States::Subkey(s) - }, - _ => States::Subkey(s), - } - }, - States::End => break, - }; - } - - let mut tpk = if let Some(p) = primary { - TPK{primary: p, userids: userids, subkeys: subkeys} - } else { - return Err(Error::NoKeyFound); - }; - - match state { - States::UserID(u) => { - tpk.userids.push(u); - Ok(tpk) - }, - States::Subkey(s) => { - tpk.subkeys.push(s); - Ok(tpk) - }, - States::End => Ok(tpk), - _ => Err(Error::NoKeyFound), - }.and_then(|tpk| tpk.canonicalize()) - } - - /// Returns the first TPK found in `buf`. - /// - /// `buf` must be an OpenPGP encoded message. - pub fn from_bytes(buf: &[u8]) -> Result { - openpgp::Message::from_bytes(buf) - .map_err(|e| Error::IoError(e)) - .and_then(Self::from_message) - } - - fn canonicalize(mut self) -> Result { - // Sanity checks. - - // - One or more User ID packets. - if self.userids.len() == 0 { - return Err(Error::NoUserId); - } - - // Drop user ids. - self.userids.retain(|userid| { - // XXX Check binding signature. - userid.signatures.len() > 0 - }); - - // Drop invalid subkeys. - self.subkeys.retain(|subkey| { - // XXX Check binding signature. - subkey.signatures.len() > 0 - }); - - // XXX Do some more canonicalization. - - Ok(self) - } - - /// Serialize the transferable public key into an OpenPGP message. - pub fn to_message(self) -> openpgp::Message { - let mut p : Vec = Vec::new(); - - p.push(openpgp::Packet::PublicKey(self.primary)); - - for u in self.userids.into_iter() { - p.push(openpgp::Packet::UserID(u.userid)); - for s in u.signatures.into_iter() { - p.push(openpgp::Packet::Signature(s)); - } - } - - let subkeys = self.subkeys; - for k in subkeys.into_iter() { - p.push(openpgp::Packet::PublicSubkey(k.subkey)); - for s in k.signatures.into_iter() { - p.push(openpgp::Packet::Signature(s)); - } - } - - openpgp::Message::from_packets(p) - } -} - -type Result = ::std::result::Result; - -/// Errors returned from the key routines. -#[derive(Debug)] -pub enum Error { - /// No key found in OpenPGP message. - NoKeyFound, - /// No user id found. - NoUserId, - /// An `io::Error` occured. - IoError(io::Error), -} - -impl From for Error { - fn from(error: io::Error) -> Self { - Error::IoError(error) - } -} - -#[cfg(test)] -mod test { - use super::{Error, TPK, openpgp}; - - macro_rules! bytes { - ( $x:expr ) => { include_bytes!(concat!("../tests/data/keys/", $x)) }; - } - - #[test] - fn broken() { - let m = openpgp::Message::from_bytes(bytes!("testy-broken-no-pk.pgp")).unwrap(); - if let Err(Error::NoKeyFound) = TPK::from_message(m) { - /* Pass. */ - } else { - panic!("Expected error, got none."); - } - - let m = openpgp::Message::from_bytes(bytes!("testy-broken-no-uid.pgp")).unwrap(); - if let Err(Error::NoUserId) = TPK::from_message(m) { - /* Pass. */ - } else { - panic!("Expected error, got none."); - } - - let m = openpgp::Message::from_bytes(bytes!("testy-broken-no-sig-on-subkey.pgp")).unwrap(); - let tpk = TPK::from_message(m).unwrap(); - assert_eq!(tpk.subkeys.len(), 0); - } - - #[test] - fn basics() { - let m = openpgp::Message::from_bytes(bytes!("testy.pgp")).unwrap(); - let orig_dbg = format!("{:?}", m); - let tpk = TPK::from_message(m).unwrap(); - //println!("{:?}", tpk); - - assert_eq!(tpk.userids.len(), 1, "number of userids"); - // XXX .value is private - //assert_eq!(tpk.userids[0].userid.value, "Testy McTestface "); - assert_eq!(tpk.subkeys.len(), 1, "number of subkeys"); - - // XXX Messages cannot be compared. - assert_eq!(format!("{:?}", tpk.to_message()), orig_dbg); - - let m = openpgp::Message::from_bytes(bytes!("testy-no-subkey.pgp")).unwrap(); - let orig_dbg = format!("{:?}", m); - let tpk = TPK::from_message(m).unwrap(); - - assert_eq!(tpk.userids.len(), 1, "number of userids"); - assert_eq!(tpk.subkeys.len(), 0, "number of subkeys"); - // XXX Messages cannot be compared. - assert_eq!(format!("{:?}", tpk.to_message()), orig_dbg); - } -} diff --git a/src/lib.rs b/src/lib.rs index 0c16e711..dd00ddcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,6 @@ extern crate bzip2; extern crate percent_encoding; pub mod openpgp; -pub mod keys; pub mod store; pub mod net; pub mod ffi; diff --git a/src/net/mod.rs b/src/net/mod.rs index 672b4422..698210eb 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -41,7 +41,7 @@ use std::io::{Cursor, Read}; use std::io; use super::Context; -use super::keys::{self, TPK}; +use super::openpgp::tpk::{self, TPK}; use super::openpgp::types::KeyId; use super::openpgp::{self, armor}; @@ -236,7 +236,7 @@ pub enum Error { /// A communication partner violated the protocol. ProtocolViolation, /// There was an error parsing the key. - KeysError(keys::Error), + KeysError(tpk::Error), /// Encountered an unexpected low-level http status. HttpStatus(hyper::StatusCode), /// An `io::Error` occured. @@ -249,8 +249,8 @@ pub enum Error { TlsError(native_tls::Error), } -impl From for Error { - fn from(e: keys::Error) -> Self { +impl From for Error { + fn from(e: tpk::Error) -> Self { Error::KeysError(e) } } diff --git a/src/openpgp/mod.rs b/src/openpgp/mod.rs index 46081fbe..0b27e330 100644 --- a/src/openpgp/mod.rs +++ b/src/openpgp/mod.rs @@ -5,6 +5,7 @@ pub mod armor; pub mod parse; +pub mod tpk; pub mod types; include!("openpgp.rs"); diff --git a/src/openpgp/tpk.rs b/src/openpgp/tpk.rs new file mode 100644 index 00000000..d95109ab --- /dev/null +++ b/src/openpgp/tpk.rs @@ -0,0 +1,272 @@ +use io; + +use openpgp; +use super::Packet; + +/// A transferable public key (TPK). +/// +/// A TPK (see [RFC 4880, section 11.1]) can be used to verify +/// signatures and encrypt data. It can be stored in a keystore and +/// uploaded to keyservers. +/// +/// [RFC 4880, section 11.1]: https://tools.ietf.org/html/rfc4880#section-11.1 +#[derive(Debug)] +pub struct TPK { + primary: openpgp::Key, + userids: Vec, + subkeys: Vec, +} + +#[derive(Debug)] +pub struct SubkeyBinding { + subkey: openpgp::Key, + signatures: Vec, +} + +#[derive(Debug)] +pub struct UserIDBinding { + userid: openpgp::UserID, + signatures: Vec, +} + +#[derive(Debug)] +enum States { + Start, + TPK, + UserID(UserIDBinding), + Subkey(SubkeyBinding), + End, +} + +impl TPK { + /// Returns the first TPK found in `m`. + pub fn from_message(m: openpgp::Message) -> Result { + let mut state = States::Start; + let mut primary = None; + let mut userids = vec![]; + let mut subkeys = vec![]; + for p in m.into_iter() { + state = match state { + States::Start => { + /* Find the first public key packet. */ + match p { + Packet::PublicKey(pk) => { + primary = Some(pk); + States::TPK + }, + _ => States::Start, + } + }, + States::TPK => { + /* Find user id, or subkey packets. */ + match p { + Packet::PublicKey(_pk) => { + States::End + }, + Packet::UserID(uid) => { + States::UserID(UserIDBinding{userid: uid, signatures: vec![]}) + }, + Packet::PublicSubkey(key) => { + States::Subkey(SubkeyBinding{subkey: key, signatures: vec![]}) + }, + _ => States::TPK, + } + }, + States::UserID(mut u) => { + /* Find signature packets. */ + match p { + Packet::PublicKey(_pk) => { + States::End + }, + Packet::UserID(uid) => { + userids.push(u); + States::UserID(UserIDBinding{userid: uid, signatures: vec![]}) + }, + Packet::PublicSubkey(key) => { + userids.push(u); + States::Subkey(SubkeyBinding{subkey: key, signatures: vec![]}) + }, + Packet::Signature(sig) => { + u.signatures.push(sig); + States::UserID(u) + }, + _ => States::UserID(u), + } + }, + States::Subkey(mut s) => { + /* Find signature packets. */ + match p { + Packet::PublicKey(_pk) => { + States::End + }, + Packet::UserID(uid) => { + subkeys.push(s); + States::UserID(UserIDBinding{userid: uid, signatures: vec![]}) + }, + Packet::PublicSubkey(key) => { + subkeys.push(s); + States::Subkey(SubkeyBinding{subkey: key, signatures: vec![]}) + }, + Packet::Signature(sig) => { + s.signatures.push(sig); + States::Subkey(s) + }, + _ => States::Subkey(s), + } + }, + States::End => break, + }; + } + + let mut tpk = if let Some(p) = primary { + TPK{primary: p, userids: userids, subkeys: subkeys} + } else { + return Err(Error::NoKeyFound); + }; + + match state { + States::UserID(u) => { + tpk.userids.push(u); + Ok(tpk) + }, + States::Subkey(s) => { + tpk.subkeys.push(s); + Ok(tpk) + }, + States::End => Ok(tpk), + _ => Err(Error::NoKeyFound), + }.and_then(|tpk| tpk.canonicalize()) + } + + /// Returns the first TPK found in `buf`. + /// + /// `buf` must be an OpenPGP encoded message. + pub fn from_bytes(buf: &[u8]) -> Result { + openpgp::Message::from_bytes(buf) + .map_err(|e| Error::IoError(e)) + .and_then(Self::from_message) + } + + fn canonicalize(mut self) -> Result { + // Sanity checks. + + // - One or more User ID packets. + if self.userids.len() == 0 { + return Err(Error::NoUserId); + } + + // Drop user ids. + self.userids.retain(|userid| { + // XXX Check binding signature. + userid.signatures.len() > 0 + }); + + // Drop invalid subkeys. + self.subkeys.retain(|subkey| { + // XXX Check binding signature. + subkey.signatures.len() > 0 + }); + + // XXX Do some more canonicalization. + + Ok(self) + } + + /// Serialize the transferable public key into an OpenPGP message. + pub fn to_message(self) -> openpgp::Message { + let mut p : Vec = Vec::new(); + + p.push(openpgp::Packet::PublicKey(self.primary)); + + for u in self.userids.into_iter() { + p.push(openpgp::Packet::UserID(u.userid)); + for s in u.signatures.into_iter() { + p.push(openpgp::Packet::Signature(s)); + } + } + + let subkeys = self.subkeys; + for k in subkeys.into_iter() { + p.push(openpgp::Packet::PublicSubkey(k.subkey)); + for s in k.signatures.into_iter() { + p.push(openpgp::Packet::Signature(s)); + } + } + + openpgp::Message::from_packets(p) + } +} + +type Result = ::std::result::Result; + +/// Errors returned from the key routines. +#[derive(Debug)] +pub enum Error { + /// No key found in OpenPGP message. + NoKeyFound, + /// No user id found. + NoUserId, + /// An `io::Error` occured. + IoError(io::Error), +} + +impl From for Error { + fn from(error: io::Error) -> Self { + Error::IoError(error) + } +} + +#[cfg(test)] +mod test { + use super::{Error, TPK, openpgp}; + + macro_rules! bytes { + ( $x:expr ) => { include_bytes!(concat!("../../tests/data/keys/", $x)) }; + } + + #[test] + fn broken() { + let m = openpgp::Message::from_bytes(bytes!("testy-broken-no-pk.pgp")).unwrap(); + if let Err(Error::NoKeyFound) = TPK::from_message(m) { + /* Pass. */ + } else { + panic!("Expected error, got none."); + } + + let m = openpgp::Message::from_bytes(bytes!("testy-broken-no-uid.pgp")).unwrap(); + if let Err(Error::NoUserId) = TPK::from_message(m) { + /* Pass. */ + } else { + panic!("Expected error, got none."); + } + + let m = openpgp::Message::from_bytes(bytes!("testy-broken-no-sig-on-subkey.pgp")).unwrap(); + let tpk = TPK::from_message(m).unwrap(); + assert_eq!(tpk.subkeys.len(), 0); + } + + #[test] + fn basics() { + let m = openpgp::Message::from_bytes(bytes!("testy.pgp")).unwrap(); + let orig_dbg = format!("{:?}", m); + let tpk = TPK::from_message(m).unwrap(); + //println!("{:?}", tpk); + + assert_eq!(tpk.userids.len(), 1, "number of userids"); + // XXX .value is private + //assert_eq!(tpk.userids[0].userid.value, "Testy McTestface "); + assert_eq!(tpk.subkeys.len(), 1, "number of subkeys"); + + // XXX Messages cannot be compared. + assert_eq!(format!("{:?}", tpk.to_message()), orig_dbg); + + let m = openpgp::Message::from_bytes(bytes!("testy-no-subkey.pgp")).unwrap(); + let orig_dbg = format!("{:?}", m); + let tpk = TPK::from_message(m).unwrap(); + + assert_eq!(tpk.userids.len(), 1, "number of userids"); + assert_eq!(tpk.subkeys.len(), 0, "number of subkeys"); + // XXX Messages cannot be compared. + assert_eq!(format!("{:?}", tpk.to_message()), orig_dbg); + } +} -- cgit v1.2.3