1use foctet_core::id::NodeId;
6use foctet_core::key;
7use std::sync::Arc;
8use x509_parser::{prelude::*, signature_algorithm::SignatureAlgorithm};
9const FOCTET_EXT_OID: [u64; 9] = [1, 3, 6, 1, 4, 1, 32473, 1, 1];
12
13const FOCTET_SIGNING_PREFIX: [u8; 21] = *b"foctet-tls-handshake:";
19
20static FOCTET_SIGNATURE_ALGORITHM: &rcgen::SignatureAlgorithm = &rcgen::PKCS_ECDSA_P256_SHA256;
23
24#[derive(Debug)]
25pub(crate) struct AlwaysResolvesCert(Arc<rustls::sign::CertifiedKey>);
26
27impl AlwaysResolvesCert {
28 pub(crate) fn new(
29 cert: rustls::pki_types::CertificateDer<'static>,
30 key: &rustls::pki_types::PrivateKeyDer<'_>,
31 ) -> Result<Self, rustls::Error> {
32 let certified_key = rustls::sign::CertifiedKey::new(
33 vec![cert],
34 rustls::crypto::ring::sign::any_ecdsa_type(key)?,
35 );
36 Ok(Self(Arc::new(certified_key)))
37 }
38}
39
40impl rustls::client::ResolvesClientCert for AlwaysResolvesCert {
41 fn resolve(
42 &self,
43 _root_hint_subjects: &[&[u8]],
44 _sigschemes: &[rustls::SignatureScheme],
45 ) -> Option<Arc<rustls::sign::CertifiedKey>> {
46 Some(Arc::clone(&self.0))
47 }
48
49 fn has_certs(&self) -> bool {
50 true
51 }
52}
53
54impl rustls::server::ResolvesServerCert for AlwaysResolvesCert {
55 fn resolve(
56 &self,
57 _client_hello: rustls::server::ClientHello<'_>,
58 ) -> Option<Arc<rustls::sign::CertifiedKey>> {
59 Some(Arc::clone(&self.0))
60 }
61}
62
63pub fn generate(
66 identity_keypair: &key::Keypair,
67) -> Result<
68 (
69 rustls::pki_types::CertificateDer<'static>,
70 rustls::pki_types::PrivateKeyDer<'static>,
71 ),
72 GenError,
73> {
74 let node_id = identity_keypair.public();
75 let node_id_base32 = node_id.to_base32();
76 let node_id_uri = format!("foctet://{}", node_id_base32);
77 let certificate_keypair = rcgen::KeyPair::generate_for(FOCTET_SIGNATURE_ALGORITHM)?;
78 let rustls_key = rustls::pki_types::PrivateKeyDer::from(
79 rustls::pki_types::PrivatePkcs8KeyDer::from(certificate_keypair.serialize_der()),
80 );
81 let mut params = rcgen::CertificateParams::new(vec![])?;
82 params
83 .subject_alt_names
84 .push(rcgen::SanType::URI(rcgen::Ia5String::try_from(
85 node_id_uri,
86 )?));
87 params.distinguished_name = rcgen::DistinguishedName::new();
88
89 let mut signing_msg = Vec::new();
92 signing_msg.extend(FOCTET_SIGNING_PREFIX);
93 signing_msg.extend(&certificate_keypair.public_key_der());
94
95 let signature = identity_keypair.sign(&signing_msg);
96
97 let signed_extension = yasna::construct_der(|writer| {
99 writer.write_sequence(|writer| {
100 writer.next().write_bytes(&node_id.to_bytes());
101 writer.next().write_bytes(&signature);
102 })
103 });
104
105 params
107 .custom_extensions
108 .push(rcgen::CustomExtension::from_oid_content(
109 &FOCTET_EXT_OID,
110 signed_extension,
111 ));
112
113 let certificate = params.self_signed(&certificate_keypair)?;
114
115 let rustls_certificate = rustls::pki_types::CertificateDer::from(certificate);
116
117 Ok((rustls_certificate, rustls_key))
118}
119
120pub fn parse<'a>(
125 cert: &'a rustls::pki_types::CertificateDer<'a>,
126) -> Result<FoctetCertificate<'a>, ParseError> {
127 let cert = parse_unverified(cert.as_ref())?;
128 cert.verify()?;
129 Ok(cert)
130}
131
132#[derive(Debug)]
135pub struct FoctetCertificate<'a> {
136 certificate: X509Certificate<'a>,
137 extension: FoctetExtension,
138}
139
140#[derive(Debug)]
143pub struct FoctetExtension {
144 public_key: key::PublicKey,
145 signature: Vec<u8>,
148}
149
150#[derive(Debug, thiserror::Error)]
151#[error(transparent)]
152pub struct GenError(#[from] rcgen::Error);
153
154#[derive(Debug, thiserror::Error)]
155#[error(transparent)]
156pub struct ParseError(#[from] pub(crate) webpki::Error);
157
158#[derive(Debug, thiserror::Error)]
159#[error(transparent)]
160pub struct VerificationError(#[from] pub(crate) webpki::Error);
161
162fn parse_unverified(der_input: &[u8]) -> Result<FoctetCertificate, webpki::Error> {
166 let x509_cert = x509_parser::parse_x509_certificate(der_input)
167 .map_err(|_| webpki::Error::BadDer)?
168 .1;
169
170 let san_node_id = match x509_cert.subject_alternative_name() {
171 Ok(san_opt) => {
172 let san = san_opt.ok_or(webpki::Error::BadDer)?;
173 let uri = san
174 .value
175 .general_names
176 .iter()
177 .find_map(|gn| {
178 if let GeneralName::URI(uri) = gn {
179 Some(uri)
180 } else {
181 None
182 }
183 })
184 .ok_or(webpki::Error::UnknownIssuer)?;
185 let node_id = NodeId::from_base32(&uri["foctet://".len()..])
186 .map_err(|_| webpki::Error::UnknownIssuer)?;
187 node_id
188 }
189 Err(e) => {
190 tracing::error!("Failed to parse SAN: {:?}", e);
191 return Err(webpki::Error::UnknownIssuer);
192 }
193 };
194
195 let custom_oid = der_parser::oid::Oid::from(&FOCTET_EXT_OID)
196 .expect("This is a valid OID of foctet extension");
197
198 let mut extracted_node_id = None;
199 let mut extracted_signature = None;
200
201 for ext in x509_cert.extensions() {
202 if ext.oid == custom_oid {
203 let (node_id_bytes, signature_bytes): (Vec<u8>, Vec<u8>) =
204 yasna::decode_der(&ext.value).map_err(|_| webpki::Error::ExtensionValueInvalid)?;
205 extracted_node_id = Some(node_id_bytes);
206 extracted_signature = Some(signature_bytes);
207 }
208 }
209 let node_id_bytes = extracted_node_id.ok_or(webpki::Error::UnknownIssuer)?;
210 let signature = extracted_signature.ok_or(webpki::Error::UnknownIssuer)?;
211
212 let ext_node_id =
213 key::PublicKey::try_from_bytes(&node_id_bytes).map_err(|_| webpki::Error::UnknownIssuer)?;
214 if san_node_id != ext_node_id {
215 return Err(webpki::Error::UnknownIssuer);
216 }
217 let ext = FoctetExtension {
218 public_key: ext_node_id,
219 signature,
220 };
221
222 Ok(FoctetCertificate {
223 certificate: x509_cert,
224 extension: ext,
225 })
226}
227
228impl FoctetCertificate<'_> {
229 pub fn node_id(&self) -> NodeId {
231 self.extension.public_key
232 }
233
234 pub fn verify_signature(
237 &self,
238 signature_scheme: rustls::SignatureScheme,
239 message: &[u8],
240 signature: &[u8],
241 ) -> Result<(), VerificationError> {
242 let pk = self.public_key(signature_scheme)?;
243 pk.verify(message, signature)
244 .map_err(|_| webpki::Error::InvalidSignatureForPublicKey)?;
245
246 Ok(())
247 }
248 fn public_key(
252 &self,
253 signature_scheme: rustls::SignatureScheme,
254 ) -> Result<ring::signature::UnparsedPublicKey<&[u8]>, webpki::Error> {
255 use ring::signature;
256 use rustls::SignatureScheme::*;
257
258 let current_signature_scheme = self.signature_scheme()?;
259 if signature_scheme != current_signature_scheme {
260 return Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey);
262 }
263
264 let verification_algorithm: &dyn signature::VerificationAlgorithm = match signature_scheme {
265 RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_2048_8192_SHA256,
266 RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_2048_8192_SHA384,
267 RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_2048_8192_SHA512,
268 ECDSA_NISTP256_SHA256 => &signature::ECDSA_P256_SHA256_ASN1,
269 ECDSA_NISTP384_SHA384 => &signature::ECDSA_P384_SHA384_ASN1,
270 ECDSA_NISTP521_SHA512 => {
271 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
273 }
274 RSA_PSS_SHA256 => &signature::RSA_PSS_2048_8192_SHA256,
275 RSA_PSS_SHA384 => &signature::RSA_PSS_2048_8192_SHA384,
276 RSA_PSS_SHA512 => &signature::RSA_PSS_2048_8192_SHA512,
277 ED25519 => &signature::ED25519,
278 ED448 => {
279 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
281 }
282 RSA_PKCS1_SHA1 => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
286 ECDSA_SHA1_Legacy => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
287 _ => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
288 };
289 let spki = &self.certificate.tbs_certificate.subject_pki;
290 let key = signature::UnparsedPublicKey::new(
291 verification_algorithm,
292 spki.subject_public_key.as_ref(),
293 );
294
295 Ok(key)
296 }
297
298 fn verify(&self) -> Result<(), webpki::Error> {
306 use webpki::Error;
307 if !self.certificate.validity().is_valid() {
310 return Err(Error::InvalidCertValidity);
311 }
312
313 let signature_scheme = self.signature_scheme()?;
319 let raw_certificate = self.certificate.tbs_certificate.as_ref();
322 let signature = self.certificate.signature_value.as_ref();
323 self.verify_signature(signature_scheme, raw_certificate, signature)
325 .map_err(|_| Error::SignatureAlgorithmMismatch)?;
326
327 let subject_pki = self.certificate.public_key().raw;
329 let mut signing_msg = Vec::new();
330 signing_msg.extend(FOCTET_SIGNING_PREFIX);
331 signing_msg.extend(subject_pki);
332 if !self
333 .extension
334 .public_key
335 .verify(&signing_msg, &self.extension.signature)
336 {
337 return Err(Error::InvalidSignatureForPublicKey);
338 }
339 Ok(())
340 }
341
342 fn signature_scheme(&self) -> Result<rustls::SignatureScheme, webpki::Error> {
346 use oid_registry::*;
349 use rustls::SignatureScheme::*;
350
351 let signature_algorithm = &self.certificate.signature_algorithm;
352 let pki_algorithm = &self.certificate.tbs_certificate.subject_pki.algorithm;
353
354 if pki_algorithm.algorithm == OID_PKCS1_RSAENCRYPTION {
355 if signature_algorithm.algorithm == OID_PKCS1_SHA256WITHRSA {
356 return Ok(RSA_PKCS1_SHA256);
357 }
358 if signature_algorithm.algorithm == OID_PKCS1_SHA384WITHRSA {
359 return Ok(RSA_PKCS1_SHA384);
360 }
361 if signature_algorithm.algorithm == OID_PKCS1_SHA512WITHRSA {
362 return Ok(RSA_PKCS1_SHA512);
363 }
364 if signature_algorithm.algorithm == OID_PKCS1_RSASSAPSS {
365 if let Ok(SignatureAlgorithm::RSASSA_PSS(params)) =
375 SignatureAlgorithm::try_from(signature_algorithm)
376 {
377 let hash_oid = params.hash_algorithm_oid();
378 if hash_oid == &OID_NIST_HASH_SHA256 {
379 return Ok(RSA_PSS_SHA256);
380 }
381 if hash_oid == &OID_NIST_HASH_SHA384 {
382 return Ok(RSA_PSS_SHA384);
383 }
384 if hash_oid == &OID_NIST_HASH_SHA512 {
385 return Ok(RSA_PSS_SHA512);
386 }
387 }
388
389 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
392 }
393 }
394
395 if pki_algorithm.algorithm == OID_KEY_TYPE_EC_PUBLIC_KEY {
396 let signature_param = pki_algorithm
397 .parameters
398 .as_ref()
399 .ok_or(webpki::Error::BadDer)?
400 .as_oid()
401 .map_err(|_| webpki::Error::BadDer)?;
402 if signature_param == OID_EC_P256
403 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA256
404 {
405 return Ok(ECDSA_NISTP256_SHA256);
406 }
407 if signature_param == OID_NIST_EC_P384
408 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA384
409 {
410 return Ok(ECDSA_NISTP384_SHA384);
411 }
412 if signature_param == OID_NIST_EC_P521
413 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA512
414 {
415 return Ok(ECDSA_NISTP521_SHA512);
416 }
417 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
418 }
419
420 if signature_algorithm.algorithm == OID_SIG_ED25519 {
421 return Ok(ED25519);
422 }
423 if signature_algorithm.algorithm == OID_SIG_ED448 {
424 return Ok(ED448);
425 }
426
427 Err(webpki::Error::UnsupportedSignatureAlgorithm)
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434
435 #[test]
436 fn generate_parse_verify() {
437 let keypair = key::Keypair::generate();
438
439 let (cert, _) = generate(&keypair).unwrap();
440 let parsed_cert = parse(&cert).unwrap();
441
442 assert!(parsed_cert.verify().is_ok());
443 assert_eq!(keypair.public(), parsed_cert.node_id());
444 }
445}