summaryrefslogtreecommitdiffstats
path: root/openpgp/src
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src')
-rw-r--r--openpgp/src/autocrypt.rs7
-rw-r--r--openpgp/src/crypto/asymmetric.rs52
-rw-r--r--openpgp/src/crypto/ecdh.rs43
-rw-r--r--openpgp/src/crypto/hash.rs33
-rw-r--r--openpgp/src/crypto/sexp.rs13
-rw-r--r--openpgp/src/lib.rs10
-rw-r--r--openpgp/src/message/mod.rs4
-rw-r--r--openpgp/src/packet/key/mod.rs (renamed from openpgp/src/packet/key.rs)614
-rw-r--r--openpgp/src/packet/mod.rs53
-rw-r--r--openpgp/src/packet/pkesk.rs36
-rw-r--r--openpgp/src/packet/prelude.rs1
-rw-r--r--openpgp/src/packet/signature/mod.rs162
-rw-r--r--openpgp/src/packet/signature/subpacket.rs27
-rw-r--r--openpgp/src/parse/parse.rs61
-rw-r--r--openpgp/src/parse/stream.rs49
-rw-r--r--openpgp/src/serialize/mod.rs34
-rw-r--r--openpgp/src/serialize/stream.rs80
-rw-r--r--openpgp/src/serialize/tpk.rs63
-rw-r--r--openpgp/src/tpk/bindings.rs105
-rw-r--r--openpgp/src/tpk/builder.rs25
-rw-r--r--openpgp/src/tpk/keyiter.rs60
-rw-r--r--openpgp/src/tpk/mod.rs96
-rw-r--r--openpgp/src/tpk/parser/grammar.lalrpop29
-rw-r--r--openpgp/src/tpk/parser/lexer.rs6
24 files changed, 1252 insertions, 411 deletions
diff --git a/openpgp/src/autocrypt.rs b/openpgp/src/autocrypt.rs
index b15fddbf..39d374d8 100644
--- a/openpgp/src/autocrypt.rs
+++ b/openpgp/src/autocrypt.rs
@@ -101,13 +101,13 @@ impl AutocryptHeader {
-> Result<Self>
where P: Into<Option<&'a str>>
{
- use crate::packet::Tag;
+ use crate::packet::key;
// Minimize TPK.
let mut acc = Vec::new();
// The primary key and the most recent selfsig.
- acc.push(tpk.primary().key().clone().into_packet(Tag::PublicKey)?);
+ acc.push(tpk.primary().key().clone().into());
tpk.selfsigs().iter().take(1)
.for_each(|s| acc.push(s.clone().into()));
@@ -120,7 +120,8 @@ impl AutocryptHeader {
continue;
}
- acc.push(skb.key().clone().into_packet(Tag::PublicSubkey)?);
+ let k : key::PublicSubkey = skb.key().clone();
+ acc.push(k.into());
skb.selfsigs().iter().take(1)
.for_each(|s| acc.push(s.clone().into()));
}
diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs
index af8ea7f0..9232bd14 100644
--- a/openpgp/src/crypto/asymmetric.rs
+++ b/openpgp/src/crypto/asymmetric.rs
@@ -2,7 +2,7 @@
use nettle::{dsa, ecc, ecdsa, ed25519, rsa, Yarrow};
-use crate::packet::{self, Key};
+use crate::packet::{self, key, Key};
use crate::crypto::SessionKey;
use crate::crypto::mpis::{self, MPI};
use crate::constants::{Curve, HashAlgorithm};
@@ -16,9 +16,11 @@ use crate::Result;
/// signature. Using this trait allows Sequoia to perform all
/// operations involving signing to use a variety of secret key
/// storage mechanisms (e.g. smart cards).
-pub trait Signer {
+pub trait Signer<R>
+ where R: key::KeyRole
+{
/// Returns a reference to the public key.
- fn public(&self) -> &Key;
+ fn public(&self) -> &Key<key::PublicParts, R>;
/// Creates a signature over the `digest` produced by `hash_algo`.
fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8])
@@ -31,9 +33,11 @@ pub trait Signer {
/// ciphertext. Using this trait allows Sequoia to perform all
/// operations involving decryption to use a variety of secret key
/// storage mechanisms (e.g. smart cards).
-pub trait Decryptor {
+pub trait Decryptor<R>
+ where R: key::KeyRole
+{
/// Returns a reference to the public key.
- fn public(&self) -> &Key;
+ fn public(&self) -> &Key<key::PublicParts, R>;
/// Decrypts `ciphertext`, returning the plain session key.
fn decrypt(&mut self, ciphertext: &mpis::Ciphertext)
@@ -49,14 +53,21 @@ pub trait Decryptor {
/// [`Signer`]: trait.Signer.html
/// [`Decryptor`]: trait.Decryptor.html
#[derive(Clone)]
-pub struct KeyPair {
- public: Key,
+pub struct KeyPair<R>
+ where R: key::KeyRole
+{
+ public: Key<key::PublicParts, R>,
secret: packet::key::Unencrypted,
}
-impl KeyPair {
+impl<R> KeyPair<R>
+ where R: key::KeyRole
+{
/// Creates a new key pair.
- pub fn new(public: Key, secret: packet::key::Unencrypted) -> Result<Self> {
+ pub fn new(public: Key<key::PublicParts, R>,
+ secret: packet::key::Unencrypted)
+ -> Result<Self>
+ {
Ok(Self {
public: public,
secret: secret,
@@ -64,7 +75,7 @@ impl KeyPair {
}
/// Returns a reference to the public key.
- pub fn public(&self) -> &Key {
+ pub fn public(&self) -> &Key<key::PublicParts, R> {
&self.public
}
@@ -74,8 +85,10 @@ impl KeyPair {
}
}
-impl Signer for KeyPair {
- fn public(&self) -> &Key {
+impl<R> Signer<R> for KeyPair<R>
+ where R: key::KeyRole
+{
+ fn public(&self) -> &Key<key::PublicParts, R> {
&self.public
}
@@ -202,8 +215,10 @@ impl Signer for KeyPair {
}
}
-impl Decryptor for KeyPair {
- fn public(&self) -> &Key {
+impl<R> Decryptor<R> for KeyPair<R>
+ where R: key::KeyRole
+{
+ fn public(&self) -> &Key<key::PublicParts, R> {
&self.public
}
@@ -248,11 +263,12 @@ impl Decryptor for KeyPair {
}
}
-impl From<KeyPair> for packet::Key {
- fn from(p: KeyPair) -> Self {
+impl<R> From<KeyPair<R>> for Key<key::SecretParts, R>
+ where R: key::KeyRole
+{
+ fn from(p: KeyPair<R>) -> Self {
let (mut key, secret) = (p.public, p.secret);
key.set_secret(Some(secret.into()));
- key
+ key.mark_parts_secret()
}
-
}
diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs
index a51362b6..9b8ad9e0 100644
--- a/openpgp/src/crypto/ecdh.rs
+++ b/openpgp/src/crypto/ecdh.rs
@@ -1,7 +1,10 @@
//! Elliptic Curve Diffie-Hellman.
use crate::Error;
-use crate::packet::Key;
+use crate::packet::{
+ Key,
+ key,
+};
use crate::Result;
use crate::constants::{
Curve,
@@ -20,7 +23,10 @@ use nettle::{cipher, curve25519, mode, Mode, ecc, ecdh, Yarrow};
/// Wraps a session key using Elliptic Curve Diffie-Hellman.
#[allow(non_snake_case)]
-pub fn encrypt(recipient: &Key, session_key: &SessionKey) -> Result<Ciphertext>
+pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
+ session_key: &SessionKey)
+ -> Result<Ciphertext>
+ where R: key::KeyRole
{
let mut rng = Yarrow::default();
@@ -130,9 +136,11 @@ pub fn encrypt(recipient: &Key, session_key: &SessionKey) -> Result<Ciphertext>
/// `VB` is the ephemeral public key (with 0x40 prefix), `S` is the
/// shared Diffie-Hellman secret.
#[allow(non_snake_case)]
-pub fn encrypt_shared(recipient: &Key, session_key: &SessionKey, VB: MPI,
- S: &Protected)
- -> Result<Ciphertext>
+pub fn encrypt_shared<R>(recipient: &Key<key::PublicParts, R>,
+ session_key: &SessionKey, VB: MPI,
+ S: &Protected)
+ -> Result<Ciphertext>
+ where R: key::KeyRole
{
match recipient.mpis() {
&PublicKey::ECDH{ ref curve, ref hash, ref sym,.. } => {
@@ -169,9 +177,12 @@ pub fn encrypt_shared(recipient: &Key, session_key: &SessionKey, VB: MPI,
/// Unwraps a session key using Elliptic Curve Diffie-Hellman.
#[allow(non_snake_case)]
-pub fn decrypt(recipient: &Key, recipient_sec: &SecretKeyMaterial,
- ciphertext: &Ciphertext)
- -> Result<SessionKey> {
+pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
+ recipient_sec: &SecretKeyMaterial,
+ ciphertext: &Ciphertext)
+ -> Result<SessionKey>
+ where R: key::KeyRole
+{
match (recipient.mpis(), recipient_sec, ciphertext) {
(PublicKey::ECDH { ref curve, ..},
SecretKeyMaterial::ECDH { ref scalar, },
@@ -280,8 +291,11 @@ pub fn decrypt(recipient: &Key, recipient_sec: &SecretKeyMaterial,
/// `recipient` is the message receiver's public key, `S` is the
/// shared Diffie-Hellman secret used to encrypt `ciphertext`.
#[allow(non_snake_case)]
-pub fn decrypt_shared(recipient: &Key, S: &Protected, ciphertext: &Ciphertext)
- -> Result<SessionKey>
+pub fn decrypt_shared<R>(recipient: &Key<key::PublicParts, R>,
+ S: &Protected,
+ ciphertext: &Ciphertext)
+ -> Result<SessionKey>
+ where R: key::KeyRole
{
match (recipient.mpis(), ciphertext) {
(PublicKey::ECDH { ref curve, ref hash, ref sym, ..},
@@ -308,8 +322,13 @@ pub fn decrypt_shared(recipient: &Key, S: &Protected, ciphertext: &Ciphertext)
}
}
-fn make_param(recipient: &Key, curve: &Curve, hash: &HashAlgorithm,
- sym: &SymmetricAlgorithm) -> Vec<u8> {
+fn make_param<P, R>(recipient: &Key<P, R>,
+ curve: &Curve, hash: &HashAlgorithm,
+ sym: &SymmetricAlgorithm)
+ -> Vec<u8>
+ where P: key::KeyParts,
+ R: key::KeyRole
+{
// Param = curve_OID_len || curve_OID ||
// public_key_alg_ID || 03 || 01 || KDF_hash_ID ||
// KEK_alg_ID for AESKeyWrap || "Anonymous Sender " ||
diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs
index 9ace7d38..3ffded0c 100644
--- a/openpgp/src/crypto/hash.rs
+++ b/openpgp/src/crypto/hash.rs
@@ -3,7 +3,7 @@
use crate::HashAlgorithm;
use crate::packet::UserID;
use crate::packet::UserAttribute;
-use crate::packet::Key;
+use crate::packet::key;
use crate::packet::key::Key4;
use crate::packet::Signature;
use crate::packet::signature::{self, Signature4};
@@ -221,7 +221,10 @@ impl Hash for UserAttribute {
}
}
-impl Hash for Key4 {
+impl<P, R> Hash for Key4<P, R>
+ where P: key::KeyParts,
+ R: key::KeyRole,
+{
/// Update the Hash with a hash of the key.
fn hash(&self, hash: &mut Context) {
// We hash 8 bytes plus the MPIs. But, the len doesn't
@@ -335,9 +338,10 @@ impl Hash for signature::Builder {
impl Signature {
/// Returns the message digest of the primary key binding over the
/// specified primary key.
- pub fn primary_key_binding_hash<'a, S>(sig: S, key: &Key)
+ pub fn primary_key_binding_hash<'a, S>(sig: S, key: &key::PublicKey)
-> Result<Vec<u8>>
- where S: Into<&'a signature::Builder> {
+ where S: Into<&'a signature::Builder>
+ {
let sig = sig.into();
let mut h = sig.hash_algo().context()?;
@@ -352,9 +356,12 @@ impl Signature {
/// Returns the message digest of the subkey binding over the
/// specified primary key and subkey.
- pub fn subkey_binding_hash<'a, S>(sig: S, key: &Key, subkey: &Key)
+ pub fn subkey_binding_hash<'a, S>(sig: S,
+ key: &key::PublicKey,
+ subkey: &key::PublicSubkey)
-> Result<Vec<u8>>
- where S: Into<&'a signature::Builder> {
+ where S: Into<&'a signature::Builder>
+ {
let sig = sig.into();
let mut h = sig.hash_algo().context()?;
@@ -370,10 +377,12 @@ impl Signature {
/// Returns the message digest of the user ID binding over the
/// specified primary key, user ID, and signature.
- pub fn userid_binding_hash<'a, S>(sig: S, key: &Key, userid: &UserID)
+ pub fn userid_binding_hash<'a, S>(sig: S,
+ key: &key::PublicKey,
+ userid: &UserID)
-> Result<Vec<u8>>
- where S: Into<&'a signature::Builder> {
-
+ where S: Into<&'a signature::Builder>
+ {
let sig = sig.into();
let mut h = sig.hash_algo().context()?;
@@ -388,10 +397,12 @@ impl Signature {
/// Returns the message digest of the user attribute binding over
/// the specified primary key, user attribute, and signature.
- pub fn user_attribute_binding_hash<'a, S>(sig: S, key: &Key,
+ pub fn user_attribute_binding_hash<'a, S>(sig: S,
+ key: &key::PublicKey,
ua: &UserAttribute)
-> Result<Vec<u8>>
- where S: Into<&'a signature::Builder> {
+ where S: Into<&'a signature::Builder>
+ {
let sig = sig.into();
let mut h = sig.hash_algo().context()?;
diff --git a/openpgp/src/crypto/sexp.rs b/openpgp/src/crypto/sexp.rs
index 454ed5e7..acd970aa 100644
--- a/openpgp/src/crypto/sexp.rs
+++ b/openpgp/src/crypto/sexp.rs
@@ -90,11 +90,14 @@ impl Sexp {
/// Such an expression is returned from gpg-agent's `PKDECRYPT`
/// command. `padding` must be set according to the status
/// messages sent.
- pub fn finish_decryption(&self,
- recipient: &crate::packet::Key,
- ciphertext: &mpis::Ciphertext,
- padding: bool)
- -> Result<SessionKey> {
+ pub fn finish_decryption<R>(&self,
+ recipient: &crate::packet::Key<
+ crate::packet::key::PublicParts, R>,
+ ciphertext: &mpis::Ciphertext,
+ padding: bool)
+ -> Result<SessionKey>
+ where R: crate::packet::key::KeyRole
+ {
use crate::crypto::mpis::PublicKey;
let not_a_session_key = || -> failure::Error {
Error::MalformedMPI(
diff --git a/openpgp/src/lib.rs b/openpgp/src/lib.rs
index 1c44137d..54b124c5 100644
--- a/openpgp/src/lib.rs
+++ b/openpgp/src/lib.rs
@@ -109,7 +109,7 @@ pub mod conversions;
pub mod crypto;
pub mod packet;
-use crate::packet::{BodyLength, Header, Container};
+use crate::packet::{BodyLength, Header, Container, key};
use crate::packet::ctb::{CTB, CTBOld, CTBNew};
pub mod parse;
@@ -265,13 +265,13 @@ pub enum Packet {
/// One pass signature packet.
OnePassSig(packet::OnePassSig),
/// Public key packet.
- PublicKey(packet::Key),
+ PublicKey(packet::key::PublicKey),
/// Public subkey packet.
- PublicSubkey(packet::Key),
+ PublicSubkey(packet::key::PublicSubkey),
/// Public/Secret key pair.
- SecretKey(packet::Key),
+ SecretKey(packet::key::SecretKey),
/// Public/Secret subkey pair.
- SecretSubkey(packet::Key),
+ SecretSubkey(packet::key::SecretSubkey),
/// Marker packet.
Marker(packet::Marker),
/// Trust packet.
diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs
index 877f503b..d36ddb3c 100644
--- a/openpgp/src/message/mod.rs
+++ b/openpgp/src/message/mod.rs
@@ -798,7 +798,7 @@ mod tests {
lit.set_body(b"data".to_vec());
let hash = crate::constants::HashAlgorithm::SHA512;
- let key: Key =
+ let key: key::SecretKey =
crate::packet::key::Key4::generate_ecc(true, crate::constants::Curve::Ed25519)
.unwrap().into();
let mut pair = key.clone().into_keypair().unwrap();
@@ -910,7 +910,7 @@ mod tests {
lit.set_body(b"data".to_vec());
let hash = crate::constants::HashAlgorithm::SHA512;
- let key: Key =
+ let key: key::SecretKey =
crate::packet::key::Key4::generate_ecc(true, crate::constants::Curve::Ed25519)
.unwrap().into();
let mut pair = key.clone().into_keypair().unwrap();
diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key/mod.rs
index 85b1ec86..5d9c9bef 100644
--- a/openpgp/src/packet/key.rs
+++ b/openpgp/src/packet/key/mod.rs
@@ -1,4 +1,54 @@
//! Public key, public subkey, private key and private subkey packets.
+//! Key variants.
+//!
+//! There are four variants of OpenPGP keys: public keys, public
+//! subkeys, secret keys, and secret subkeys. These are based on
+//! the cross product of two attributes: whether the key contains
+//! any secret key material, and the key's role.
+//!
+//! The underlying representation of these four variants is
+//! identical (even a public key and a secret key are the same:
+//! the public key variant just contains 0 bits of secret key
+//! material), and many (but not all) operations can be done on
+//! all four variants.
+//!
+//! We separate these variants into two types: parts (public or
+//! secret) and roles (primary or secondary). We also add
+//! unspecified variants, because sometimes we want a slice of
+//! keys, and we don't care about the key's role. For instance,
+//! when iterating over all of the keys in a TPK, we want the
+//! primary and the subkeys. These can't be put in the same slice
+//! without first wrapping them, which is awkward.
+//!
+//! For the most part, the user doesn't need to worry about the
+//! markers. Occasionally, it is necessary to change a key's markers.
+//! For these cases, it is possible to just use the `From` trait to
+//! get the require markers. But, it is also possible to explicitly
+//! set markers. Compare:
+//!
+//! ```rust
+//! # extern crate sequoia_openpgp as openpgp;
+//! # use openpgp::Result;
+//! # use openpgp::parse::{Parse, PacketParserResult, PacketParser};
+//! # use openpgp::tpk::TPKParser;
+//! # use openpgp::tpk::{CipherSuite, TPKBuilder};
+//! use openpgp::packet::{Key, key};
+//!
+//! # fn main() { f().unwrap(); }
+//! # fn f() -> Result<()>
+//! # {
+//! # let (tpk, _) = TPKBuilder::new()
+//! # .set_cipher_suite(CipherSuite::Cv25519)
+//! # .generate()?;
+//! // Get a handle to the TPK's primary key that allows using the
+//! // secret key material.
+//! let sk : &key::SecretKey = tpk.primary().key().into();
+//!
+//! // Make the conversion explicit.
+//! let sk : &key::SecretKey = tpk.primary().key().mark_parts_secret_ref();
+//! # Ok(())
+//! # }
+//! ```
use std::fmt;
use std::cmp::Ordering;
@@ -6,9 +56,8 @@ use time;
use crate::Error;
use crate::crypto::{self, mem::{self, Protected}, mpis, hash::Hash};
-use crate::packet::Tag;
use crate::packet;
-use crate::Packet;
+use crate::packet::prelude::*;
use crate::PublicKeyAlgorithm;
use crate::SymmetricAlgorithm;
use crate::HashAlgorithm;
@@ -20,13 +69,447 @@ use crate::crypto::Password;
use crate::KeyID;
use crate::Fingerprint;
+/// A marker trait that indicates whether a `Key` only contains
+/// public key material or *may* also contains secret key
+/// material.
+pub trait KeyParts: fmt::Debug {}
+
+/// A marker trait that indicates whether a `Key` is a primary key or
+/// subordinate key (i.e., a subkey).
+pub trait KeyRole: fmt::Debug {}
+
+/// Indicates that a `Key` should be treated like a public key.
+///
+/// Note: this doesn't indicate whether the data structure contains
+/// secret key material; it indicates whether any secret key material
+/// should be ignored. For instance, when exporting a key with the
+/// `PublicParts` marker, secret key material will *not* be exported.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct PublicParts;
+impl KeyParts for PublicParts {}
+
+/// Indicates that a `Key` should be treated like a secret key.
+///
+/// Note: this doesn't indicate whether the data structure contains
+/// secret key material; it indicates whether any secret key material
+/// should be used. For instance, when exporting a key with the
+/// `SecretParts` marker, secret key material will be exported.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct SecretParts;
+impl KeyParts for SecretParts {}
+
+/// Indicates that a `Key`'s parts are unspecified.
+///
+/// Neither public key-specific nor secret key-specific operations are
+/// allowed on such keys.
+///
+/// For instance, it is not possible to export a key with the
+/// `UnspecifiedParts` marker, because it is unclear how to treat any
+/// secret key material. To export such a key, you need to use a
+/// different `KeyParts` marker.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct UnspecifiedParts;
+impl KeyParts for UnspecifiedParts {}
+
+/// Indicates that a `Key` should treated like a primary key.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct PrimaryRole;
+impl KeyRole for PrimaryRole {}
+
+/// Indicates that a `Key` should treated like a subkey key.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct SubordinateRole;
+impl KeyRole for SubordinateRole {}
+
+/// Indicates that a `Key`'s role is unknown.
+///
+/// Neither primary key-specific nor subkey-specific operations
+/// are allowed.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct UnspecifiedRole;
+impl KeyRole for UnspecifiedRole {}
+
+/// A Public Key.
+pub type PublicKey = Key<PublicParts, PrimaryRole>;
+/// A Public Subkey.
+pub type PublicSubkey = Key<PublicParts, SubordinateRole>;
+/// A Secret Key.
+pub type SecretKey = Key<SecretParts, PrimaryRole>;
+/// A Secret Subkey.
+pub type SecretSubkey = Key<SecretParts, SubordinateRole>;
+
+/// A key with public parts, and an unspecified role
+/// (`UnspecifiedRole`).
+pub type UnspecifiedPublic = Key<PublicParts, UnspecifiedRole>;
+/// A key with secret parts, and an unspecified role
+/// (`UnspecifiedRole`).
+pub type UnspecifiedSecret = Key<SecretParts, UnspecifiedRole>;
+
+/// A primary key with unspecified parts (`UnspecifiedParts`).
+pub type UnspecifiedPrimary = Key<UnspecifiedParts, PrimaryRole>;
+/// A subkey key with unspecified parts (`UnspecifiedParts`).
+pub type UnspecifiedSecondary = Key<UnspecifiedParts, SubordinateRole>;
+
+/// A key whose parts and role are unspecified
+/// (`UnspecifiedParts`, `UnspecifiedRole`).
+pub type UnspecifiedKey = Key<UnspecifiedParts, UnspecifiedRole>;
+
+macro_rules! convert {
+ ( $x:ident ) => {
+ // XXX: This is ugly, but how can we do better?
+ unsafe { std::mem::transmute($x) }
+ }
+}
+
+macro_rules! convert_ref {
+ ( $x:id