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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
//! CBOR Encoded X.509 Certificate (C509 Certificate) library
//!
//! This crate provides a functionality for generating C509 Certificate.
//!
//! ## C509 certificate contains 2 parts
//! 1. `TBSCertificate`
//! 2. `issuerSignatureValue`
//!
//! In order to generate an unsigned C509 certificate, the TBS Certificate must be
//! provided. Then the unsigned C509 certificate will then be used to calculate the
//! issuerSignatureValue.
//!
//! # TBS Certificate
//!
//! The To Be Sign Certificate contains the following fields:
//! * c509CertificateType: A certificate type, whether 0 a natively signed C509
//! certificate following X.509 v3 or 1 a CBOR re-encoded X.509 v3 DER certificate.
//! * certificateSerialNumber: A unique serial number for the certificate.
//! * issuer: The entity that issued the certificate.
//! * validityNotBefore: The duration for which the Certificate Authority (CA)
//! guarantees it will retain information regarding the certificate's status on which
//! the period begins.
//! * validityNotAfter: The duration for which the Certificate Authority (CA)
//! guarantees it will retain information regarding the certificate's status on which
//! the period ends.
//! * subject: The entity associated with the public key stored in the subject public
//! key field.
//! * subjectPublicKeyAlgorithm: The algorithm that the public key is used.
//! * subjectPublicKey: The public key of the subject.
//! * extensions: A list of extensions defined for X.509 v3 certificate, providing
//! additional attributes for users or public keys, and for managing relationships
//! between Certificate Authorities (CAs).
//! * issuerSignatureAlgorithm: The algorithm used to sign the certificate (must be the
//! algorithm uses to create `IssuerSignatureValue`).
//!
//! Please refer to the [C509 Certificate](https://datatracker.ietf.org/doc/draft-ietf-cose-cbor-encoded-cert/09/) for more information.
use anyhow::anyhow;
use c509::C509;
use minicbor::{Decode, Encode};
use signing::{PrivateKey, PublicKey};
use tbs_cert::TbsCert;
pub mod algorithm_identifier;
pub mod attributes;
pub mod big_uint;
pub mod c509;
pub mod extensions;
pub mod general_names;
pub mod issuer_sig_algo;
pub mod name;
pub mod oid;
pub mod signing;
pub mod subject_pub_key_algo;
mod tables;
pub mod tbs_cert;
pub mod time;
pub mod wasm_binding;
/// Generate a signed or unsigned C509 certificate.
///
/// # Arguments
/// - `tbs_cert` - A TBS certificate.
/// - `private_key` - An optional private key, if provided certificate is signed.
///
/// # Returns
/// Returns a signed or unsigned C509 certificate.
///
/// # Errors
///
/// Returns an error if tne data cannot be converted to CBOR bytes.
pub fn generate(tbs_cert: &TbsCert, private_key: Option<&PrivateKey>) -> anyhow::Result<Vec<u8>> {
// Encode the TbsCert
let encoded_tbs = {
let mut buffer = Vec::new();
let mut encoder = minicbor::Encoder::new(&mut buffer);
tbs_cert.encode(&mut encoder, &mut ())?;
buffer
};
let sign_data = private_key.map(|pk| pk.sign(&encoded_tbs));
// Encode the whole C509 certificate including `TbSCert` and `issuerSignatureValue`
let encoded_c509 = {
let mut buffer = Vec::new();
let mut encoder = minicbor::Encoder::new(&mut buffer);
let c509 = C509::new(tbs_cert.clone(), sign_data);
c509.encode(&mut encoder, &mut ())?;
buffer
};
Ok(encoded_c509)
}
/// Verify the signature of a C509 certificate.
///
/// # Arguments
/// - `c509` - The cbor encoded C509 certificate to verify.
/// - `public_key` - The public key used to verify the certificate.
///
/// # Errors
/// Returns an error if the `issuer_signature_value` is invalid or the signature cannot be
/// verified.
pub fn verify(c509: &[u8], public_key: &PublicKey) -> anyhow::Result<()> {
let mut d = minicbor::Decoder::new(c509);
let c509 = C509::decode(&mut d, &mut ())?;
let mut encoded_tbs = Vec::new();
let mut encoder = minicbor::Encoder::new(&mut encoded_tbs);
c509.get_tbs_cert().encode(&mut encoder, &mut ())?;
let issuer_sig = c509.get_issuer_signature_value().clone().ok_or(anyhow!(
"Signature verification failed, No issuer signature"
))?;
public_key.verify(&encoded_tbs, &issuer_sig)
}
#[cfg(test)]
mod test {
use std::str::FromStr;
use signing::tests::private_key_str;
use tbs_cert::test_tbs_cert::tbs;
use super::*;
#[test]
fn test_generate_and_verify_signed_c509_cert() {
let tbs_cert = tbs();
let private_key = FromStr::from_str(&private_key_str()).expect("Cannot create private key");
let signed_c509 = generate(&tbs_cert, Some(&private_key))
.expect("Failed to generate signed C509 certificate");
assert!(verify(&signed_c509, &private_key.public_key()).is_ok());
}
}