spiffe/svid/x509/
validations.rs1use 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
12pub(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
20pub(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}