diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-12-16 11:51:33 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-12-16 11:51:33 +0100 |
commit | 94babb06f0210666fcb70415f37de5566d3a7834 (patch) | |
tree | 8ecabe57163ef6b7423d453121b40a5a39c4f2e6 | |
parent | 139aa5527f9b0d400151f26187bcd27f261973bd (diff) |
openpgp: Add methods for primary key binding signatures.
- Fixes #402.
-rw-r--r-- | openpgp/src/cert/builder.rs | 4 | ||||
-rw-r--r-- | openpgp/src/crypto/hash.rs | 14 | ||||
-rw-r--r-- | openpgp/src/packet/signature/mod.rs | 102 |
3 files changed, 77 insertions, 43 deletions
diff --git a/openpgp/src/cert/builder.rs b/openpgp/src/cert/builder.rs index 42780a65..ce1a0a6c 100644 --- a/openpgp/src/cert/builder.rs +++ b/openpgp/src/cert/builder.rs @@ -389,8 +389,8 @@ impl CertBuilder { time::SystemTime::now())? .set_issuer_fingerprint(subkey.fingerprint())? .set_issuer(subkey.keyid())? - .sign_subkey_binding(&mut subkey_signer, &primary, - &subkey.mark_parts_public_ref())?; + .sign_primary_key_binding(&mut subkey_signer, &primary, + &subkey)?; builder = builder.set_embedded_signature(backsig)?; } diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs index 12502c10..539970f1 100644 --- a/openpgp/src/crypto/hash.rs +++ b/openpgp/src/crypto/hash.rs @@ -415,6 +415,20 @@ impl Signature { Ok(digest) } + /// Returns the message digest of the primary key binding over the + /// specified primary key and subkey. + pub fn hash_primary_key_binding<'a, P, Q, S>( + sig: S, + key: &Key<P, key::PrimaryRole>, + subkey: &Key<Q, key::SubordinateRole>) + -> Result<Vec<u8>> + where P: key::KeyParts, + Q: key::KeyParts, + S: Into<&'a signature::Builder> + { + Self::hash_subkey_binding(sig.into(), key, subkey) + } + /// Returns the message digest of the user ID binding over the /// specified primary key, user ID, and signature. pub fn hash_userid_binding<'a, S>(sig: S, diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs index e849f8f9..3dc7f9e1 100644 --- a/openpgp/src/packet/signature/mod.rs +++ b/openpgp/src/packet/signature/mod.rs @@ -33,20 +33,20 @@ use nettle::rsa::verify_digest_pkcs1; pub mod subpacket; -const TRACE : bool = false; - /// Builds a signature packet. /// /// This is the mutable version of a `Signature4` packet. To convert /// it to one, use [`sign_hash`], [`sign_message`], /// [`sign_direct_key`], [`sign_subkey_binding`], -/// [`sign_userid_binding`], [`sign_user_attribute_binding`], -/// [`sign_standalone`], or [`sign_timestamp`], +/// [`sign_primary_key_binding`], [`sign_userid_binding`], +/// [`sign_user_attribute_binding`], [`sign_standalone`], or +/// [`sign_timestamp`], /// /// [`sign_hash`]: #method.sign_hash /// [`sign_message`]: #method.sign_message /// [`sign_direct_key`]: #method.sign_direct_key /// [`sign_subkey_binding`]: #method.sign_subkey_binding +/// [`sign_primary_key_binding`]: #method.sign_primary_key_binding /// [`sign_userid_binding`]: #method.sign_userid_binding /// [`sign_user_attribute_binding`]: #method.sign_user_attribute_binding /// [`sign_standalone`]: #method.sign_standalone @@ -206,6 +206,26 @@ impl Builder { self.sign(signer, digest) } + /// Signs primary key binding from `primary` to `subkey` using + /// `subkey_signer`. + /// + /// The Signature's public-key algorithm field is set to the + /// algorithm used by `subkey_signer`. + pub fn sign_primary_key_binding<P, Q>(mut self, + subkey_signer: &mut dyn Signer, + primary: &Key<P, key::PrimaryRole>, + subkey: &Key<Q, key::SubordinateRole>) + -> Result<Signature> + where P: key:: KeyParts, + Q: key:: KeyParts, + { + self.pk_algo = subkey_signer.public().pk_algo(); + let digest = + Signature::hash_primary_key_binding(&self, primary, subkey)?; + self.sign(subkey_signer, digest) + } + + /// Signs binding between `ua` and `key` using `signer`. /// /// The Signature's public-key algorithm field is set to the @@ -575,10 +595,10 @@ impl Signature4 { /// is not revoked, not expired, has a valid self-signature, has a /// subkey binding signature (if appropriate), has the signing /// capability, etc. - pub fn verify_digest<R, D>(&self, key: &Key<key::PublicParts, R>, - digest: D) + pub fn verify_digest<P, R, D>(&self, key: &Key<P, R>, digest: D) -> Result<bool> - where R: key::KeyRole, + where P: key::KeyParts, + R: key::KeyRole, D: AsRef<[u8]>, { use crate::PublicKeyAlgorithm::*; @@ -896,46 +916,46 @@ impl Signature4 { return Ok(true) } - let mut backsig_ok = false; if let Some(Packet::Signature(super::Signature::V4(backsig))) = self.embedded_signature() { - if backsig.typ() != SignatureType::PrimaryKeyBinding { - return Err(Error::UnsupportedSignatureType(self.typ()).into()); - } else { - // We can't use backsig.verify_subkey_binding. - let hash = Signature::hash_subkey_binding(&backsig, pk, subkey)?; - match backsig.verify_digest(subkey.mark_role_unspecified_ref(), - &hash[..]) - { - Ok(true) => { - if TRACE { - eprintln!("{} / {}: Backsig is good!", - pk.keyid(), subkey.keyid()); - } - backsig_ok = true; - }, - Ok(false) => { - if TRACE { - eprintln!("{} / {}: Backsig is bad!", - pk.keyid(), subkey.keyid()); - } - }, - Err(err) => { - if TRACE { - eprintln!("{} / {}: Error validating backsig: {}", - pk.keyid(), subkey.keyid(), - err); - } - }, - } - } + backsig.verify_primary_key_binding(pk, subkey) } else { - return Err(Error::BadSignature( - "Primary key binding signature missing".into()).into()); + Err(Error::BadSignature( + "Primary key binding signature missing".into()).into()) + } + } + + /// Verifies the primary key binding. + /// + /// `self` is the primary key binding signature, `pk` is the + /// primary key, and `subkey` is the subkey. + /// + /// Note: Due to limited context, this only verifies the + /// cryptographic signature, checks the signature's type, and + /// checks that the key predates the signature. Further + /// constraints on the signature, like creation and expiration + /// time, or signature revocations must be checked by the caller. + /// + /// Likewise, this function does not check whether `subkey` can + /// made valid signatures; it is up to the caller to make sure the + /// key is not revoked, not expired, has a valid self-signature, + /// has a subkey binding signature (if appropriate), has the + /// signing capability, etc. + pub fn verify_primary_key_binding<P, Q>( + &self, + pk: &Key<P, key::PrimaryRole>, + subkey: &Key<Q, key::SubordinateRole>) + -> Result<bool> + where P: key::KeyParts, + Q: key::KeyParts, + { + if self.typ() != SignatureType::PrimaryKeyBinding { + return Err(Error::UnsupportedSignatureType(self.typ()).into()); } - Ok(backsig_ok) + let hash = Signature::hash_primary_key_binding(self, pk, subkey)?; + self.verify_digest(subkey, &hash[..]) } /// Verifies the subkey revocation. |