Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions rcgen/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,28 +1069,37 @@ pub enum IsCa {
impl IsCa {
#[cfg(all(test, feature = "x509-parser"))]
fn from_x509(x509: &x509_parser::certificate::X509Certificate<'_>) -> Result<Self, Error> {
use x509_parser::extensions::BasicConstraints as B;

let basic_constraints = x509
.basic_constraints()
.map_err(|_| Error::CouldNotParseCertificate)?
.map(|ext| ext.value);

match basic_constraints {
Some(bc) => Self::from_basic_constraints(bc),
None => Ok(Self::NoCa),
}
}

#[cfg(feature = "x509-parser")]
pub(crate) fn from_basic_constraints(
Comment thread
5Dev24 marked this conversation as resolved.
basic_constraints: &x509_parser::extensions::BasicConstraints,
) -> Result<Self, Error> {
use x509_parser::extensions::BasicConstraints as B;

Ok(match basic_constraints {
Some(B {
B {
ca: true,
path_len_constraint: Some(n),
}) if *n <= u8::MAX as u32 => Self::Ca(BasicConstraints::Constrained(*n as u8)),
Some(B {
} if *n <= u8::MAX as u32 => Self::Ca(BasicConstraints::Constrained(*n as u8)),
B {
ca: true,
path_len_constraint: Some(_),
}) => return Err(Error::CouldNotParseCertificate),
Some(B {
} => return Err(Error::CouldNotParseCertificate),
B {
ca: true,
path_len_constraint: None,
}) => Self::Ca(BasicConstraints::Unconstrained),
Some(B { ca: false, .. }) => Self::ExplicitNoCa,
None => Self::NoCa,
} => Self::Ca(BasicConstraints::Unconstrained),
B { ca: false, .. } => Self::ExplicitNoCa,
})
}
}
Expand Down
7 changes: 5 additions & 2 deletions rcgen/src/csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
Certificate, CertificateParams, Error, Issuer, PublicKeyData, SignatureAlgorithm, SigningKey,
};
#[cfg(feature = "x509-parser")]
use crate::{DistinguishedName, ExtendedKeyUsagePurpose, KeyUsagePurpose, SanType};
use crate::{DistinguishedName, ExtendedKeyUsagePurpose, IsCa, KeyUsagePurpose, SanType};

/// A public key, extracted from a CSR
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -90,6 +90,7 @@ impl CertificateSigningRequestParams {
/// - `Subject Alternative Name` (see [`SanType`])
/// - `Key Usage` (see [`KeyUsagePurpose`])
/// - `Extended Key Usage` (see [`ExtendedKeyUsagePurpose`])
/// - `Basic Constraints` (see [`crate::BasicConstraints`])
///
/// On encountering other extensions, this function will return [`Error::UnsupportedExtension`].
/// If the request's signature is invalid, it will return
Expand Down Expand Up @@ -167,13 +168,15 @@ impl CertificateSigningRequestParams {
return Err(Error::UnsupportedExtension);
}
},
x509_parser::extensions::ParsedExtension::BasicConstraints(bc) => {
params.is_ca = IsCa::from_basic_constraints(bc)?;
},
_ => return Err(Error::UnsupportedExtension),
}
}
}

// Not yet handled:
// * is_ca
// * name_constraints
// and any other extensions.

Expand Down
152 changes: 152 additions & 0 deletions verify-tests/tests/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,158 @@ mod test_csr_custom_attributes {
}
}

