Skip to content

Commit f005791

Browse files
authored
x509-cert: make SKI optional in leaf certificate (#1028)
[RFC5280 Section 4.2.1.2] recommends the SKI to be included but other specifications (IEEE 801.1AR Section 8.10.2 subjectKeyIdentifier) says it should not be included. This introduces a tunable in the Leaf profile under the `hazmat` feature not to include it. [RFC5280 Section 4.2.1.2]: https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.2
1 parent 3c1060e commit f005791

2 files changed

Lines changed: 56 additions & 7 deletions

File tree

x509-cert/src/builder.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ pub enum Profile {
9292
enable_key_agreement: bool,
9393
/// should the key encipherment flag of KeyUsage be enabled
9494
enable_key_encipherment: bool,
95+
/// should the subject key identifier extension be included
96+
///
97+
/// From [RFC 5280 Section 4.2.1.2]:
98+
/// For end entity certificates, subject key identifiers SHOULD be
99+
/// derived from the public key. Two common methods for generating key
100+
/// identifiers from the public key are identified above.
101+
#[cfg(feature = "hazmat")]
102+
include_subject_key_identifier: bool,
95103
},
96104
#[cfg(feature = "hazmat")]
97105
/// Opt-out of the default extensions
@@ -128,7 +136,14 @@ impl Profile {
128136

129137
let mut extensions: vec::Vec<Extension> = vec::Vec::new();
130138

131-
extensions.push(SubjectKeyIdentifier::try_from(spk)?.to_extension(tbs)?);
139+
match self {
140+
#[cfg(feature = "hazmat")]
141+
Profile::Leaf {
142+
include_subject_key_identifier: false,
143+
..
144+
} => {}
145+
_ => extensions.push(SubjectKeyIdentifier::try_from(spk)?.to_extension(tbs)?),
146+
}
132147

133148
// Build Authority Key Identifier
134149
match self {

x509-cert/tests/builder.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,27 +90,35 @@ fn leaf_certificate() {
9090
let issuer =
9191
Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
9292
let profile = Profile::Leaf {
93-
issuer,
93+
issuer: issuer.clone(),
9494
enable_key_agreement: false,
9595
enable_key_encipherment: false,
96+
#[cfg(feature = "hazmat")]
97+
include_subject_key_identifier: true,
9698
};
9799

98100
let subject = Name::from_str("CN=service.domination.world").unwrap();
99101
let pub_key =
100102
SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
101103

102104
let signer = ecdsa_signer();
103-
let builder =
104-
CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
105-
.expect("Create certificate");
105+
let builder = CertificateBuilder::new(
106+
profile,
107+
serial_number.clone(),
108+
validity.clone(),
109+
subject.clone(),
110+
pub_key.clone(),
111+
&signer,
112+
)
113+
.expect("Create certificate");
106114

107115
let certificate = builder.build::<ecdsa::Signature<NistP256>>().unwrap();
108116

109117
let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
110118
println!("{}", openssl::check_certificate(pem.as_bytes()));
111119

112120
// TODO(baloo): not too sure we should tackle those in this API.
113-
let ignored = &[
121+
let ignored = vec![
114122
"e_sub_cert_aia_missing",
115123
"e_sub_cert_crl_distribution_points_missing",
116124
"w_sub_cert_aia_does_not_contain_issuing_ca_url",
@@ -126,7 +134,31 @@ fn leaf_certificate() {
126134
"e_sub_cert_eku_missing",
127135
];
128136

129-
zlint::check_certificate(pem.as_bytes(), ignored);
137+
zlint::check_certificate(pem.as_bytes(), &ignored);
138+
139+
#[cfg(feature = "hazmat")]
140+
{
141+
let profile = Profile::Leaf {
142+
issuer,
143+
enable_key_agreement: false,
144+
enable_key_encipherment: false,
145+
include_subject_key_identifier: false,
146+
};
147+
let builder =
148+
CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
149+
.expect("Create certificate");
150+
151+
let certificate = builder.build::<ecdsa::Signature<NistP256>>().unwrap();
152+
153+
let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
154+
println!("{}", openssl::check_certificate(pem.as_bytes()));
155+
156+
// Ignore warning about leaf not having SKI extension (this is a warning not a fail, as
157+
// denoted by the `w_` prefix.
158+
let mut ignored = ignored;
159+
ignored.push("w_ext_subject_key_identifier_missing_sub_cert");
160+
zlint::check_certificate(pem.as_bytes(), &ignored);
161+
}
130162
}
131163

132164
#[test]
@@ -140,6 +172,8 @@ fn pss_certificate() {
140172
issuer,
141173
enable_key_agreement: false,
142174
enable_key_encipherment: false,
175+
#[cfg(feature = "hazmat")]
176+
include_subject_key_identifier: true,
143177
};
144178

145179
let subject = Name::from_str("CN=service.domination.world").unwrap();

0 commit comments

Comments
 (0)