1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
// Copyright (c) 2023 MASSA LABS <info@massa.net>
//! This module provides functions for generating certificates for a Certificate Authority (CA) and
//! signing certificates using the CA certificate in mutual TLS (mTLS) scenarios.
//!
//! The `gen_cert_for_ca` function generates a certificate for the CA, while the `gen_signed_cert`
//! function generates a certificate signed by the CA. These functions utilize the `rcgen` crate for
//! generating and managing certificates.
use rcgen::{
BasicConstraints, Certificate, CertificateParams, CertificateSigningRequest, DistinguishedName,
DnType, IsCa, KeyUsagePurpose, RcgenError, PKCS_ECDSA_P256_SHA256,
};
use std::collections::HashSet;
/// Generate a certificate for a certificate authority (CA).
///
/// # Returns
///
/// Returns a `Certificate` representing the generated CA certificate, or an `RcgenError` if there was an error during the certificate generation.
pub fn gen_cert_for_ca() -> Result<Certificate, RcgenError> {
let mut dn = DistinguishedName::new();
dn.push(DnType::CommonName, "Auto-Generated Massalabs CA");
let mut params = CertificateParams::default();
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
params.alg = &PKCS_ECDSA_P256_SHA256;
params.distinguished_name = dn;
params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
let ca_cert = Certificate::from_params(params)?;
Ok(ca_cert)
}
/// Generate a certificate signed by a certificate authority (CA).
///
/// # Arguments
///
/// * `ca`: A reference to the CA certificate used to sign the generated certificate.
/// * `subject_alt_names`: A vector of subject alternative names to include in the certificate.
///
/// # Returns
///
/// Returns a tuple containing the signed certificate PEM and the corresponding private key PEM,
/// or an `RcgenError` if there was an error during the certificate generation or signing process.
pub fn gen_signed_cert(
ca: &Certificate,
subject_alt_names: Vec<String>,
) -> Result<(String, String), RcgenError> {
let mut dn = DistinguishedName::new();
dn.push(DnType::CommonName, "Auto-Generated Massa gRPC Server");
// Add "localhost" to the subject alternative names
let all_subject_alt_names_set: HashSet<String> = subject_alt_names
.into_iter()
.chain(vec!["localhost".to_string()])
.collect();
let all_subject_alt_names = all_subject_alt_names_set.into_iter().collect::<Vec<_>>();
let mut params = CertificateParams::new(all_subject_alt_names);
params.is_ca = IsCa::NoCa;
params.alg = &PKCS_ECDSA_P256_SHA256;
params.distinguished_name = dn;
let unsigned = Certificate::from_params(params)?;
let request_pem = unsigned.serialize_request_pem()?;
let csr = CertificateSigningRequest::from_pem(&request_pem)?;
let signed_pem = csr.serialize_pem_with_signer(ca)?;
Ok((signed_pem, unsigned.serialize_private_key_pem()))
}