| 
 | 1 | +use std::error::Error;  | 
 | 2 | +use std::fs;  | 
 | 3 | +use std::path::PathBuf;  | 
 | 4 | + | 
 | 5 | +use rcgen::{CertificateParams, DnType, ExtendedKeyUsagePurpose, Issuer, KeyPair, KeyUsagePurpose};  | 
 | 6 | +use time::{Duration, OffsetDateTime};  | 
 | 7 | + | 
 | 8 | +/// Generate a new certificate, and sign it with an existing root or  | 
 | 9 | +/// intermediate certificate.  | 
 | 10 | +fn main() -> Result<(), Box<dyn Error>> {  | 
 | 11 | +	let mut args = std::env::args().skip(1);  | 
 | 12 | + | 
 | 13 | +	let signer_keys_file = PathBuf::from(  | 
 | 14 | +		args.next()  | 
 | 15 | +			.ok_or("provide signer's pem keys file as 1st argument")?,  | 
 | 16 | +	);  | 
 | 17 | + | 
 | 18 | +	let signer_cert_file = PathBuf::from(  | 
 | 19 | +		args.next()  | 
 | 20 | +			.ok_or("provide signer's pem certificate file as 2nd argument")?,  | 
 | 21 | +	);  | 
 | 22 | + | 
 | 23 | +	let output_keys_file =  | 
 | 24 | +		PathBuf::from(args.next().ok_or("output pem keys file as 3rd argument")?);  | 
 | 25 | + | 
 | 26 | +	let output_cert_file = PathBuf::from(args.next().ok_or("output pem cert file as 4th fourth")?);  | 
 | 27 | + | 
 | 28 | +	// Read existing certificate authority  | 
 | 29 | +	let keys_pem = fs::read_to_string(&signer_keys_file)?;  | 
 | 30 | +	let cert_pem = fs::read_to_string(&signer_cert_file)?;  | 
 | 31 | + | 
 | 32 | +	let key_pair = KeyPair::from_pem(&keys_pem)?;  | 
 | 33 | +	let signer = Issuer::from_ca_cert_pem(&cert_pem, key_pair)?;  | 
 | 34 | + | 
 | 35 | +	// Create a new signed server certificate  | 
 | 36 | +	const DOMAIN: &str = "example.domain";  | 
 | 37 | + | 
 | 38 | +	let sans = vec![DOMAIN.into()];  | 
 | 39 | + | 
 | 40 | +	let mut params = CertificateParams::new(sans)?;  | 
 | 41 | + | 
 | 42 | +	params.distinguished_name.push(DnType::CommonName, DOMAIN);  | 
 | 43 | +	params.use_authority_key_identifier_extension = true;  | 
 | 44 | +	params.key_usages.push(KeyUsagePurpose::DigitalSignature);  | 
 | 45 | +	params  | 
 | 46 | +		.extended_key_usages  | 
 | 47 | +		.push(ExtendedKeyUsagePurpose::ServerAuth);  | 
 | 48 | + | 
 | 49 | +	const DAY: Duration = Duration::days(1);  | 
 | 50 | + | 
 | 51 | +	let yesterday = OffsetDateTime::now_utc()  | 
 | 52 | +		.checked_sub(DAY)  | 
 | 53 | +		.ok_or("invalid yesterday")?;  | 
 | 54 | + | 
 | 55 | +	let tomorrow = OffsetDateTime::now_utc()  | 
 | 56 | +		.checked_add(DAY)  | 
 | 57 | +		.ok_or("invalid tomorrow")?;  | 
 | 58 | + | 
 | 59 | +	params.not_before = yesterday;  | 
 | 60 | +	params.not_after = tomorrow;  | 
 | 61 | + | 
 | 62 | +	let output_keys = KeyPair::generate()?;  | 
 | 63 | +	let output_cert = params.signed_by(&output_keys, &signer)?;  | 
 | 64 | + | 
 | 65 | +	// Write new certificate  | 
 | 66 | +	fs::write(&output_keys_file, output_keys.serialize_pem())?;  | 
 | 67 | +	fs::write(&output_cert_file, output_cert.pem())?;  | 
 | 68 | + | 
 | 69 | +	println!("Wrote signed leaf certificate:");  | 
 | 70 | +	println!("  keys: {}", output_keys_file.display());  | 
 | 71 | +	println!("  cert: {}", output_cert_file.display());  | 
 | 72 | +	println!();  | 
 | 73 | + | 
 | 74 | +	Ok(())  | 
 | 75 | +}  | 
0 commit comments