#[cfg(feature = "x509-parser")]
mod test_csr_basic_constraints {
use rcgen::{BasicConstraints, CertificateSigningRequestParams, Error, IsCa};

/// Tests deserializing a csr with a basic constraint of CA:TRUE,pathlen:5
///
/// This should deserialize fine to a ca constrained to 5
#[test]
fn test_csr_basic_constraints_true_pathlen() {
let csr_params =
CertificateSigningRequestParams::from_pem(CSR_TEST_BASIC_CONSTRAINTS_CA_TRUE_5_PEM)
.unwrap();

assert_eq!(
csr_params.params.is_ca,
IsCa::Ca(BasicConstraints::Constrained(5))
);
}

/*
Generated by: openssl req -new -key ./tmp.key \
-subj "/CN=test.local" -addext "basicConstraints=CA:TRUE,pathlen:5"
Where `verify_tests::RSA_TEST_KEY_PAIR_PEM`'s content is stored in ./tmp.key
*/
const CSR_TEST_BASIC_CONSTRAINTS_CA_TRUE_5_PEM: &str = r#"
-----BEGIN CERTIFICATE REQUEST-----
MIICfDCCAWQCAQAwFTETMBEGA1UEAwwKdGVzdC5sb2NhbDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBANiOaDJXf8tKLMletisBNmus+vYR2jzKI6AEsWaL
iyB4Z1DmfqeGNMZ8EQg/YhrrP6FuIY4ydxpsQFzOR0wT4kVhUJKRLuviK8w7OnZ6
DEuBw8px6sGhcjwNRseEhH3Pz2UeI8cMm/f53QBzVv1vP1vw4B5laJCYW+aOltzY
N+FDY4XHYzAVkJgXX3qutc5zr9JHZ6xlVGuRbbZEEoVODPoYgDkD/lVYoghJKoQH
WA5wzPaKrn3zsjbz4TPitwtnaUHtxntNs3GQDC3R88v4S7I/tc7NsiPj+RICVTnF
/A0RFrcES44WujiLkSZIOP6VHnF1GkWfHSPnM6jNQvaUcb0CAwEAAaAiMCAGCSqG
SIb3DQEJDjETMBEwDwYDVR0TBAgwBgEB/wIBBTANBgkqhkiG9w0BAQsFAAOCAQEA
T9NEuWv7p/zJgGPEROpd7f6uguZU0fldW8c6NdilYSYTWGk2CKxK1tV77Dh34TWX
c/KtDONZ26lsJzgxZ4anDJ91Qi7SAPzPK5aqSfR4kOAfSmtlg/iAHPJxOcyeEDCQ
s0WPMbnDQs7mzPH8rEQyjeEj+wqnuG75eNWw4Vaz67dLYDrGEhm799tpZcaRhIvH
suZNckh3DzhMHTstIMxMhlrjFuoe8OvzGfcNAOJYYz+T4E4PZWsNDXKi67iTtsbz
JotPi403/0BNGtis/EjzClzSOHKJvWvA2dn7XEoQx3yTMWqGf3p1GEwYPBcFKCN1
p5evxprnXDk0qMh66vSZ3Q==
-----END CERTIFICATE REQUEST-----
"#;

/// Tests deserializing a csr with a basic constraint of CA:TRUE,pathlen:256
///
/// This should be too large for a u8 and fail
#[test]
fn test_csr_basic_constraints_true_pathlen_too_large() {
let result =
CertificateSigningRequestParams::from_pem(CSR_TEST_BASIC_CONSTRAINTS_CA_TRUE_256_PEM);

assert_eq!(result.unwrap_err(), Error::CouldNotParseCertificate);
}

/*
Generated by: openssl req -new -key ./tmp.key \
-subj "/CN=test.local" -addext "basicConstraints=CA:TRUE,pathlen:256"
Where `verify_tests::RSA_TEST_KEY_PAIR_PEM`'s content is stored in ./tmp.key
*/
const CSR_TEST_BASIC_CONSTRAINTS_CA_TRUE_256_PEM: &str = r#"
-----BEGIN CERTIFICATE REQUEST-----
MIICfTCCAWUCAQAwFTETMBEGA1UEAwwKdGVzdC5sb2NhbDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBANiOaDJXf8tKLMletisBNmus+vYR2jzKI6AEsWaL
iyB4Z1DmfqeGNMZ8EQg/YhrrP6FuIY4ydxpsQFzOR0wT4kVhUJKRLuviK8w7OnZ6
DEuBw8px6sGhcjwNRseEhH3Pz2UeI8cMm/f53QBzVv1vP1vw4B5laJCYW+aOltzY
N+FDY4XHYzAVkJgXX3qutc5zr9JHZ6xlVGuRbbZEEoVODPoYgDkD/lVYoghJKoQH
WA5wzPaKrn3zsjbz4TPitwtnaUHtxntNs3GQDC3R88v4S7I/tc7NsiPj+RICVTnF
/A0RFrcES44WujiLkSZIOP6VHnF1GkWfHSPnM6jNQvaUcb0CAwEAAaAjMCEGCSqG
SIb3DQEJDjEUMBIwEAYDVR0TBAkwBwEB/wICAQAwDQYJKoZIhvcNAQELBQADggEB
AJvBfceI2fbBwW/wjtOJYUlYJR72X8ZeMSbRkl0hbd+UxjB7uces5aq0RTXALYGx
Ikw3ZWf4aODxeWHWGzESJMBowi5DWunVwmM3Qu7SNVPQfBgZ79LVkjz5c1Ig9TXv
avZnsmojq2/q2xBllK27nbhlsaNcM+SJEX4BiuYkDoCL13bmzwgnbFMR2gyWE7qD
WQiZbH+NRvQbdu7PSzYHIzc6e4p+k2dub6P8aW2hB+XOfMJecWwYKO2d+vo0M0FA
bpKr1I9iw98R+A3WMfEsWVpCEERQtu7t3N4Pd97sLKoa3woGBfHk9BoGM8zCdneG
RioOvAyCH6bFMvSJxZm7FYM=
-----END CERTIFICATE REQUEST-----
"#;

/// Tests deserializing a csr with a basic constraint of CA:TRUE
///
/// This should deserialize fine to a ca unconstrained
#[test]
fn test_csr_basic_constraints_true() {
let csr_params =
CertificateSigningRequestParams::from_pem(CSR_TEST_BASIC_CONSTRAINTS_CA_TRUE).unwrap();

assert_eq!(
csr_params.params.is_ca,
IsCa::Ca(BasicConstraints::Unconstrained)
);
}

/*
Generated by: openssl req -new -key ./tmp.key \
-subj "/CN=test.local" -addext "basicConstraints=CA:TRUE"
Where `verify_tests::RSA_TEST_KEY_PAIR_PEM`'s content is stored in ./tmp.key
*/
const CSR_TEST_BASIC_CONSTRAINTS_CA_TRUE: &str = r#"
-----BEGIN CERTIFICATE REQUEST-----
MIICeTCCAWECAQAwFTETMBEGA1UEAwwKdGVzdC5sb2NhbDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBANiOaDJXf8tKLMletisBNmus+vYR2jzKI6AEsWaL
iyB4Z1DmfqeGNMZ8EQg/YhrrP6FuIY4ydxpsQFzOR0wT4kVhUJKRLuviK8w7OnZ6
DEuBw8px6sGhcjwNRseEhH3Pz2UeI8cMm/f53QBzVv1vP1vw4B5laJCYW+aOltzY
N+FDY4XHYzAVkJgXX3qutc5zr9JHZ6xlVGuRbbZEEoVODPoYgDkD/lVYoghJKoQH
WA5wzPaKrn3zsjbz4TPitwtnaUHtxntNs3GQDC3R88v4S7I/tc7NsiPj+RICVTnF
/A0RFrcES44WujiLkSZIOP6VHnF1GkWfHSPnM6jNQvaUcb0CAwEAAaAfMB0GCSqG
SIb3DQEJDjEQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAGzzg
376bY6J2+bnhmbsxjFGrbI57OvIEefQxQ+1vAHirvdAvXMZcV5Y3CRZdIg3t0/0j
2B+K2dqHuEMlSYp0fBa76A/qUGfujucq04ti2xau1Pd2Nmx9KA9eFZ2g1yGkSCEH
Dt9lS7NjYOGIU5QkvCChJUaP5pFxn3HIFuWzLRjuvS7wiHAB5hMU479cmF0zu3Qs
l5B/4S4l8rcX1uLfRviiOJSrSpoTJDJjQwsks6j/iu99cYBmULLNrpUP+sIYP7hZ
IJgMpHPIiotOsYV16GPOStG9Fyz3bKH6NFWwkC4ncGul7wzQdXj/qr29HNmP+2fB
lZLnFMmv1pkn052qtQ==
-----END CERTIFICATE REQUEST-----
"#;

/// Tests deserializing a csr with a basic constraint of CA:TRUE
///
/// This should deserialize fine to explicitly no ca
#[test]
fn test_csr_basic_constraints_false() {
let csr_params =
CertificateSigningRequestParams::from_pem(CSR_TEST_BASIC_CONSTRAINTS_CA_FALSE).unwrap();

assert_eq!(csr_params.params.is_ca, IsCa::ExplicitNoCa);
}

/*
Generated by: openssl req -new -key ./tmp.key \
-subj "/CN=test.local" -addext "basicConstraints=CA:FALSE"
Where `verify_tests::RSA_TEST_KEY_PAIR_PEM`'s content is stored in ./tmp.key
*/
const CSR_TEST_BASIC_CONSTRAINTS_CA_FALSE: &str = r#"
-----BEGIN CERTIFICATE REQUEST-----
MIICdjCCAV4CAQAwFTETMBEGA1UEAwwKdGVzdC5sb2NhbDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBANiOaDJXf8tKLMletisBNmus+vYR2jzKI6AEsWaL
iyB4Z1DmfqeGNMZ8EQg/YhrrP6FuIY4ydxpsQFzOR0wT4kVhUJKRLuviK8w7OnZ6
DEuBw8px6sGhcjwNRseEhH3Pz2UeI8cMm/f53QBzVv1vP1vw4B5laJCYW+aOltzY
N+FDY4XHYzAVkJgXX3qutc5zr9JHZ6xlVGuRbbZEEoVODPoYgDkD/lVYoghJKoQH
WA5wzPaKrn3zsjbz4TPitwtnaUHtxntNs3GQDC3R88v4S7I/tc7NsiPj+RICVTnF
/A0RFrcES44WujiLkSZIOP6VHnF1GkWfHSPnM6jNQvaUcb0CAwEAAaAcMBoGCSqG
SIb3DQEJDjENMAswCQYDVR0TBAIwADANBgkqhkiG9w0BAQsFAAOCAQEAJ14zBkXP
VmllImMlJ4BeQZkBEKj60hMu7xJLiy0isdt7R1q6Hwaot7ibS9magRhhBQDE64dA
U0UX+3T97eDf8vT0g1A7KBILE9dHFAmB6RuzYXX1BNXQSmFQ8ygUbvf9uZYwG4/o
YAYYRuGyw3Nah2KJIMJMlNLaowrQojas0tHQnelBv6phHwi8eDKZnQgvHOczJkGH
+0+KrUr5Vh9DzMZSfiqCaKu3JbfEHuypPEzNGBEhP75c1+9j8khpsM6nEMB8CuGn
t7TyFr3lPp7qn5metrd8n9soFSodJqb3bkcLHKGCUbHY74wMylZLBdKNd0esQpZ1
9n2hz8T5m4UTlg==
-----END CERTIFICATE REQUEST-----
"#;
}

#[cfg(feature = "x509-parser")]
mod test_x509_parser_crl {
use verify_tests as util;
Expand Down
Loading