summaryrefslogtreecommitdiffstats
path: root/openpgp/src/cert.rs
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-12-14 16:37:33 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-12-14 16:37:33 +0100
commit8c50ba96a5434aeefbf44e0d034072dfc6669521 (patch)
tree7c6a5d31c22dac12fa97c4545de873a3605c7b2e /openpgp/src/cert.rs
parent7e57122f0bd6db27c6e2f0c7deac1333256e5146 (diff)
openpgp: Change general purpose keys to have a signing subkey.
- Certificates with a primary key that is not signing capable, and a subkey that is, are strictly more secure than ones that combine signing and certification capabilities in the primary key. - If the owner of a certificate with a signing-capable primary key can be tricked into creating a binary signature over carefully chosen attacker-controlled data, this signature can be repurposed to bind arbitrary attacker-controlled components to the certificate using a chosen-prefix collision attack on the hash function (see e.g. "SHA-1 is a Shambles" for a similar attack). - Having a separate signing-subkey mitigates the attack, because signatures by the signing subkey cannot bind components to the certificate.
Diffstat (limited to 'openpgp/src/cert.rs')
-rw-r--r--openpgp/src/cert.rs14
1 files changed, 12 insertions, 2 deletions
diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs
index fc548cd2..648be37a 100644
--- a/openpgp/src/cert.rs
+++ b/openpgp/src/cert.rs
@@ -4034,6 +4034,8 @@ mod test {
+ 1 // binding signature
+ 1 // subkey
+ 1 // binding signature
+ + 1 // subkey
+ + 1 // binding signature
);
let cert = check_set_validity_period(p, cert);
assert_eq!(cert.clone().into_packet_pile().children().count(),
@@ -4045,6 +4047,8 @@ mod test {
+ 2 // two new binding signatures
+ 1 // subkey
+ 1 // binding signature
+ + 1 // subkey
+ + 1 // binding signature
);
}
@@ -4075,6 +4079,8 @@ mod test {
+ 1 // binding signature
+ 1 // subkey
+ 1 // binding signature
+ + 1 // subkey
+ + 1 // binding signature
);
let cert = check_set_validity_period(p, cert);
assert_eq!(cert.clone().into_packet_pile().children().count(),
@@ -4089,6 +4095,8 @@ mod test {
+ 2 // two new binding signatures
+ 1 // subkey
+ 1 // binding signature
+ + 1 // subkey
+ + 1 // binding signature
);
assert_eq!(&primary_uid, cert.with_policy(p, None)?.primary_userid()?.userid());
Ok(())
@@ -5674,11 +5682,12 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
let (cert, _) = CertBuilder::general_purpose(
None, Some("alice@example.org")).generate().unwrap();
assert_eq!(cert.userids().count(), 1);
- assert_eq!(cert.subkeys().count(), 1);
+ assert_eq!(cert.subkeys().count(), 2);
assert_eq!(cert.unknowns().count(), 0);
assert_eq!(cert.bad_signatures().count(), 0);
assert_eq!(cert.userids().nth(0).unwrap().self_signatures().len(), 1);
assert_eq!(cert.subkeys().nth(0).unwrap().self_signatures().len(), 1);
+ assert_eq!(cert.subkeys().nth(1).unwrap().self_signatures().len(), 1);
// Create a variant of cert where the signatures have
// additional information in the unhashed area.
@@ -5698,11 +5707,12 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
let cert_b = Cert::from_packets(packets.into_iter())?;
let cert = cert.merge_public_and_secret(cert_b)?;
assert_eq!(cert.userids().count(), 1);
- assert_eq!(cert.subkeys().count(), 1);
+ assert_eq!(cert.subkeys().count(), 2);
assert_eq!(cert.unknowns().count(), 0);
assert_eq!(cert.bad_signatures().count(), 0);
assert_eq!(cert.userids().nth(0).unwrap().self_signatures().len(), 1);
assert_eq!(cert.subkeys().nth(0).unwrap().self_signatures().len(), 1);
+ assert_eq!(cert.subkeys().nth(1).unwrap().self_signatures().len(), 1);
Ok(())
}