Skip to main content

rust_pdf_box/crypto/
x509.rs

1use crate::crypto::asn1::DerElement;
2use crate::error::{PdfError, PdfResult};
3use chrono::{Duration, Utc};
4use rsa::RsaPrivateKey;
5use rsa::pkcs1v15::SigningKey as RsaSigningKey;
6use rsa::signature::{SignatureEncoding, Signer as RsaSignerTrait};
7use rsa::traits::PublicKeyParts;
8use sha2::Sha256;
9
10/// A cryptographic signing key and associated X.509 certificate.
11#[derive(Clone)]
12pub struct SigningKey {
13    pub private_key: RsaPrivateKey,
14    pub certificate_der: Vec<u8>,
15    pub issuer_name_der: Vec<u8>,
16    pub serial_number: Vec<u8>,
17}
18
19impl SigningKey {
20    /// Generates an in-memory RSA key pair and a self-signed X.509 certificate for rapid signing.
21    pub fn generate_self_signed(common_name: &str) -> PdfResult<Self> {
22        Self::generate_self_signed_with_bits(common_name, 2048)
23    }
24
25    /// Generates a self-signed certificate with specified RSA key bits (e.g. 2048, 3072, 4096).
26    pub fn generate_self_signed_with_bits(common_name: &str, bits: usize) -> PdfResult<Self> {
27        let mut rng = rand::thread_rng();
28        let private_key = RsaPrivateKey::new(&mut rng, bits)
29            .map_err(|e| PdfError::Crypto(format!("Failed generating RSA key: {e}")))?;
30
31        // Serial number (e.g. 16 random bytes)
32        let serial_num = vec![1, 2, 3, 4, 5, 6, 7, 8];
33
34        // Validity: today to 10 years later
35        let not_before = Utc::now();
36        let not_after = not_before + Duration::days(365 * 10);
37        let not_before_str = not_before.format("%y%m%d%H%M%SZ").to_string();
38        let not_after_str = not_after.format("%y%m%d%H%M%SZ").to_string();
39
40        let validity = DerElement::Sequence(vec![
41            DerElement::UtcTime(not_before_str),
42            DerElement::UtcTime(not_after_str),
43        ]);
44
45        // Subject / Issuer RDN: CN={common_name}
46        let cn_oid = vec![2, 5, 4, 3];
47        let rdn_attr = DerElement::Sequence(vec![
48            DerElement::ObjectIdentifier(cn_oid),
49            DerElement::Utf8String(common_name.to_string()),
50        ]);
51        let rdn_set = DerElement::Set(vec![rdn_attr]);
52        let name_seq = DerElement::Sequence(vec![rdn_set]);
53        let name_der = name_seq.to_der();
54
55        // AlgorithmIdentifier: sha256WithRSAEncryption (1.2.840.113549.1.1.11)
56        let sha256_with_rsa_oid = vec![1, 2, 840, 113549, 1, 1, 11];
57        let alg_id = DerElement::Sequence(vec![
58            DerElement::ObjectIdentifier(sha256_with_rsa_oid.clone()),
59            DerElement::Null,
60        ]);
61
62        // SubjectPublicKeyInfo: rsaEncryption (1.2.840.113549.1.1.1)
63        let rsa_oid = vec![1, 2, 840, 113549, 1, 1, 1];
64        let pub_key = private_key.to_public_key();
65        let n_bytes = pub_key.n().to_bytes_be();
66        let e_bytes = pub_key.e().to_bytes_be();
67        let rsa_pub_der = DerElement::Sequence(vec![
68            DerElement::integer_from_bytes(&n_bytes),
69            DerElement::integer_from_bytes(&e_bytes),
70        ])
71        .to_der();
72
73        let spki = DerElement::Sequence(vec![
74            DerElement::Sequence(vec![
75                DerElement::ObjectIdentifier(rsa_oid),
76                DerElement::Null,
77            ]),
78            DerElement::BitString(rsa_pub_der, 0),
79        ]);
80
81        // TBSCertificate
82        let tbs_cert = DerElement::Sequence(vec![
83            // v3 version tag [0] -> 2
84            DerElement::ContextSpecific(0, Box::new(DerElement::integer_from_u64(2)), true),
85            DerElement::integer_from_bytes(&serial_num),
86            alg_id.clone(),
87            name_seq.clone(), // issuer
88            validity,
89            name_seq.clone(), // subject
90            spki,
91        ]);
92
93        let tbs_der = tbs_cert.to_der();
94
95        // Sign TBSCertificate with RSA-SHA256
96        let signer = RsaSigningKey::<Sha256>::new(private_key.clone());
97        let signature = signer.sign(&tbs_der);
98
99        // Final X.509 Certificate
100        let cert = DerElement::Sequence(vec![
101            tbs_cert,
102            alg_id,
103            DerElement::BitString(signature.to_vec(), 0),
104        ]);
105
106        let cert_der = cert.to_der();
107
108        Ok(Self {
109            private_key,
110            certificate_der: cert_der,
111            issuer_name_der: name_der,
112            serial_number: serial_num,
113        })
114    }
115
116    /// Creates a SigningKey from existing RSA private key and DER-encoded X.509 certificate.
117    pub fn from_rsa_and_cert(private_key: RsaPrivateKey, cert_der: Vec<u8>) -> Self {
118        // Attempt basic extraction of issuer and serial from cert DER, fallback if needed
119        let serial = vec![1];
120        let issuer = vec![0x30, 0x00];
121        Self {
122            private_key,
123            certificate_der: cert_der,
124            issuer_name_der: issuer,
125            serial_number: serial,
126        }
127    }
128}