summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-01-12 09:14:21 +0100
committerJustus Winter <justus@sequoia-pgp.org>2021-01-19 09:00:22 +0100
commit4cf73914f253c8c8d46ffc94b73213e0313343b3 (patch)
treec5dfa1c0add212bb11301865c1d6eb44f78ece01
parent7b960896802e8391930e0807fd7eae4a606b3978 (diff)
openpgp: Implement verification of attested key signatures.
- Note that the spec is still in flux, therefore we don't expose it.
-rw-r--r--openpgp/src/packet/signature.rs130
-rw-r--r--openpgp/src/packet/signature/subpacket.rs5
-rw-r--r--openpgp/src/types/mod.rs6
3 files changed, 141 insertions, 0 deletions
diff --git a/openpgp/src/packet/signature.rs b/openpgp/src/packet/signature.rs
index 079d09d1..0cdbf70b 100644
--- a/openpgp/src/packet/signature.rs
+++ b/openpgp/src/packet/signature.rs
@@ -2787,6 +2787,71 @@ impl Signature {
self.verify_digest(signer, &hash.into_digest()?[..])
}
+ /// Verifies an attested key signature on a user id.
+ ///
+ /// `self` is the attested key signature, `signer` is the key that
+ /// allegedly made the signature, `pk` is the primary key, and
+ /// `userid` is the user id.
+ ///
+ /// 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 `signer` 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.
+ #[allow(dead_code)]
+ pub(crate) fn verify_userid_attestation<P, Q, R>(
+ &mut self,
+ signer: &Key<P, R>,
+ pk: &Key<Q, key::PrimaryRole>,
+ userid: &UserID)
+ -> Result<()>
+ where P: key::KeyParts,
+ Q: key::KeyParts,
+ R: key::KeyRole,
+ {
+ use crate::types::SignatureType__AttestedKey;
+ use crate::packet::signature::subpacket
+ ::SubpacketTag__AttestedCertifications;
+
+ if self.typ() != SignatureType__AttestedKey {
+ return Err(Error::UnsupportedSignatureType(self.typ()).into());
+ }
+
+ let mut hash = self.hash_algo().context()?;
+
+ if self.hashed_area()
+ .subpackets(SubpacketTag__AttestedCertifications).count() != 1
+ || self.unhashed_area()
+ .subpackets(SubpacketTag__AttestedCertifications).count() != 0
+ {
+ return Err(Error::BadSignature(
+ "Wrong number of attested certification subpackets".into())
+ .into());
+ }
+
+ if let SubpacketValue::Unknown { body, .. } =
+ self.subpacket(SubpacketTag__AttestedCertifications).unwrap()
+ .value()
+ {
+ if body.len() % hash.digest_size() != 0 {
+ return Err(Error::BadSignature(
+ "Wrong number of bytes in certification subpacket".into())
+ .into());
+ }
+ } else {
+ unreachable!("Selected attested certifications, got wrong value");
+ }
+
+ self.hash_userid_binding(&mut hash, pk, userid);
+ self.verify_digest(signer, &hash.into_digest()?[..])
+ }
+
/// Verifies the user attribute binding.
///
/// `self` is the user attribute binding signature, `signer` is
@@ -2865,6 +2930,71 @@ impl Signature {
self.verify_digest(signer, &hash.into_digest()?[..])
}
+ /// Verifies an attested key signature on a user attribute.
+ ///
+ /// `self` is the attested key signature, `signer` is the key that
+ /// allegedly made the signature, `pk` is the primary key, and
+ /// `ua` is the user attribute.
+ ///
+ /// 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 `signer` 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.
+ #[allow(dead_code)]
+ pub(crate) fn verify_user_attribute_attestation<P, Q, R>(
+ &mut self,
+ signer: &Key<P, R>,
+ pk: &Key<Q, key::PrimaryRole>,
+ ua: &UserAttribute)
+ -> Result<()>
+ where P: key::KeyParts,
+ Q: key::KeyParts,
+ R: key::KeyRole,
+ {
+ use crate::types::SignatureType__AttestedKey;
+ use crate::packet::signature::subpacket
+ ::SubpacketTag__AttestedCertifications;
+
+ if self.typ() != SignatureType__AttestedKey {
+ return Err(Error::UnsupportedSignatureType(self.typ()).into());
+ }
+
+ let mut hash = self.hash_algo().context()?;
+
+ if self.hashed_area()
+ .subpackets(SubpacketTag__AttestedCertifications).count() != 1
+ || self.unhashed_area()
+ .subpackets(SubpacketTag__AttestedCertifications).count() != 0
+ {
+ return Err(Error::BadSignature(
+ "Wrong number of attested certification subpackets".into())
+ .into());
+ }
+
+ if let SubpacketValue::Unknown { body, .. } =
+ self.subpacket(SubpacketTag__AttestedCertifications).unwrap()
+ .value()
+ {
+ if body.len() % hash.digest_size() != 0 {
+ return Err(Error::BadSignature(
+ "Wrong number of bytes in certification subpacket".into())
+ .into());
+ }
+ } else {
+ unreachable!("Selected attested certifications, got wrong value");
+ }
+
+ self.hash_user_attribute_binding(&mut hash, pk, ua);
+ self.verify_digest(signer, &hash.into_digest()?[..])
+ }
+
/// Verifies a signature of a message.
///
/// `self` is the message signature, `signer` is
diff --git a/openpgp/src/packet/signature/subpacket.rs b/openpgp/src/packet/signature/subpacket.rs
index d97593c0..601649b2 100644
--- a/openpgp/src/packet/signature/subpacket.rs
+++ b/openpgp/src/packet/signature/subpacket.rs
@@ -326,6 +326,11 @@ pub enum SubpacketTag {
}
assert_send_and_sync!(SubpacketTag);
+/// The proposed Attested Certifications subpacket.
+#[allow(non_upper_case_globals)]
+pub(crate) const SubpacketTag__AttestedCertifications: SubpacketTag =
+ SubpacketTag::Unknown(37);
+
impl fmt::Display for SubpacketTag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs
index cc408770..951cfa8e 100644
--- a/openpgp/src/types/mod.rs
+++ b/openpgp/src/types/mod.rs
@@ -1127,6 +1127,12 @@ pub enum SignatureType {
}
assert_send_and_sync!(SignatureType);
+/// An attested key signature.
+#[allow(non_upper_case_globals)]
+pub(crate) const SignatureType__AttestedKey: SignatureType =
+ SignatureType::Unknown(0x16);
+
+
impl From<u8> for SignatureType {
fn from(u: u8) -> Self {
match u {