1#![allow(clippy::uninlined_format_args)] 2 3//! A program that generates ca certs, certs verified by the ca, and public 4//! and private keys. 5 6use openssl::asn1::Asn1Time; 7use openssl::bn::{BigNum, MsbOption}; 8use openssl::error::ErrorStack; 9use openssl::hash::MessageDigest; 10use openssl::pkey::{PKey, PKeyRef, Private}; 11use openssl::rsa::Rsa; 12use openssl::x509::extension::{ 13 AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, 14 SubjectKeyIdentifier, 15}; 16use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509}; 17 18/// Make a CA certificate and private key 19fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> { 20 let rsa = Rsa::generate(2048)?; 21 let key_pair = 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(&key_pair)?; 41 let not_before = Asn1Time::days_from_now(0)?; 42 cert_builder.set_not_before(¬_before)?; 43 let not_after = Asn1Time::days_from_now(365)?; 44 cert_builder.set_not_after(¬_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(&key_pair, MessageDigest::sha256())?; 60 let cert = cert_builder.build(); 61 62 Ok((cert, key_pair)) 63} 64 65/// Make a X509 request with the given private key 66fn mk_request(key_pair: &PKey<Private>) -> Result<X509Req, ErrorStack> { 67 let mut req_builder = X509ReqBuilder::new()?; 68 req_builder.set_pubkey(key_pair)?; 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(key_pair, 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 84fn mk_ca_signed_cert( 85 ca_cert: &X509Ref, 86 ca_key_pair: &PKeyRef<Private>, 87) -> Result<(X509, PKey<Private>), ErrorStack> { 88 let rsa = Rsa::generate(2048)?; 89 let key_pair = PKey::from_rsa(rsa)?; 90 91 let req = mk_request(&key_pair)?; 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(&key_pair)?; 104 let not_before = Asn1Time::days_from_now(0)?; 105 cert_builder.set_not_before(¬_before)?; 106 let not_after = Asn1Time::days_from_now(365)?; 107 cert_builder.set_not_after(¬_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_key_pair, MessageDigest::sha256())?; 137 let cert = cert_builder.build(); 138 139 Ok((cert, key_pair)) 140} 141 142fn real_main() -> Result<(), ErrorStack> { 143 let (ca_cert, ca_key_pair) = mk_ca_cert()?; 144 let (cert, _key_pair) = mk_ca_signed_cert(&ca_cert, &ca_key_pair)?; 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 155fn main() { 156 match real_main() { 157 Ok(()) => println!("Finished."), 158 Err(e) => println!("Error: {}", e), 159 }; 160} 161