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