1 //! A program that generates ca certs, certs verified by the ca, and public
2 //! and private keys.
3 
4 use openssl::asn1::Asn1Time;
5 use openssl::bn::{BigNum, MsbOption};
6 use openssl::error::ErrorStack;
7 use openssl::hash::MessageDigest;
8 use openssl::pkey::{PKey, PKeyRef, Private};
9 use openssl::rsa::Rsa;
10 use openssl::x509::extension::{
11     AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName,
12     SubjectKeyIdentifier,
13 };
14 use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509};
15 
16 /// Make a CA certificate and private key
mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack>17 fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> {
18     let rsa = Rsa::generate(2048)?;
19     let key_pair = PKey::from_rsa(rsa)?;
20 
21     let mut x509_name = X509NameBuilder::new()?;
22     x509_name.append_entry_by_text("C", "US")?;
23     x509_name.append_entry_by_text("ST", "TX")?;
24     x509_name.append_entry_by_text("O", "Some CA organization")?;
25     x509_name.append_entry_by_text("CN", "ca test")?;
26     let x509_name = x509_name.build();
27 
28     let mut cert_builder = X509::builder()?;
29     cert_builder.set_version(2)?;
30     let serial_number = {
31         let mut serial = BigNum::new()?;
32         serial.rand(159, MsbOption::MAYBE_ZERO, false)?;
33         serial.to_asn1_integer()?
34     };
35     cert_builder.set_serial_number(&serial_number)?;
36     cert_builder.set_subject_name(&x509_name)?;
37     cert_builder.set_issuer_name(&x509_name)?;
38     cert_builder.set_pubkey(&key_pair)?;
39     let not_before = Asn1Time::days_from_now(0)?;
40     cert_builder.set_not_before(&not_before)?;
41     let not_after = Asn1Time::days_from_now(365)?;
42     cert_builder.set_not_after(&not_after)?;
43 
44     cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?;
45     cert_builder.append_extension(
46         KeyUsage::new()
47             .critical()
48             .key_cert_sign()
49             .crl_sign()
50             .build()?,
51     )?;
52 
53     let subject_key_identifier =
54         SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
55     cert_builder.append_extension(subject_key_identifier)?;
56 
57     cert_builder.sign(&key_pair, MessageDigest::sha256())?;
58     let cert = cert_builder.build();
59 
60     Ok((cert, key_pair))
61 }
62 
63 /// Make a X509 request with the given private key
mk_request(key_pair: &PKey<Private>) -> Result<X509Req, ErrorStack>64 fn mk_request(key_pair: &PKey<Private>) -> Result<X509Req, ErrorStack> {
65     let mut req_builder = X509ReqBuilder::new()?;
66     req_builder.set_pubkey(key_pair)?;
67 
68     let mut x509_name = X509NameBuilder::new()?;
69     x509_name.append_entry_by_text("C", "US")?;
70     x509_name.append_entry_by_text("ST", "TX")?;
71     x509_name.append_entry_by_text("O", "Some organization")?;
72     x509_name.append_entry_by_text("CN", "www.example.com")?;
73     let x509_name = x509_name.build();
74     req_builder.set_subject_name(&x509_name)?;
75 
76     req_builder.sign(key_pair, MessageDigest::sha256())?;
77     let req = req_builder.build();
78     Ok(req)
79 }
80 
81 /// Make a certificate and private key signed by the given CA cert and private key
mk_ca_signed_cert( ca_cert: &X509Ref, ca_key_pair: &PKeyRef<Private>, ) -> Result<(X509, PKey<Private>), ErrorStack>82 fn mk_ca_signed_cert(
83     ca_cert: &X509Ref,
84     ca_key_pair: &PKeyRef<Private>,
85 ) -> Result<(X509, PKey<Private>), ErrorStack> {
86     let rsa = Rsa::generate(2048)?;
87     let key_pair = PKey::from_rsa(rsa)?;
88 
89     let req = mk_request(&key_pair)?;
90 
91     let mut cert_builder = X509::builder()?;
92     cert_builder.set_version(2)?;
93     let serial_number = {
94         let mut serial = BigNum::new()?;
95         serial.rand(159, MsbOption::MAYBE_ZERO, false)?;
96         serial.to_asn1_integer()?
97     };
98     cert_builder.set_serial_number(&serial_number)?;
99     cert_builder.set_subject_name(req.subject_name())?;
100     cert_builder.set_issuer_name(ca_cert.subject_name())?;
101     cert_builder.set_pubkey(&key_pair)?;
102     let not_before = Asn1Time::days_from_now(0)?;
103     cert_builder.set_not_before(&not_before)?;
104     let not_after = Asn1Time::days_from_now(365)?;
105     cert_builder.set_not_after(&not_after)?;
106 
107     cert_builder.append_extension(BasicConstraints::new().build()?)?;
108 
109     cert_builder.append_extension(
110         KeyUsage::new()
111             .critical()
112             .non_repudiation()
113             .digital_signature()
114             .key_encipherment()
115             .build()?,
116     )?;
117 
118     let subject_key_identifier =
119         SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
120     cert_builder.append_extension(subject_key_identifier)?;
121 
122     let auth_key_identifier = AuthorityKeyIdentifier::new()
123         .keyid(false)
124         .issuer(false)
125         .build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
126     cert_builder.append_extension(auth_key_identifier)?;
127 
128     let subject_alt_name = SubjectAlternativeName::new()
129         .dns("*.example.com")
130         .dns("hello.com")
131         .build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
132     cert_builder.append_extension(subject_alt_name)?;
133 
134     cert_builder.sign(ca_key_pair, MessageDigest::sha256())?;
135     let cert = cert_builder.build();
136 
137     Ok((cert, key_pair))
138 }
139 
real_main() -> Result<(), ErrorStack>140 fn real_main() -> Result<(), ErrorStack> {
141     let (ca_cert, ca_key_pair) = mk_ca_cert()?;
142     let (cert, _key_pair) = mk_ca_signed_cert(&ca_cert, &ca_key_pair)?;
143 
144     // Verify that this cert was issued by this ca
145     match ca_cert.issued(&cert) {
146         X509VerifyResult::OK => println!("Certificate verified!"),
147         ver_err => println!("Failed to verify certificate: {}", ver_err),
148     };
149 
150     Ok(())
151 }
152 
main()153 fn main() {
154     match real_main() {
155         Ok(()) => println!("Finished."),
156         Err(e) => println!("Error: {}", e),
157     };
158 }
159