Skip to content

Commit

Permalink
Add an example of making a CA and certs and verifying.
Browse files Browse the repository at this point in the history
  • Loading branch information
bvinc committed Oct 18, 2017
1 parent 09f2a3e commit b23e5b5
Showing 1 changed file with 153 additions and 0 deletions.
153 changes: 153 additions & 0 deletions openssl/examples/mk_certs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
//! A program that generates ca certs, certs verified by the ca, and public
//! and private keys.
extern crate openssl;

use openssl::asn1::Asn1Time;
use openssl::bn::BigNum;
use openssl::error::ErrorStack;
use openssl::hash::MessageDigest;
use openssl::pkey::{PKey, PKeyRef};
use openssl::rand::rand_bytes;
use openssl::rsa::Rsa;
use openssl::x509::{X509, X509Ref};
use openssl::x509::{X509NameBuilder, X509Req, X509ReqBuilder};
use openssl::x509::extension::{AuthorityKeyIdentifier, BasicConstraints, KeyUsage,
SubjectAlternativeName, SubjectKeyIdentifier};

/// Make a CA certificate and private key
fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> {
let rsa = Rsa::generate(2048)?;
let privkey = 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 buf = [0;20];
rand_bytes(&mut buf)?;
BigNum::from_slice(&buf)?.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(&privkey)?;
let not_before = Asn1Time::days_from_now(0)?;
cert_builder.set_not_before(&not_before)?;
let not_after = Asn1Time::days_from_now(365)?;
cert_builder.set_not_after(&not_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(&privkey, MessageDigest::sha256())?;
let cert = cert_builder.build();

Ok((cert, privkey))
}

/// Make a X509 request with the given private key
fn mk_request(privkey: &PKey) -> Result<(X509Req), ErrorStack> {
let mut req_builder = X509ReqBuilder::new()?;
req_builder.set_pubkey(&privkey)?;

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(&privkey, 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_privkey: &PKeyRef) -> Result<(X509, PKey), ErrorStack> {
let rsa = Rsa::generate(2048)?;
let privkey = PKey::from_rsa(rsa)?;

let req = mk_request(&privkey)?;

let mut cert_builder = X509::builder()?;
cert_builder.set_version(2)?;
let serial_number = {
let mut buf = [0;20];
rand_bytes(&mut buf)?;
BigNum::from_slice(&buf)?.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(&privkey)?;
let not_before = Asn1Time::days_from_now(0)?;
cert_builder.set_not_before(&not_before)?;
let not_after = Asn1Time::days_from_now(365)?;
cert_builder.set_not_after(&not_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_privkey, MessageDigest::sha256())?;
let cert = cert_builder.build();

Ok((cert, privkey))
}

fn real_main() -> Result<(), ErrorStack> {
let (ca_cert, ca_privkey) = mk_ca_cert()?;
let (cert, _privkey) = mk_ca_signed_cert(&ca_cert, &ca_privkey)?;

// Verify that this cert was issued by this ca
match ca_cert.issued(&cert) {
Err(ver_err) => println!("Failed to verify certificate: {}", ver_err),
Ok(()) => println!("Certificate verified!"),
};

Ok(())
}

fn main() {
match real_main() {
Ok(()) => println!("Finished."),
Err(e) => println!("Error: {}", e),
};
}

0 comments on commit b23e5b5

Please sign in to comment.