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());
    }
}