openpgp_x509_sequoia/
lib.rs1use std::ops::DerefMut;
6
7use anyhow::Result;
8use asn1_rs::nom::AsBytes;
9use chrono::{DateTime, Utc};
10use sequoia_openpgp::packet::key::{PublicParts, SecretParts, UnspecifiedRole};
11use sequoia_openpgp::packet::Key;
12use sequoia_openpgp::Cert;
13use sha2::{Digest, Sha256, Sha384, Sha512};
14use x509::der::write::{der_octet_string, der_sequence};
15use x509::write::algorithm_identifier;
16use x509_certificate::X509Certificate;
17use zeroize::Zeroizing;
18
19use crate::types::{AlgorithmId, DigestId, PublicKeyInfo, SigId};
20
21pub mod experimental;
22pub mod types;
23
24const CB_OBJ_MAX: usize = 3072 - 9;
26
27fn aid_to_sid(algo_id: AlgorithmId) -> SigId {
28 match algo_id {
29 AlgorithmId::Rsa2048 => SigId::Sha256WithRsaEncryption,
30 AlgorithmId::Rsa3072 => SigId::Sha384WithRsaEncryption,
31 AlgorithmId::Rsa4096 => SigId::Sha512WithRsaEncryption,
32
33 AlgorithmId::EccP256 => SigId::EcdsaWithSha256,
34 AlgorithmId::EccP384 => SigId::EcdsaWithSha384,
35 AlgorithmId::EccP521 => SigId::EcdsaWithSha512,
36 }
37}
38
39pub fn generate_x509(
49 subject_pki: &PublicKeyInfo,
50 key: &Key<SecretParts, UnspecifiedRole>,
51 common_name: &str,
52 extensions: &[x509::Extension<&'static [u64]>],
53) -> Zeroizing<Vec<u8>> {
54 let creation: DateTime<Utc> = key.creation_time().into();
55
56 let fp: [u8; 20] = key
58 .fingerprint()
59 .as_bytes()
60 .try_into()
61 .expect("fingerprint len != 20");
62 let serial: Vec<u8> = fp.into();
63
64 let subject = x509::RelativeDistinguishedName::common_name(common_name);
65
66 let signature_algorithm = aid_to_sid(subject_pki.algorithm());
67
68 let mut tbs_cert = Zeroizing::new(Vec::with_capacity(CB_OBJ_MAX));
70
71 cookie_factory::gen(
72 x509::write::tbs_certificate::<&mut Vec<u8>, SigId, PublicKeyInfo, &'static [u64]>(
73 &serial,
74 &signature_algorithm,
75 &[subject.clone()],
77 creation,
78 None, &[subject],
80 subject_pki,
81 extensions,
82 ),
83 tbs_cert.deref_mut(),
84 )
85 .expect("can serialize to Vec");
86
87 tbs_cert
88}
89
90#[allow(clippy::type_complexity)]
92pub fn self_sign_x509(
93 tbs_cert: Zeroizing<Vec<u8>>,
94 algo_id: AlgorithmId,
95 signer: &mut dyn FnMut(&[u8], AlgorithmId) -> Result<Vec<u8>>,
96) -> Result<Vec<u8>> {
97 fn sig<Alg: x509::AlgorithmIdentifier>(
98 h: &'_ [u8],
99 algorithm_ident: &'_ Alg,
100 algo_id: AlgorithmId,
101 signer: &mut dyn FnMut(&[u8], AlgorithmId) -> Result<Vec<u8>>,
102 ) -> Result<Vec<u8>> {
103 let t = cookie_factory::gen_simple(
104 der_sequence((algorithm_identifier(algorithm_ident), der_octet_string(h))),
105 vec![],
106 )
107 .expect("can serialize into Vec");
108
109 signer(&t, algo_id)
111 }
112
113 let signature_algorithm = aid_to_sid(algo_id);
114
115 let signature: Vec<_> = match signature_algorithm {
116 SigId::Sha256WithRsaEncryption => {
117 let h = Sha256::digest(&tbs_cert);
118 sig(&h, &DigestId::Sha256, algo_id, signer)?
119 }
120 SigId::Sha384WithRsaEncryption => {
121 let h = Sha384::digest(&tbs_cert);
122 sig(&h, &DigestId::Sha384, algo_id, signer)?
123 }
124 SigId::Sha512WithRsaEncryption => {
125 let h = Sha512::digest(&tbs_cert);
126 sig(&h, &DigestId::Sha512, algo_id, signer)?
127 }
128 SigId::EcdsaWithSha256 => signer(&Sha256::digest(&tbs_cert), algo_id)?,
129 SigId::EcdsaWithSha384 => signer(&Sha384::digest(&tbs_cert), algo_id)?,
130 SigId::EcdsaWithSha512 => signer(&Sha512::digest(&tbs_cert), algo_id)?,
131 };
132
133 let mut data = Zeroizing::new(Vec::with_capacity(CB_OBJ_MAX));
134
135 cookie_factory::gen(
136 x509::write::certificate(&tbs_cert, &signature_algorithm, &signature),
137 data.deref_mut(),
138 )
139 .expect("can serialize to Vec");
140
141 Ok(data.to_vec())
142}
143
144pub fn find_key_by_x509cert(
147 x509cert: &X509Certificate,
148 cert: &Cert,
149) -> Result<Key<PublicParts, UnspecifiedRole>> {
150 use sequoia_openpgp::crypto::mpi::PublicKey;
151
152 let x509_cert = x509_certificate::rfc5280::Certificate::from(x509cert.clone());
153
154 if let Ok(rsa_pub) = x509cert.rsa_public_key_data() {
155 for k in cert.keys() {
156 if let PublicKey::RSA { n, .. } = k.key().mpis() {
157 let modulus = rsa_pub.modulus.as_slice();
158 if modulus.len() < n.value().len() {
159 continue;
164 }
165
166 if modulus == n.value_padded(modulus.len()).unwrap().as_ref() {
172 return Ok(k.key().clone());
173 }
174 }
175 }
176 } else {
177 let ai = x509_cert.tbs_certificate.subject_public_key_info.algorithm;
178
179 if ai.algorithm.0.as_bytes() != [42, 134, 72, 206, 61, 2, 1] {
180 return Err(anyhow::anyhow!("Unexpected KeyAlgorithm {:?}", ai));
181 }
182
183 let ec = x509_cert
184 .tbs_certificate
185 .subject_public_key_info
186 .subject_public_key;
187
188 for k in cert.keys() {
189 match k.key().mpis() {
190 PublicKey::ECDSA { q, .. } | PublicKey::ECDH { q, .. } => {
191 if ec.octet_bytes().as_ref() == q.value() {
192 return Ok(k.key().clone());
193 }
194 }
195 _ => {}
196 }
197 }
198 }
199
200 Err(anyhow::anyhow!("Didn't find matching key in Cert"))
201}