spiffe/svid/x509/
validations.rs

1use crate::cert::errors::CertificateError;
2use crate::cert::parsing::{get_x509_extension, parse_der_encoded_bytes_as_x509_certificate};
3use crate::cert::Certificate;
4use crate::spiffe_id::SpiffeId;
5use crate::svid::x509::X509SvidError;
6use std::convert::TryFrom;
7use x509_parser::certificate::X509Certificate;
8use x509_parser::extensions::GeneralName::URI;
9use x509_parser::extensions::ParsedExtension;
10use x509_parser::oid_registry;
11
12/// Parse the [`Certificate`] as an X.509 certificate,
13/// validate and return the [`SpiffeId`] from certificate URI SAN.
14pub(crate) fn validate_leaf_certificate(cert: &Certificate) -> Result<SpiffeId, X509SvidError> {
15    let x509 = parse_der_encoded_bytes_as_x509_certificate(cert.content())?;
16    validate_x509_leaf_certificate(&x509)?;
17    find_spiffe_id(&x509)
18}
19
20/// Parse the chain of [`Certificate`] as X.509 certificates and validate them
21/// as signing certificates.
22pub(crate) fn validate_signing_certificates(certs: &[Certificate]) -> Result<(), X509SvidError> {
23    for cert in certs {
24        let ca = parse_der_encoded_bytes_as_x509_certificate(cert.content())?;
25        validate_signing_certificate(&ca)?;
26    }
27    Ok(())
28}
29
30fn validate_x509_leaf_certificate(cert: &X509Certificate<'_>) -> Result<(), X509SvidError> {
31    validate_leaf_certificate_key_usage(cert)?;
32
33    let basic_constraints = get_x509_extension(cert, oid_registry::OID_X509_EXT_BASIC_CONSTRAINTS)?;
34    match basic_constraints {
35        ParsedExtension::BasicConstraints(b) if b.ca => {
36            Err(X509SvidError::LeafCertificateHasCaFlag)
37        }
38        _ => Ok(()),
39    }
40}
41
42fn validate_signing_certificate(cert: &X509Certificate<'_>) -> Result<(), X509SvidError> {
43    let basic_constraints = get_x509_extension(cert, oid_registry::OID_X509_EXT_BASIC_CONSTRAINTS)?;
44    match basic_constraints {
45        ParsedExtension::BasicConstraints(b) if !b.ca => {
46            return Err(X509SvidError::SigningCertificatedNoCa)
47        }
48        _ => {}
49    };
50
51    let key_usage = get_x509_extension(cert, oid_registry::OID_X509_EXT_KEY_USAGE)?;
52    match key_usage {
53        ParsedExtension::KeyUsage(k) if !k.key_cert_sign() => {
54            Err(X509SvidError::SigningCertificatedNoKeyCertSign)
55        }
56        _ => Ok(()),
57    }
58}
59
60fn validate_leaf_certificate_key_usage(cert: &X509Certificate<'_>) -> Result<(), X509SvidError> {
61    let key_usage = get_x509_extension(cert, oid_registry::OID_X509_EXT_KEY_USAGE)?;
62    match key_usage {
63        ParsedExtension::KeyUsage(k) if !k.digital_signature() => {
64            Err(X509SvidError::LeafCertificatedNoDigitalSignature)
65        }
66
67        ParsedExtension::KeyUsage(k) if k.crl_sign() => {
68            Err(X509SvidError::LeafCertificateHasCrlSign)
69        }
70        ParsedExtension::KeyUsage(k) if k.key_cert_sign() => {
71            Err(X509SvidError::LeafCertificateHasKeyCertSign)
72        }
73        _ => Ok(()),
74    }
75}
76
77fn find_spiffe_id(cert: &X509Certificate<'_>) -> Result<SpiffeId, X509SvidError> {
78    let san_ext = get_x509_extension(cert, oid_registry::OID_X509_EXT_SUBJECT_ALT_NAME)?;
79
80    match san_ext {
81        ParsedExtension::SubjectAlternativeName(s) => {
82            let uri_san = s
83                .general_names
84                .iter()
85                .find(|n| matches!(n, URI(_)))
86                .and_then(|n| match n {
87                    URI(n) => Some(*n),
88                    _ => None,
89                });
90
91            let uri_str = match uri_san {
92                None => return Err(X509SvidError::MissingSpiffeId),
93                Some(s) => s,
94            };
95
96            Ok(SpiffeId::try_from(uri_str)?)
97        }
98        other => Err(X509SvidError::Certificate(
99            CertificateError::UnexpectedExtension(format!("{other:?}")),
100        )),
101    }
102}