• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![cfg(all(feature = "builder", feature = "pem"))]
2 
3 use der::{asn1::PrintableString, pem::LineEnding, Decode, Encode, EncodePem};
4 use p256::{ecdsa::DerSignature, pkcs8::DecodePrivateKey, NistP256};
5 use rsa::pkcs1::DecodeRsaPrivateKey;
6 use rsa::pkcs1v15::SigningKey;
7 use sha2::Sha256;
8 use spki::SubjectPublicKeyInfoOwned;
9 use std::{str::FromStr, time::Duration};
10 use x509_cert::{
11     builder::{Builder, CertificateBuilder, Profile, RequestBuilder},
12     ext::pkix::{
13         name::{DirectoryString, GeneralName},
14         SubjectAltName,
15     },
16     name::Name,
17     request,
18     serial_number::SerialNumber,
19     time::Validity,
20 };
21 use x509_cert_test_support::{openssl, zlint};
22 
23 const RSA_2048_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-pub.der");
24 const PKCS8_PUBLIC_KEY_DER: &[u8] = include_bytes!("examples/p256-pub.der");
25 
26 #[test]
root_ca_certificate()27 fn root_ca_certificate() {
28     let serial_number = SerialNumber::from(42u32);
29     let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
30     let profile = Profile::Root;
31     let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US")
32         .unwrap()
33         .to_der()
34         .unwrap();
35     let subject = Name::from_der(&subject).unwrap();
36     let pub_key =
37         SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
38 
39     let signer = rsa_signer();
40     let builder =
41         CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
42             .expect("Create certificate");
43 
44     let certificate = builder.build().unwrap();
45 
46     let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
47     println!("{}", openssl::check_certificate(pem.as_bytes()));
48 
49     let ignored = &[];
50     zlint::check_certificate(pem.as_bytes(), ignored);
51 }
52 
53 #[test]
root_ca_certificate_ecdsa()54 fn root_ca_certificate_ecdsa() {
55     let serial_number = SerialNumber::from(42u32);
56     let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
57     let profile = Profile::Root;
58     let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US")
59         .unwrap()
60         .to_der()
61         .unwrap();
62     let subject = Name::from_der(&subject).unwrap();
63     let pub_key =
64         SubjectPublicKeyInfoOwned::try_from(PKCS8_PUBLIC_KEY_DER).expect("get ecdsa pub key");
65 
66     let signer = ecdsa_signer();
67     let builder =
68         CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
69             .expect("Create certificate");
70 
71     let certificate = builder.build::<DerSignature>().unwrap();
72 
73     let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
74     println!("{}", openssl::check_certificate(pem.as_bytes()));
75 
76     let ignored = &[];
77     zlint::check_certificate(pem.as_bytes(), ignored);
78 }
79 
80 #[test]
sub_ca_certificate()81 fn sub_ca_certificate() {
82     let serial_number = SerialNumber::from(42u32);
83     let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
84 
85     let issuer =
86         Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
87     let profile = Profile::SubCA {
88         issuer,
89         path_len_constraint: Some(0),
90     };
91 
92     let subject =
93         Name::from_str("CN=World domination task force,O=World domination Inc,C=US").unwrap();
94     let pub_key =
95         SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
96 
97     let signer = ecdsa_signer();
98     let builder =
99         CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
100             .expect("Create certificate");
101 
102     let certificate = builder.build::<DerSignature>().unwrap();
103 
104     let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
105     println!("{}", openssl::check_certificate(pem.as_bytes()));
106 
107     // TODO(baloo): not too sure we should tackle those in this API.
108     let ignored = &[
109         "w_sub_ca_aia_missing",
110         "e_sub_ca_crl_distribution_points_missing",
111         "e_sub_ca_certificate_policies_missing",
112         "w_sub_ca_aia_does_not_contain_issuing_ca_url",
113     ];
114 
115     zlint::check_certificate(pem.as_bytes(), ignored);
116 }
117 
118 #[test]
leaf_certificate()119 fn leaf_certificate() {
120     let serial_number = SerialNumber::from(42u32);
121     let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
122 
123     let issuer =
124         Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
125     let profile = Profile::Leaf {
126         issuer: issuer.clone(),
127         enable_key_agreement: false,
128         enable_key_encipherment: false,
129         #[cfg(feature = "hazmat")]
130         include_subject_key_identifier: true,
131     };
132 
133     let subject = Name::from_str("CN=service.domination.world").unwrap();
134     let pub_key =
135         SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
136 
137     let signer = ecdsa_signer();
138     let builder = CertificateBuilder::new(
139         profile,
140         serial_number.clone(),
141         validity,
142         subject.clone(),
143         pub_key.clone(),
144         &signer,
145     )
146     .expect("Create certificate");
147 
148     let certificate = builder.build::<DerSignature>().unwrap();
149 
150     let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
151     println!("{}", openssl::check_certificate(pem.as_bytes()));
152 
153     // TODO(baloo): not too sure we should tackle those in this API.
154     let ignored = vec![
155         "e_sub_cert_aia_missing",
156         "e_sub_cert_crl_distribution_points_missing",
157         "w_sub_cert_aia_does_not_contain_issuing_ca_url",
158         // Missing policies
159         "e_sub_cert_certificate_policies_missing",
160         "e_sub_cert_cert_policy_empty",
161         // Needs to be added by the end-user
162         "e_sub_cert_aia_does_not_contain_ocsp_url",
163         // SAN needs to include DNS name (if used)
164         "e_ext_san_missing",
165         "e_subject_common_name_not_exactly_from_san",
166         // Extended key usage needs to be added by end-user and is use-case dependent
167         "e_sub_cert_eku_missing",
168     ];
169 
170     zlint::check_certificate(pem.as_bytes(), &ignored);
171 
172     #[cfg(feature = "hazmat")]
173     {
174         let profile = Profile::Leaf {
175             issuer,
176             enable_key_agreement: false,
177             enable_key_encipherment: false,
178             include_subject_key_identifier: false,
179         };
180         let builder =
181             CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
182                 .expect("Create certificate");
183 
184         let certificate = builder.build::<DerSignature>().unwrap();
185 
186         let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
187         println!("{}", openssl::check_certificate(pem.as_bytes()));
188 
189         // Ignore warning about leaf not having SKI extension (this is a warning not a fail, as
190         // denoted by the `w_` prefix.
191         let mut ignored = ignored;
192         ignored.push("w_ext_subject_key_identifier_missing_sub_cert");
193         zlint::check_certificate(pem.as_bytes(), &ignored);
194     }
195 }
196 
197 #[test]
pss_certificate()198 fn pss_certificate() {
199     let serial_number = SerialNumber::from(42u32);
200     let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
201 
202     let issuer =
203         Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();
204     let profile = Profile::Leaf {
205         issuer,
206         enable_key_agreement: false,
207         enable_key_encipherment: false,
208         #[cfg(feature = "hazmat")]
209         include_subject_key_identifier: true,
210     };
211 
212     let subject = Name::from_str("CN=service.domination.world").unwrap();
213     let pub_key =
214         SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key");
215 
216     let signer = rsa_pss_signer();
217     let builder =
218         CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)
219             .expect("Create certificate");
220 
221     let certificate = builder
222         .build_with_rng::<rsa::pss::Signature>(&mut rand::thread_rng())
223         .unwrap();
224 
225     let pem = certificate.to_pem(LineEnding::LF).expect("generate pem");
226     println!("{}", openssl::check_certificate(pem.as_bytes()));
227 
228     // TODO(baloo): not too sure we should tackle those in this API.
229     let ignored = &[
230         "e_sub_cert_aia_missing",
231         "e_sub_cert_crl_distribution_points_missing",
232         "w_sub_cert_aia_does_not_contain_issuing_ca_url",
233         // Missing policies
234         "e_sub_cert_certificate_policies_missing",
235         "e_sub_cert_cert_policy_empty",
236         // Needs to be added by the end-user
237         "e_sub_cert_aia_does_not_contain_ocsp_url",
238         // SAN needs to include DNS name (if used)
239         "e_ext_san_missing",
240         "e_subject_common_name_not_exactly_from_san",
241         // Extended key usage needs to be added by end-user and is use-case dependent
242         "e_sub_cert_eku_missing",
243         // zlint warns on RSAPSS signature algorithms
244         "e_signature_algorithm_not_supported",
245     ];
246 
247     zlint::check_certificate(pem.as_bytes(), ignored);
248 }
249 
250 const RSA_2048_PRIV_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.der");
251 
rsa_signer() -> SigningKey<Sha256>252 fn rsa_signer() -> SigningKey<Sha256> {
253     let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER_EXAMPLE).unwrap();
254     SigningKey::<Sha256>::new(private_key)
255 }
256 
rsa_pss_signer() -> rsa::pss::SigningKey<Sha256>257 fn rsa_pss_signer() -> rsa::pss::SigningKey<Sha256> {
258     let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER_EXAMPLE).unwrap();
259     rsa::pss::SigningKey::<Sha256>::new(private_key)
260 }
261 
262 const PKCS8_PRIVATE_KEY_DER: &[u8] = include_bytes!("examples/p256-priv.der");
263 
ecdsa_signer() -> ecdsa::SigningKey<NistP256>264 fn ecdsa_signer() -> ecdsa::SigningKey<NistP256> {
265     let secret_key = p256::SecretKey::from_pkcs8_der(PKCS8_PRIVATE_KEY_DER).unwrap();
266     ecdsa::SigningKey::from(secret_key)
267 }
268 
269 #[test]
certificate_request()270 fn certificate_request() {
271     use std::net::{IpAddr, Ipv4Addr};
272     let subject = Name::from_str("CN=service.domination.world").unwrap();
273 
274     let signer = ecdsa_signer();
275     let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request");
276     builder
277         .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4(
278             Ipv4Addr::new(192, 0, 2, 0),
279         ))]))
280         .unwrap();
281 
282     let cert_req = builder.build::<DerSignature>().unwrap();
283     let pem = cert_req.to_pem(LineEnding::LF).expect("generate pem");
284     use std::fs::File;
285     use std::io::Write;
286     let mut file = File::create("/tmp/ecdsa.csr").expect("create pem file");
287     file.write_all(pem.as_bytes()).expect("Create pem file");
288     println!("{}", openssl::check_request(pem.as_bytes()));
289 }
290 
291 #[test]
certificate_request_attributes()292 fn certificate_request_attributes() {
293     let subject = Name::from_str("CN=service.domination.world").unwrap();
294 
295     let signer = ecdsa_signer();
296     let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request");
297     builder
298         .add_attribute(&request::attributes::ChallengePassword(
299             DirectoryString::PrintableString(
300                 PrintableString::new(b"password1234")
301                     .expect("create printable string with password"),
302             ),
303         ))
304         .expect("unable to add attribute");
305 
306     let cert_req = builder.build::<DerSignature>().unwrap();
307     let pem = cert_req.to_pem(LineEnding::LF).expect("generate pem");
308     use std::fs::File;
309     use std::io::Write;
310     let mut file = File::create("/tmp/ecdsa.csr").expect("create pem file");
311     file.write_all(pem.as_bytes()).expect("Create pem file");
312     println!("{}", openssl::check_request(pem.as_bytes()));
313 }
314