summaryrefslogtreecommitdiffstats
path: root/openpgp/src/packet/signature.rs
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src/packet/signature.rs')
-rw-r--r--openpgp/src/packet/signature.rs155
1 files changed, 132 insertions, 23 deletions
diff --git a/openpgp/src/packet/signature.rs b/openpgp/src/packet/signature.rs
index c5f3b019..d09ea346 100644
--- a/openpgp/src/packet/signature.rs
+++ b/openpgp/src/packet/signature.rs
@@ -154,7 +154,7 @@ use crate::types::Timestamp;
#[cfg(test)]
/// Like quickcheck::Arbitrary, but bounded.
-trait ArbitraryBounded {
+pub(crate) trait ArbitraryBounded {
/// Generates an arbitrary value, but only recurses if `depth >
/// 0`.
fn arbitrary_bounded(g: &mut Gen, depth: usize) -> Self;
@@ -178,6 +178,8 @@ macro_rules! impl_arbitrary_with_bound {
}
pub mod subpacket;
+mod v6;
+pub use v6::Signature6;
/// How many seconds to backdate signatures.
///
@@ -285,6 +287,20 @@ impl SignatureFields {
}
}
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub(crate) enum SBVersion {
+ V4 {},
+ V6 {
+ salt: Vec<u8>,
+ },
+}
+
+impl Default for SBVersion {
+ fn default() -> Self {
+ SBVersion::V4 {}
+ }
+}
+
/// A Signature builder.
///
/// The `SignatureBuilder` is used to create [`Signature`]s. Although
@@ -451,7 +467,8 @@ pub struct SignatureBuilder {
reference_time: Option<SystemTime>,
overrode_creation_time: bool,
original_creation_time: Option<SystemTime>,
- fields: SignatureFields,
+ pub(crate) fields: SignatureFields,
+ pub(crate) version: SBVersion,
}
assert_send_and_sync!(SignatureBuilder);
@@ -482,7 +499,8 @@ impl SignatureBuilder {
pk_algo: PublicKeyAlgorithm::Unknown(0),
hash_algo: HashAlgorithm::default(),
subpackets: SubpacketAreas::default(),
- }
+ },
+ version: SBVersion::default(),
}
}
@@ -1702,7 +1720,24 @@ impl SignatureBuilder {
/// # Ok(()) }
/// ```
pub fn pre_sign(mut self, signer: &dyn Signer) -> Result<Self> {
- self.pk_algo = signer.public().pk_algo();
+ let pk = signer.public();
+ self.pk_algo = pk.pk_algo();
+
+ // Set the version. A Key6 will create a Signature6, a key4
+ // will create a Signature4. If necessary, generate a salt.
+ // If the salt has been explicitly set, it is not changed.
+ self.version = match (self.version, pk.version()) {
+ (SBVersion::V4 {}, 4) => SBVersion::V4 {},
+ (SBVersion::V6 { .. }, 4) => SBVersion::V4 {},
+ (SBVersion::V4 {}, 6) => {
+ let mut salt = vec![0; self.fields.hash_algo().salt_size()?];
+ crate::crypto::random(&mut salt);
+ SBVersion::V6 { salt }
+ },
+ (SBVersion::V6 { salt }, 6) => SBVersion::V6 { salt },
+ (_, n) => return Err(Error::InvalidOperation(
+ format!("Unsupported key version {}", n)).into()),
+ };
// Set the creation time.
if ! self.overrode_creation_time {
@@ -1711,31 +1746,83 @@ impl SignatureBuilder {
}
}
- // Make sure we have an issuer packet.
- if self.issuers().next().is_none()
- && self.issuer_fingerprints().next().is_none()
- {
- self = self.set_issuer(signer.public().keyid())?
- .set_issuer_fingerprint(signer.public().fingerprint())?;
- }
+ match &self.version {
+ SBVersion::V4 {} => {
+ // Make sure we have an issuer packet.
+ if self.issuers().next().is_none()
+ && self.issuer_fingerprints().next().is_none()
+ {
+ self = self.set_issuer(signer.public().keyid())?
+ .set_issuer_fingerprint(signer.public().fingerprint())?;
+ }
+
+ // Add a salt to v4 signatures to make the signature
+ // unpredictable.
+ let mut salt = [0; 32];
+ crate::crypto::random(&mut salt);
+ self = self.set_notation("salt@notations.sequoia-pgp.org",
+ salt, None, false)?;
+ },
+ SBVersion::V6 { .. } => {
+ // Make sure we have an issuer fingerprint packet.
+ if self.issuer_fingerprints().next().is_none() {
+ self = self
+ .set_issuer_fingerprint(signer.public().fingerprint())?;
+ }
- // Add a salt to make the signature unpredictable.
- let mut salt = [0; 32];
- crate::crypto::random(&mut salt);
- self = self.set_notation("salt@notations.sequoia-pgp.org",
- salt, None, false)?;
+ // In v6 signatures, we have a proper prefix salt.
+ },
+ }
self.sort();
Ok(self)
}
+ /// Returns the prefix salt.
+ ///
+ /// In OpenPGP v6 signatures, a salt is prefixed to the data
+ /// stream hashed in the signature. If a v6 signature is
+ /// generated by using a v6 key, then a salt will be added
+ /// automatically. If a salt has been set explicitly (see
+ /// [`SignatureBuilder::set_prefix_salt`]), this function will
+ /// return the salt.
+ pub fn prefix_salt(&self) -> Option<&[u8]> {
+ match &self.version {
+ SBVersion::V4 {} => None,
+ SBVersion::V6 { salt } => Some(salt),
+ }
+ }
+
+ /// Explicitly sets the prefix salt.
+ ///
+ /// In OpenPGP v6 signatures, a salt is prefixed to the data
+ /// stream hashed in the signature. If a v6 signature is
+ /// generated by using a v6 key, then a salt will be added
+ /// automatically. In general, you do not need to call this
+ /// function.
+ ///
+ /// When streaming a signed message, it is useful to explicitly
+ /// set the salt using this function.
+ pub fn set_prefix_salt(mut self, new_salt: Vec<u8>) -> (Self, Option<Vec<u8>>) {
+ let mut old = None;
+
+ self.version = match std::mem::take(&mut self.version) {
+ SBVersion::V4 {} => SBVersion::V6 { salt: new_salt },
+ SBVersion::V6 { salt } => {
+ old = Some(salt);
+ SBVersion::V6 { salt: new_salt }
+ },
+ };
+
+ (self, old)
+ }
+
fn sign(self, signer: &mut dyn Signer, digest: Vec<u8>)
-> Result<Signature>
{
let mpis = signer.sign(self.hash_algo, &digest)?;
-
- Ok(Signature4 {
+ let v4 = Signature4 {
common: Default::default(),
fields: self.fields,
digest_prefix: [digest[0], digest[1]],
@@ -1743,7 +1830,13 @@ impl SignatureBuilder {
computed_digest: Some(digest),
level: 0,
additional_issuers: Vec::with_capacity(0),
- }.into())
+ };
+
+ match self.version {
+ SBVersion::V4 {} => Ok(v4.into()),
+ SBVersion::V6 { salt } =>
+ Ok(Signature6::from_common(v4, salt)?.into())
+ }
}
}
@@ -1752,6 +1845,7 @@ impl From<Signature> for SignatureBuilder {
match sig {
Signature::V3(sig) => sig.into(),
Signature::V4(sig) => sig.into(),
+ Signature::V6(sig) => sig.into(),
}
}
}
@@ -1777,10 +1871,17 @@ impl From<Signature4> for SignatureBuilder {
overrode_creation_time: false,
original_creation_time: creation_time,
fields,
+ version: Default::default(),
}
}
}
+impl From<Signature6> for SignatureBuilder {
+ fn from(sig: Signature6) -> Self {
+ SignatureBuilder::from(sig.common)
+ }
+}
+
/// Holds a v4 Signature packet.
///
/// This holds a [version 4] Signature packet. Normally, you won't
@@ -2699,6 +2800,13 @@ impl Signature {
"Signature has no creation time subpacket".into()).into());
}
+ // XXX if hash_algo.salt_size().map(|expected| expected != salt_len)
+ // XXX .unwrap_or(false)
+ // XXX {
+ // XXX return php.fail(format!("bad salt length, expected {} got {}",
+ // XXX );
+ // XXX }
+
let result = key.verify(self.mpis(), self.hash_algo(), digest.as_ref());
if result.is_ok() {
// Mark information in this signature as authenticated.
@@ -3378,10 +3486,11 @@ impl From<Signature4> for super::Signature {
#[cfg(test)]
impl ArbitraryBounded for super::Signature {
fn arbitrary_bounded(g: &mut Gen, depth: usize) -> Self {
- if bool::arbitrary(g) {
- Signature3::arbitrary_bounded(g, depth).into()
- } else {
- Signature4::arbitrary_bounded(g, depth).into()
+ match u8::arbitrary(g) % 3 {
+ 0 => Signature3::arbitrary_bounded(g, depth).into(),
+ 1 => Signature4::arbitrary_bounded(g, depth).into(),
+ 2 => Signature6::arbitrary_bounded(g, depth).into(),
+ _ => unreachable!(),
}
}
}