| #![allow(clippy::uninlined_format_args)] |
| |
| //! A program that generates ca certs, certs verified by the ca, and public |
| //! and private keys. |
| |
| use openssl::asn1::Asn1Time; |
| use openssl::bn::{BigNum, MsbOption}; |
| use openssl::error::ErrorStack; |
| use openssl::hash::MessageDigest; |
| use openssl::pkey::{PKey, PKeyRef, Private}; |
| use openssl::rsa::Rsa; |
| use openssl::x509::extension::{ |
| AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, |
| SubjectKeyIdentifier, |
| }; |
| use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509}; |
| |
| /// Make a CA certificate and private key |
| fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> { |
| let rsa = Rsa::generate(2048)?; |
| let key_pair = PKey::from_rsa(rsa)?; |
| |
| let mut x509_name = X509NameBuilder::new()?; |
| x509_name.append_entry_by_text("C", "US")?; |
| x509_name.append_entry_by_text("ST", "TX")?; |
| x509_name.append_entry_by_text("O", "Some CA organization")?; |
| x509_name.append_entry_by_text("CN", "ca test")?; |
| let x509_name = x509_name.build(); |
| |
| let mut cert_builder = X509::builder()?; |
| cert_builder.set_version(2)?; |
| let serial_number = { |
| let mut serial = BigNum::new()?; |
| serial.rand(159, MsbOption::MAYBE_ZERO, false)?; |
| serial.to_asn1_integer()? |
| }; |
| cert_builder.set_serial_number(&serial_number)?; |
| cert_builder.set_subject_name(&x509_name)?; |
| cert_builder.set_issuer_name(&x509_name)?; |
| cert_builder.set_pubkey(&key_pair)?; |
| let not_before = Asn1Time::days_from_now(0)?; |
| cert_builder.set_not_before(¬_before)?; |
| let not_after = Asn1Time::days_from_now(365)?; |
| cert_builder.set_not_after(¬_after)?; |
| |
| cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?; |
| cert_builder.append_extension( |
| KeyUsage::new() |
| .critical() |
| .key_cert_sign() |
| .crl_sign() |
| .build()?, |
| )?; |
| |
| let subject_key_identifier = |
| SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?; |
| cert_builder.append_extension(subject_key_identifier)?; |
| |
| cert_builder.sign(&key_pair, MessageDigest::sha256())?; |
| let cert = cert_builder.build(); |
| |
| Ok((cert, key_pair)) |
| } |
| |
| /// Make a X509 request with the given private key |
| fn mk_request(key_pair: &PKey<Private>) -> Result<X509Req, ErrorStack> { |
| let mut req_builder = X509ReqBuilder::new()?; |
| req_builder.set_pubkey(key_pair)?; |
| |
| let mut x509_name = X509NameBuilder::new()?; |
| x509_name.append_entry_by_text("C", "US")?; |
| x509_name.append_entry_by_text("ST", "TX")?; |
| x509_name.append_entry_by_text("O", "Some organization")?; |
| x509_name.append_entry_by_text("CN", "www.example.com")?; |
| let x509_name = x509_name.build(); |
| req_builder.set_subject_name(&x509_name)?; |
| |
| req_builder.sign(key_pair, MessageDigest::sha256())?; |
| let req = req_builder.build(); |
| Ok(req) |
| } |
| |
| /// Make a certificate and private key signed by the given CA cert and private key |
| fn mk_ca_signed_cert( |
| ca_cert: &X509Ref, |
| ca_key_pair: &PKeyRef<Private>, |
| ) -> Result<(X509, PKey<Private>), ErrorStack> { |
| let rsa = Rsa::generate(2048)?; |
| let key_pair = PKey::from_rsa(rsa)?; |
| |
| let req = mk_request(&key_pair)?; |
| |
| let mut cert_builder = X509::builder()?; |
| cert_builder.set_version(2)?; |
| let serial_number = { |
| let mut serial = BigNum::new()?; |
| serial.rand(159, MsbOption::MAYBE_ZERO, false)?; |
| serial.to_asn1_integer()? |
| }; |
| cert_builder.set_serial_number(&serial_number)?; |
| cert_builder.set_subject_name(req.subject_name())?; |
| cert_builder.set_issuer_name(ca_cert.subject_name())?; |
| cert_builder.set_pubkey(&key_pair)?; |
| let not_before = Asn1Time::days_from_now(0)?; |
| cert_builder.set_not_before(¬_before)?; |
| let not_after = Asn1Time::days_from_now(365)?; |
| cert_builder.set_not_after(¬_after)?; |
| |
| cert_builder.append_extension(BasicConstraints::new().build()?)?; |
| |
| cert_builder.append_extension( |
| KeyUsage::new() |
| .critical() |
| .non_repudiation() |
| .digital_signature() |
| .key_encipherment() |
| .build()?, |
| )?; |
| |
| let subject_key_identifier = |
| SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?; |
| cert_builder.append_extension(subject_key_identifier)?; |
| |
| let auth_key_identifier = AuthorityKeyIdentifier::new() |
| .keyid(false) |
| .issuer(false) |
| .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; |
| cert_builder.append_extension(auth_key_identifier)?; |
| |
| let subject_alt_name = SubjectAlternativeName::new() |
| .dns("*.example.com") |
| .dns("hello.com") |
| .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; |
| cert_builder.append_extension(subject_alt_name)?; |
| |
| cert_builder.sign(ca_key_pair, MessageDigest::sha256())?; |
| let cert = cert_builder.build(); |
| |
| Ok((cert, key_pair)) |
| } |
| |
| fn real_main() -> Result<(), ErrorStack> { |
| let (ca_cert, ca_key_pair) = mk_ca_cert()?; |
| let (cert, _key_pair) = mk_ca_signed_cert(&ca_cert, &ca_key_pair)?; |
| |
| // Verify that this cert was issued by this ca |
| match ca_cert.issued(&cert) { |
| X509VerifyResult::OK => println!("Certificate verified!"), |
| ver_err => println!("Failed to verify certificate: {}", ver_err), |
| }; |
| |
| Ok(()) |
| } |
| |
| fn main() { |
| match real_main() { |
| Ok(()) => println!("Finished."), |
| Err(e) => println!("Error: {}", e), |
| }; |
| } |