1use std::sync::Arc;
26
27use libp2p_identity as identity;
28use libp2p_identity::PeerId;
29use x509_parser::{prelude::*, signature_algorithm::SignatureAlgorithm};
30
31const P2P_EXT_OID: [u64; 9] = [1, 3, 6, 1, 4, 1, 53594, 1, 1];
35
36const P2P_SIGNING_PREFIX: [u8; 21] = *b"libp2p-tls-handshake:";
42
43static P2P_SIGNATURE_ALGORITHM: &rcgen::SignatureAlgorithm = &rcgen::PKCS_ECDSA_P256_SHA256;
46
47#[derive(Debug)]
48pub(crate) struct AlwaysResolvesCert(Arc<rustls::sign::CertifiedKey>);
49
50impl AlwaysResolvesCert {
51 pub(crate) fn new(
52 cert: rustls::pki_types::CertificateDer<'static>,
53 key: &rustls::pki_types::PrivateKeyDer<'_>,
54 ) -> Result<Self, rustls::Error> {
55 let certified_key = rustls::sign::CertifiedKey::new(
56 vec![cert],
57 rustls::crypto::ring::sign::any_ecdsa_type(key)?,
58 );
59 Ok(Self(Arc::new(certified_key)))
60 }
61}
62
63impl rustls::client::ResolvesClientCert for AlwaysResolvesCert {
64 fn resolve(
65 &self,
66 _root_hint_subjects: &[&[u8]],
67 _sigschemes: &[rustls::SignatureScheme],
68 ) -> Option<Arc<rustls::sign::CertifiedKey>> {
69 Some(Arc::clone(&self.0))
70 }
71
72 fn has_certs(&self) -> bool {
73 true
74 }
75}
76
77impl rustls::server::ResolvesServerCert for AlwaysResolvesCert {
78 fn resolve(
79 &self,
80 _client_hello: rustls::server::ClientHello<'_>,
81 ) -> Option<Arc<rustls::sign::CertifiedKey>> {
82 Some(Arc::clone(&self.0))
83 }
84}
85
86pub fn generate(
89 identity_keypair: &identity::Keypair,
90) -> Result<
91 (
92 rustls::pki_types::CertificateDer<'static>,
93 rustls::pki_types::PrivateKeyDer<'static>,
94 ),
95 GenError,
96> {
97 let certificate_keypair = rcgen::KeyPair::generate_for(P2P_SIGNATURE_ALGORITHM)?;
103 let rustls_key = rustls::pki_types::PrivateKeyDer::from(
104 rustls::pki_types::PrivatePkcs8KeyDer::from(certificate_keypair.serialize_der()),
105 );
106
107 let certificate = {
108 let mut params = rcgen::CertificateParams::new(vec![])?;
109 params.distinguished_name = rcgen::DistinguishedName::new();
110 params.custom_extensions.push(make_libp2p_extension(
111 identity_keypair,
112 &certificate_keypair,
113 )?);
114 params.self_signed(&certificate_keypair)?
115 };
116
117 Ok((certificate.into(), rustls_key))
118}
119
120pub fn parse<'a>(
125 certificate: &'a rustls::pki_types::CertificateDer<'a>,
126) -> Result<P2pCertificate<'a>, ParseError> {
127 let certificate = parse_unverified(certificate.as_ref())?;
128
129 certificate.verify()?;
130
131 Ok(certificate)
132}
133
134#[derive(Debug)]
137pub struct P2pCertificate<'a> {
138 certificate: X509Certificate<'a>,
139 extension: P2pExtension,
143}
144
145#[derive(Debug)]
148pub struct P2pExtension {
149 public_key: identity::PublicKey,
150 signature: Vec<u8>,
153}
154
155#[derive(Debug, thiserror::Error)]
156#[error(transparent)]
157pub struct GenError(#[from] rcgen::Error);
158
159#[derive(Debug, thiserror::Error)]
160#[error(transparent)]
161pub struct ParseError(#[from] pub(crate) webpki::Error);
162
163#[derive(Debug, thiserror::Error)]
164#[error(transparent)]
165pub struct VerificationError(#[from] pub(crate) webpki::Error);
166
167fn parse_unverified(der_input: &[u8]) -> Result<P2pCertificate, webpki::Error> {
171 let x509 = X509Certificate::from_der(der_input)
172 .map(|(_rest_input, x509)| x509)
173 .map_err(|_| webpki::Error::BadDer)?;
174
175 let p2p_ext_oid = der_parser::oid::Oid::from(&P2P_EXT_OID)
176 .expect("This is a valid OID of p2p extension; qed");
177
178 let mut libp2p_extension = None;
179
180 for ext in x509.extensions() {
181 let oid = &ext.oid;
182 if oid == &p2p_ext_oid && libp2p_extension.is_some() {
183 return Err(webpki::Error::BadDer);
185 }
186
187 if oid == &p2p_ext_oid {
188 let (public_key, signature): (Vec<u8>, Vec<u8>) =
196 yasna::decode_der(ext.value).map_err(|_| webpki::Error::ExtensionValueInvalid)?;
197 let public_key = identity::PublicKey::try_decode_protobuf(&public_key)
210 .map_err(|_| webpki::Error::UnknownIssuer)?;
211 let ext = P2pExtension {
212 public_key,
213 signature,
214 };
215 libp2p_extension = Some(ext);
216 continue;
217 }
218
219 if ext.critical {
220 return Err(webpki::Error::UnsupportedCriticalExtension);
223 }
224
225 }
227
228 let extension = libp2p_extension.ok_or(webpki::Error::BadDer)?;
231
232 let certificate = P2pCertificate {
233 certificate: x509,
234 extension,
235 };
236
237 Ok(certificate)
238}
239
240fn make_libp2p_extension(
241 identity_keypair: &identity::Keypair,
242 certificate_keypair: &rcgen::KeyPair,
243) -> Result<rcgen::CustomExtension, rcgen::Error> {
244 let signature = {
248 let mut msg = vec![];
249 msg.extend(P2P_SIGNING_PREFIX);
250 msg.extend(certificate_keypair.public_key_der());
251
252 identity_keypair
253 .sign(&msg)
254 .map_err(|_| rcgen::Error::RingUnspecified)?
255 };
256
257 let extension_content = {
265 let serialized_pubkey = identity_keypair.public().encode_protobuf();
266 yasna::encode_der(&(serialized_pubkey, signature))
267 };
268
269 let mut ext = rcgen::CustomExtension::from_oid_content(&P2P_EXT_OID, extension_content);
271 ext.set_criticality(true);
272
273 Ok(ext)
274}
275
276impl P2pCertificate<'_> {
277 pub fn peer_id(&self) -> PeerId {
279 self.extension.public_key.to_peer_id()
280 }
281
282 pub fn verify_signature(
285 &self,
286 signature_scheme: rustls::SignatureScheme,
287 message: &[u8],
288 signature: &[u8],
289 ) -> Result<(), VerificationError> {
290 let pk = self.public_key(signature_scheme)?;
291 pk.verify(message, signature)
292 .map_err(|_| webpki::Error::InvalidSignatureForPublicKey)?;
293
294 Ok(())
295 }
296
297 fn public_key(
301 &self,
302 signature_scheme: rustls::SignatureScheme,
303 ) -> Result<ring::signature::UnparsedPublicKey<&[u8]>, webpki::Error> {
304 use ring::signature;
305 use rustls::SignatureScheme::*;
306
307 let current_signature_scheme = self.signature_scheme()?;
308 if signature_scheme != current_signature_scheme {
309 return Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey);
311 }
312
313 let verification_algorithm: &dyn signature::VerificationAlgorithm = match signature_scheme {
314 RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_2048_8192_SHA256,
315 RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_2048_8192_SHA384,
316 RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_2048_8192_SHA512,
317 ECDSA_NISTP256_SHA256 => &signature::ECDSA_P256_SHA256_ASN1,
318 ECDSA_NISTP384_SHA384 => &signature::ECDSA_P384_SHA384_ASN1,
319 ECDSA_NISTP521_SHA512 => {
320 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
322 }
323 RSA_PSS_SHA256 => &signature::RSA_PSS_2048_8192_SHA256,
324 RSA_PSS_SHA384 => &signature::RSA_PSS_2048_8192_SHA384,
325 RSA_PSS_SHA512 => &signature::RSA_PSS_2048_8192_SHA512,
326 ED25519 => &signature::ED25519,
327 ED448 => {
328 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
330 }
331 RSA_PKCS1_SHA1 => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
335 ECDSA_SHA1_Legacy => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
336 _ => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
337 };
338 let spki = &self.certificate.tbs_certificate.subject_pki;
339 let key = signature::UnparsedPublicKey::new(
340 verification_algorithm,
341 spki.subject_public_key.as_ref(),
342 );
343
344 Ok(key)
345 }
346
347 fn verify(&self) -> Result<(), webpki::Error> {
355 use webpki::Error;
356 if !self.certificate.validity().is_valid() {
359 return Err(Error::InvalidCertValidity);
360 }
361
362 let signature_scheme = self.signature_scheme()?;
368 let raw_certificate = self.certificate.tbs_certificate.as_ref();
371 let signature = self.certificate.signature_value.as_ref();
372 self.verify_signature(signature_scheme, raw_certificate, signature)
374 .map_err(|_| Error::SignatureAlgorithmMismatch)?;
375
376 let subject_pki = self.certificate.public_key().raw;
377
378 let mut msg = vec![];
382 msg.extend(P2P_SIGNING_PREFIX);
383 msg.extend(subject_pki);
384
385 let user_owns_sk = self
390 .extension
391 .public_key
392 .verify(&msg, &self.extension.signature);
393 if !user_owns_sk {
394 return Err(Error::UnknownIssuer);
395 }
396
397 Ok(())
398 }
399
400 fn signature_scheme(&self) -> Result<rustls::SignatureScheme, webpki::Error> {
404 use oid_registry::*;
407 use rustls::SignatureScheme::*;
408
409 let signature_algorithm = &self.certificate.signature_algorithm;
410 let pki_algorithm = &self.certificate.tbs_certificate.subject_pki.algorithm;
411
412 if pki_algorithm.algorithm == OID_PKCS1_RSAENCRYPTION {
413 if signature_algorithm.algorithm == OID_PKCS1_SHA256WITHRSA {
414 return Ok(RSA_PKCS1_SHA256);
415 }
416 if signature_algorithm.algorithm == OID_PKCS1_SHA384WITHRSA {
417 return Ok(RSA_PKCS1_SHA384);
418 }
419 if signature_algorithm.algorithm == OID_PKCS1_SHA512WITHRSA {
420 return Ok(RSA_PKCS1_SHA512);
421 }
422 if signature_algorithm.algorithm == OID_PKCS1_RSASSAPSS {
423 if let Ok(SignatureAlgorithm::RSASSA_PSS(params)) =
433 SignatureAlgorithm::try_from(signature_algorithm)
434 {
435 let hash_oid = params.hash_algorithm_oid();
436 if hash_oid == &OID_NIST_HASH_SHA256 {
437 return Ok(RSA_PSS_SHA256);
438 }
439 if hash_oid == &OID_NIST_HASH_SHA384 {
440 return Ok(RSA_PSS_SHA384);
441 }
442 if hash_oid == &OID_NIST_HASH_SHA512 {
443 return Ok(RSA_PSS_SHA512);
444 }
445 }
446
447 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
450 }
451 }
452
453 if pki_algorithm.algorithm == OID_KEY_TYPE_EC_PUBLIC_KEY {
454 let signature_param = pki_algorithm
455 .parameters
456 .as_ref()
457 .ok_or(webpki::Error::BadDer)?
458 .as_oid()
459 .map_err(|_| webpki::Error::BadDer)?;
460 if signature_param == OID_EC_P256
461 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA256
462 {
463 return Ok(ECDSA_NISTP256_SHA256);
464 }
465 if signature_param == OID_NIST_EC_P384
466 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA384
467 {
468 return Ok(ECDSA_NISTP384_SHA384);
469 }
470 if signature_param == OID_NIST_EC_P521
471 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA512
472 {
473 return Ok(ECDSA_NISTP521_SHA512);
474 }
475 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
476 }
477
478 if signature_algorithm.algorithm == OID_SIG_ED25519 {
479 return Ok(ED25519);
480 }
481 if signature_algorithm.algorithm == OID_SIG_ED448 {
482 return Ok(ED448);
483 }
484
485 Err(webpki::Error::UnsupportedSignatureAlgorithm)
486 }
487}
488
489#[cfg(test)]
490mod tests {
491 use hex_literal::hex;
492
493 use super::*;
494
495 #[test]
496 fn sanity_check() {
497 let keypair = identity::Keypair::generate_ed25519();
498
499 let (cert, _) = generate(&keypair).unwrap();
500 let parsed_cert = parse(&cert).unwrap();
501
502 assert!(parsed_cert.verify().is_ok());
503 assert_eq!(keypair.public(), parsed_cert.extension.public_key);
504 }
505
506 macro_rules! check_cert {
507 ($name:ident, $path:literal, $scheme:path) => {
508 #[test]
509 fn $name() {
510 let cert: &[u8] = include_bytes!($path);
511
512 let cert = parse_unverified(cert).unwrap();
513 assert!(cert.verify().is_err()); assert_eq!(cert.signature_scheme(), Ok($scheme));
517 }
518 };
519 }
520
521 check_cert! {ed448, "./test_assets/ed448.der", rustls::SignatureScheme::ED448}
522 check_cert! {ed25519, "./test_assets/ed25519.der", rustls::SignatureScheme::ED25519}
523 check_cert! {rsa_pkcs1_sha256, "./test_assets/rsa_pkcs1_sha256.der", rustls::SignatureScheme::RSA_PKCS1_SHA256}
524 check_cert! {rsa_pkcs1_sha384, "./test_assets/rsa_pkcs1_sha384.der", rustls::SignatureScheme::RSA_PKCS1_SHA384}
525 check_cert! {rsa_pkcs1_sha512, "./test_assets/rsa_pkcs1_sha512.der", rustls::SignatureScheme::RSA_PKCS1_SHA512}
526 check_cert! {nistp256_sha256, "./test_assets/nistp256_sha256.der", rustls::SignatureScheme::ECDSA_NISTP256_SHA256}
527 check_cert! {nistp384_sha384, "./test_assets/nistp384_sha384.der", rustls::SignatureScheme::ECDSA_NISTP384_SHA384}
528 check_cert! {nistp521_sha512, "./test_assets/nistp521_sha512.der", rustls::SignatureScheme::ECDSA_NISTP521_SHA512}
529
530 #[test]
531 fn rsa_pss_sha384() {
532 let cert = rustls::pki_types::CertificateDer::from(
533 include_bytes!("./test_assets/rsa_pss_sha384.der").to_vec(),
534 );
535
536 let cert = parse(&cert).unwrap();
537
538 assert_eq!(
539 cert.signature_scheme(),
540 Ok(rustls::SignatureScheme::RSA_PSS_SHA384)
541 );
542 }
543
544 #[test]
545 fn nistp384_sha256() {
546 let cert: &[u8] = include_bytes!("./test_assets/nistp384_sha256.der");
547
548 let cert = parse_unverified(cert).unwrap();
549
550 assert!(cert.signature_scheme().is_err());
551 }
552
553 #[test]
554 fn can_parse_certificate_with_ed25519_keypair() {
555 let certificate = rustls::pki_types::CertificateDer::from(hex!("308201773082011ea003020102020900f5bd0debaa597f52300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d030107034200046bf9871220d71dcb3483ecdfcbfcc7c103f8509d0974b3c18ab1f1be1302d643103a08f7a7722c1b247ba3876fe2c59e26526f479d7718a85202ddbe47562358a37f307d307b060a2b0601040183a25a01010101ff046a30680424080112207fda21856709c5ae12fd6e8450623f15f11955d384212b89f56e7e136d2e17280440aaa6bffabe91b6f30c35e3aa4f94b1188fed96b0ffdd393f4c58c1c047854120e674ce64c788406d1c2c4b116581fd7411b309881c3c7f20b46e54c7e6fe7f0f300a06082a8648ce3d040302034700304402207d1a1dbd2bda235ff2ec87daf006f9b04ba076a5a5530180cd9c2e8f6399e09d0220458527178c7e77024601dbb1b256593e9b96d961b96349d1f560114f61a87595").to_vec());
556
557 let peer_id = parse(&certificate).unwrap().peer_id();
558
559 assert_eq!(
560 "12D3KooWJRSrypvnpHgc6ZAgyCni4KcSmbV7uGRaMw5LgMKT18fq"
561 .parse::<PeerId>()
562 .unwrap(),
563 peer_id
564 );
565 }
566
567 #[test]
568 fn fails_to_parse_bad_certificate_with_ed25519_keypair() {
569 let certificate = rustls::pki_types::CertificateDer::from(hex!("308201773082011da003020102020830a73c5d896a1109300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d03010703420004bbe62df9a7c1c46b7f1f21d556deec5382a36df146fb29c7f1240e60d7d5328570e3b71d99602b77a65c9b3655f62837f8d66b59f1763b8c9beba3be07778043a37f307d307b060a2b0601040183a25a01010101ff046a3068042408011220ec8094573afb9728088860864f7bcea2d4fd412fef09a8e2d24d482377c20db60440ecabae8354afa2f0af4b8d2ad871e865cb5a7c0c8d3dbdbf42de577f92461a0ebb0a28703e33581af7d2a4f2270fc37aec6261fcc95f8af08f3f4806581c730a300a06082a8648ce3d040302034800304502202dfb17a6fa0f94ee0e2e6a3b9fb6e986f311dee27392058016464bd130930a61022100ba4b937a11c8d3172b81e7cd04aedb79b978c4379c2b5b24d565dd5d67d3cb3c").to_vec());
570
571 let error = parse(&certificate).unwrap_err();
572
573 assert_eq!(format!("{error}"), "UnknownIssuer");
574 }
575
576 #[test]
577 fn can_parse_certificate_with_ecdsa_keypair() {
578 let certificate = rustls::pki_types::CertificateDer::from(hex!("308201c030820166a003020102020900eaf419a6e3edb4a6300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d030107034200048dbf1116c7c608d6d5292bd826c3feb53483a89fce434bf64538a359c8e07538ff71f6766239be6a146dcc1a5f3bb934bcd4ae2ae1d4da28ac68b4a20593f06ba381c63081c33081c0060a2b0601040183a25a01010101ff0481ae3081ab045f0803125b3059301306072a8648ce3d020106082a8648ce3d0301070342000484b93fa456a74bd0153919f036db7bc63c802f055bc7023395d0203de718ee0fc7b570b767cdd858aca6c7c4113ff002e78bd2138ac1a3b26dde3519e06979ad04483046022100bc84014cea5a41feabdf4c161096564b9ccf4b62fbef4fe1cd382c84e11101780221009204f086a84cb8ed8a9ddd7868dc90c792ee434adf62c66f99a08a5eba11615b300a06082a8648ce3d0403020348003045022054b437be9a2edf591312d68ff24bf91367ad4143f76cf80b5658f232ade820da022100e23b48de9df9c25d4c83ddddf75d2676f0b9318ee2a6c88a736d85eab94a912f").to_vec());
579
580 let peer_id = parse(&certificate).unwrap().peer_id();
581
582 assert_eq!(
583 "QmZcrvr3r4S3QvwFdae3c2EWTfo792Y14UpzCZurhmiWeX"
584 .parse::<PeerId>()
585 .unwrap(),
586 peer_id
587 );
588 }
589
590 #[test]
591 fn can_parse_certificate_with_secp256k1_keypair() {
592 let certificate = rustls::pki_types::CertificateDer::from(hex!("3082018230820128a003020102020900f3b305f55622cfdf300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d0301070342000458f7e9581748ff9bdd933b655cc0e5552a1248f840658cc221dec2186b5a2fe4641b86ab7590a3422cdbb1000cf97662f27e5910d7569f22feed8829c8b52e0fa38188308185308182060a2b0601040183a25a01010101ff0471306f042508021221026b053094d1112bce799dc8026040ae6d4eb574157929f1598172061f753d9b1b04463044022040712707e97794c478d93989aaa28ae1f71c03af524a8a4bd2d98424948a782302207b61b7f074b696a25fb9e0059141a811cccc4cc28042d9301b9b2a4015e87470300a06082a8648ce3d04030203480030450220143ae4d86fdc8675d2480bb6912eca5e39165df7f572d836aa2f2d6acfab13f8022100831d1979a98f0c4a6fb5069ca374de92f1a1205c962a6d90ad3d7554cb7d9df4").to_vec());
593
594 let peer_id = parse(&certificate).unwrap().peer_id();
595
596 assert_eq!(
597 "16Uiu2HAm2dSCBFxuge46aEt7U1oejtYuBUZXxASHqmcfVmk4gsbx"
598 .parse::<PeerId>()
599 .unwrap(),
600 peer_id
601 );
602 }
603}