GitLab

Verified Commit 35119b75 authored by Neal H. Walfield's avatar Neal H. Walfield
Browse files
  - If the signer controls the data that is being signed, then the
    hash algorithm only needs second pre-image resistance.
  - This observation can be used to extend the life of hash algorithms
    that have been weakened, as is the case for SHA-1.
  - Introduces a new `enum HashAlgoSecurity`, which is now passed to
    `Policy::signature`.
  - See #595.
+13 −3
Original line number Diff line number Diff line
@@ -1267,15 +1267,25 @@ impl Cert {
    {
        let mut keys = std::collections::HashSet::new();

        let pk_sec = self.primary_key().hash_algo_security();

        // All user ids.
        self.userids()
            .flat_map(|ua| {
                // All valid self-signatures.
                ua.self_signatures().iter()
                let sec = ua.hash_algo_security;
                ua.self_signatures()
                    .iter()
                    .filter(move |sig| {
                        policy.signature(sig, sec).is_ok()
                   })
            })
            // All direct-key signatures.
            .chain(self.primary_key().self_signatures() .iter())
            .filter(|sig| policy.signature(sig).is_ok())
            .chain(self.primary_key()
                   .self_signatures().iter()
                   .filter(|sig| {
                       policy.signature(sig, pk_sec).is_ok()
                   }))
            .flat_map(|sig| sig.revocation_keys())
            .for_each(|rk| { keys.insert(rk); });

+7 −2
Original line number Diff line number Diff line
@@ -895,15 +895,20 @@ impl<'a, C> ComponentAmalgamation<'a, C> {
        let mut keys = std::collections::HashSet::new();
        for rk in self.self_signatures().iter()
            .filter(|sig| {
                policy.signature(sig).is_ok()
                policy
                    .signature(sig, self.hash_algo_security)
                    .is_ok()
            })
            .flat_map(|sig| sig.revocation_keys())
        {
            keys.insert(rk);
        }
        let pk_sec = self.cert().primary_key().hash_algo_security();
        for rk in self.cert().primary_key().self_signatures().iter()
            .filter(|sig| {
                policy.signature(sig).is_ok()
                policy
                    .signature(sig, pk_sec)
                    .is_ok()
            })
            .flat_map(|sig| sig.revocation_keys())
        {
+18 −6
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ use crate::{
    packet::UserAttribute,
    packet::Unknown,
    Packet,
    policy::HashAlgoSecurity,
    policy::Policy,
    Result,
};
@@ -112,6 +113,8 @@ use super::{
pub struct ComponentBundle<C> {
    pub(crate) component: C,

    pub(crate) hash_algo_security: HashAlgoSecurity,

    // Self signatures.
    pub(crate) self_signatures: Vec<Signature>,

@@ -302,7 +305,8 @@ impl<C> ComponentBundle<C> {
                continue;
            }

            if let Err(e) = policy.signature(s) {
            if let Err(e) = policy.signature(s, self.hash_algo_security)
            {
                if error.is_none() {
                    error = Some(e);
                }
@@ -329,7 +333,9 @@ impl<C> ComponentBundle<C> {
                        continue 'next_backsig;
                    }

                    if let Err(e) = policy.signature(backsig) {
                    if let Err(e) = policy
                        .signature(backsig, self.hash_algo_security)
                    {
                        if error.is_none() {
                            error = Some(e);
                        }
@@ -523,9 +529,11 @@ impl<C> ComponentBundle<C> {
                selfsig.signature_alive(t, time::Duration::new(0, 0)).is_ok());
        }

        let check = |revs: &'a [Signature]| -> Option<Vec<&'a Signature>> {
        let check = |revs: &'a [Signature], sec: HashAlgoSecurity|
            -> Option<Vec<&'a Signature>>
        {
            let revs = revs.iter().filter_map(|rev| {
                if let Err(err) = policy.signature(rev) {
                if let Err(err) = policy.signature(rev, sec) {
                    t!("  revocation rejected by caller policy: {}", err);
                    None
                } else if hard_revocations_are_final
@@ -580,9 +588,13 @@ impl<C> ComponentBundle<C> {
            }
        };

        if let Some(revs) = check(&self.self_revocations) {
        if let Some(revs)
            = check(&self.self_revocations, self.hash_algo_security)
        {
            RevocationStatus::Revoked(revs)
        } else if let Some(revs) = check(&self.other_revocations) {
        } else if let Some(revs)
            = check(&self.other_revocations, Default::default())
        {
            RevocationStatus::CouldBe(revs)
        } else {
            RevocationStatus::NotAsFarAsWeKnow
+10 −0
Original line number Diff line number Diff line
@@ -44,10 +44,12 @@ pub Cert: Option<Cert> = {
                    _ => unreachable!(),
                };
                let c = c.unwrap();
                let sec = key.hash_algo_security();

                let mut cert = Cert {
                    primary: PrimaryKeyBundle {
                        component: key,
                        hash_algo_security: sec,
                        self_signatures: vec![],
                        certifications: sigs,
                        self_revocations: vec![],
@@ -156,9 +158,11 @@ Component: Option<Component> = {
        match key {
            Some(key) => {
                let sigs = sigs.unwrap();
                let sec = key.hash_algo_security();

                Some(Component::SubkeyBundle(SubkeyBundle {
                    component: key,
                    hash_algo_security: sec,
                    self_signatures: vec![],
                    certifications: sigs,
                    self_revocations: vec![],
@@ -173,9 +177,11 @@ Component: Option<Component> = {
        match u {
            Some(u) => {
                let sigs = sigs.unwrap();
                let sec = u.hash_algo_security();

                Some(Component::UserIDBundle(UserIDBundle {
                    component: u,
                    hash_algo_security: sec,
                    self_signatures: vec![],
                    certifications: sigs,
                    self_revocations: vec![],
@@ -190,9 +196,11 @@ Component: Option<Component> = {
        match u {
            Some(u) => {
                let sigs = sigs.unwrap();
                let sec = u.hash_algo_security();

                Some(Component::UserAttributeBundle(UserAttributeBundle {
                    component: u,
                    hash_algo_security: sec,
                    self_signatures: vec![],
                    certifications: sigs,
                    self_revocations: vec![],
@@ -207,9 +215,11 @@ Component: Option<Component> = {
        match u {
            Some(u) => {
                let sigs = sigs.unwrap();
                let sec = u.hash_algo_security();

                Some(Component::UnknownBundle(UnknownBundle {
                    component: u,
                    hash_algo_security: sec,
                    self_signatures: vec![],
                    certifications: sigs,
                    self_revocations: vec![],
+30 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ use crate::crypto::Password;
use crate::KeyID;
use crate::Fingerprint;
use crate::KeyHandle;
use crate::policy::HashAlgoSecurity;

mod conversions;

@@ -832,6 +833,35 @@ impl<P, R> Key4<P, R>
    where P: key::KeyParts,
          R: key::KeyRole,
{
    /// The security requirements of the hash algorithm for
    /// self-signatures.
    ///
    /// A cryptographic hash algorithm usually has [three security
    /// properties]: pre-image resistance, second pre-image
    /// resistance, and collision resistance.  If an attacker can
    /// influence the signed data, then the hash algorithm needs to
    /// have both second pre-image resistance, and collision
    /// resistance.  If not, second pre-image resistance is
    /// sufficient.
    ///
    ///   [three security properties]: https://en.wikipedia.org/wiki/Cryptographic_hash_function#Properties
    ///
    /// In general, an attacker may be able to influence third-party
    /// signatures.  But direct key signatures, and binding signatures
    /// are only over data fully determined by signer.  And, an
    /// attacker's control over self signatures over User IDs is
    /// limited due to their structure.
    ///
    /// These observations can be used to extend the life of a hash
    /// algorithm after its collision resistance has been partially
    /// compromised, but not completely broken.  For more details,
    /// please refer to the documentation for [HashAlgoSecurity].
    ///
    ///   [HashAlgoSecurity]: ../policy/enum.HashAlgoSecurity.html
    pub fn hash_algo_security(&self) -> HashAlgoSecurity {
        HashAlgoSecurity::SecondPreImageResistance
    }

    /// Compares the public bits of two keys.
    ///
    /// This returns `Ordering::Equal` if the public MPIs, creation

Read the original on gitlab.com ↗