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(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.alg = P2P_SIGNATURE_ALGORITHM;
115 params.key_pair = Some(certificate_keypair);
116 rcgen::Certificate::from_params(params)?
117 };
118
119 let rustls_certificate = rustls::pki_types::CertificateDer::from(certificate.serialize_der()?);
120
121 Ok((rustls_certificate, rustls_key))
122}
123
124pub fn parse<'a>(
129 certificate: &'a rustls::pki_types::CertificateDer<'a>,
130) -> Result<P2pCertificate<'a>, ParseError> {
131 let certificate = parse_unverified(certificate.as_ref())?;
132
133 certificate.verify()?;
134
135 Ok(certificate)
136}
137
138#[derive(Debug)]
141pub struct P2pCertificate<'a> {
142 certificate: X509Certificate<'a>,
143 extension: P2pExtension,
147}
148
149#[derive(Debug)]
152pub struct P2pExtension {
153 public_key: identity::PublicKey,
154 signature: Vec<u8>,
157}
158
159#[derive(Debug, thiserror::Error)]
160#[error(transparent)]
161pub struct GenError(#[from] rcgen::RcgenError);
162
163#[derive(Debug, thiserror::Error)]
164#[error(transparent)]
165pub struct ParseError(#[from] pub(crate) webpki::Error);
166
167#[derive(Debug, thiserror::Error)]
168#[error(transparent)]
169pub struct VerificationError(#[from] pub(crate) webpki::Error);
170
171fn parse_unverified(der_input: &[u8]) -> Result<P2pCertificate, webpki::Error> {
175 let x509 = X509Certificate::from_der(der_input)
176 .map(|(_rest_input, x509)| x509)
177 .map_err(|_| webpki::Error::BadDer)?;
178
179 let p2p_ext_oid = der_parser::oid::Oid::from(&P2P_EXT_OID)
180 .expect("This is a valid OID of p2p extension; qed");
181
182 let mut libp2p_extension = None;
183
184 for ext in x509.extensions() {
185 let oid = &ext.oid;
186 if oid == &p2p_ext_oid && libp2p_extension.is_some() {
187 return Err(webpki::Error::BadDer);
189 }
190
191 if oid == &p2p_ext_oid {
192 let (public_key, signature): (Vec<u8>, Vec<u8>) =
200 yasna::decode_der(ext.value).map_err(|_| webpki::Error::ExtensionValueInvalid)?;
201 let public_key = identity::PublicKey::try_decode_protobuf(&public_key)
214 .map_err(|_| webpki::Error::UnknownIssuer)?;
215 let ext = P2pExtension {
216 public_key,
217 signature,
218 };
219 libp2p_extension = Some(ext);
220 continue;
221 }
222
223 if ext.critical {
224 return Err(webpki::Error::UnsupportedCriticalExtension);
227 }
228
229 }
231
232 let extension = libp2p_extension.ok_or(webpki::Error::BadDer)?;
235
236 let certificate = P2pCertificate {
237 certificate: x509,
238 extension,
239 };
240
241 Ok(certificate)
242}
243
244fn make_libp2p_extension(
245 identity_keypair: &identity::Keypair,
246 certificate_keypair: &rcgen::KeyPair,
247) -> Result<rcgen::CustomExtension, rcgen::RcgenError> {
248 let signature = {
252 let mut msg = vec![];
253 msg.extend(P2P_SIGNING_PREFIX);
254 msg.extend(certificate_keypair.public_key_der());
255
256 identity_keypair
257 .sign(&msg)
258 .map_err(|_| rcgen::RcgenError::RingUnspecified)?
259 };
260
261 let extension_content = {
269 let serialized_pubkey = identity_keypair.public().encode_protobuf();
270 yasna::encode_der(&(serialized_pubkey, signature))
271 };
272
273 let mut ext = rcgen::CustomExtension::from_oid_content(&P2P_EXT_OID, extension_content);
275 ext.set_criticality(true);
276
277 Ok(ext)
278}
279
280impl P2pCertificate<'_> {
281 pub fn peer_id(&self) -> PeerId {
283 self.extension.public_key.to_peer_id()
284 }
285
286 pub fn verify_signature(
289 &self,
290 signature_scheme: rustls::SignatureScheme,
291 message: &[u8],
292 signature: &[u8],
293 ) -> Result<(), VerificationError> {
294 let pk = self.public_key(signature_scheme)?;
295 pk.verify(message, signature)
296 .map_err(|_| webpki::Error::InvalidSignatureForPublicKey)?;
297
298 Ok(())
299 }
300
301 fn public_key(
305 &self,
306 signature_scheme: rustls::SignatureScheme,
307 ) -> Result<ring::signature::UnparsedPublicKey<&[u8]>, webpki::Error> {
308 use ring::signature;
309 use rustls::SignatureScheme::*;
310
311 let current_signature_scheme = self.signature_scheme()?;
312 if signature_scheme != current_signature_scheme {
313 return Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey);
315 }
316
317 let verification_algorithm: &dyn signature::VerificationAlgorithm = match signature_scheme {
318 RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_2048_8192_SHA256,
319 RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_2048_8192_SHA384,
320 RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_2048_8192_SHA512,
321 ECDSA_NISTP256_SHA256 => &signature::ECDSA_P256_SHA256_ASN1,
322 ECDSA_NISTP384_SHA384 => &signature::ECDSA_P384_SHA384_ASN1,
323 ECDSA_NISTP521_SHA512 => {
324 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
326 }
327 RSA_PSS_SHA256 => &signature::RSA_PSS_2048_8192_SHA256,
328 RSA_PSS_SHA384 => &signature::RSA_PSS_2048_8192_SHA384,
329 RSA_PSS_SHA512 => &signature::RSA_PSS_2048_8192_SHA512,
330 ED25519 => &signature::ED25519,
331 ED448 => {
332 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
334 }
335 RSA_PKCS1_SHA1 => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
339 ECDSA_SHA1_Legacy => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
340 _ => return Err(webpki::Error::UnsupportedSignatureAlgorithm),
341 };
342 let spki = &self.certificate.tbs_certificate.subject_pki;
343 let key = signature::UnparsedPublicKey::new(
344 verification_algorithm,
345 spki.subject_public_key.as_ref(),
346 );
347
348 Ok(key)
349 }
350
351 fn verify(&self) -> Result<(), webpki::Error> {
359 use webpki::Error;
360 if !self.certificate.validity().is_valid() {
363 return Err(Error::InvalidCertValidity);
364 }
365
366 let signature_scheme = self.signature_scheme()?;
372 let raw_certificate = self.certificate.tbs_certificate.as_ref();
375 let signature = self.certificate.signature_value.as_ref();
376 self.verify_signature(signature_scheme, raw_certificate, signature)
378 .map_err(|_| Error::SignatureAlgorithmMismatch)?;
379
380 let subject_pki = self.certificate.public_key().raw;
381
382 let mut msg = vec![];
386 msg.extend(P2P_SIGNING_PREFIX);
387 msg.extend(subject_pki);
388
389 let user_owns_sk = self
394 .extension
395 .public_key
396 .verify(&msg, &self.extension.signature);
397 if !user_owns_sk {
398 return Err(Error::UnknownIssuer);
399 }
400
401 Ok(())
402 }
403
404 fn signature_scheme(&self) -> Result<rustls::SignatureScheme, webpki::Error> {
408 use oid_registry::*;
411 use rustls::SignatureScheme::*;
412
413 let signature_algorithm = &self.certificate.signature_algorithm;
414 let pki_algorithm = &self.certificate.tbs_certificate.subject_pki.algorithm;
415
416 if pki_algorithm.algorithm == OID_PKCS1_RSAENCRYPTION {
417 if signature_algorithm.algorithm == OID_PKCS1_SHA256WITHRSA {
418 return Ok(RSA_PKCS1_SHA256);
419 }
420 if signature_algorithm.algorithm == OID_PKCS1_SHA384WITHRSA {
421 return Ok(RSA_PKCS1_SHA384);
422 }
423 if signature_algorithm.algorithm == OID_PKCS1_SHA512WITHRSA {
424 return Ok(RSA_PKCS1_SHA512);
425 }
426 if signature_algorithm.algorithm == OID_PKCS1_RSASSAPSS {
427 if let Ok(SignatureAlgorithm::RSASSA_PSS(params)) =
437 SignatureAlgorithm::try_from(signature_algorithm)
438 {
439 let hash_oid = params.hash_algorithm_oid();
440 if hash_oid == &OID_NIST_HASH_SHA256 {
441 return Ok(RSA_PSS_SHA256);
442 }
443 if hash_oid == &OID_NIST_HASH_SHA384 {
444 return Ok(RSA_PSS_SHA384);
445 }
446 if hash_oid == &OID_NIST_HASH_SHA512 {
447 return Ok(RSA_PSS_SHA512);
448 }
449 }
450
451 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
454 }
455 }
456
457 if pki_algorithm.algorithm == OID_KEY_TYPE_EC_PUBLIC_KEY {
458 let signature_param = pki_algorithm
459 .parameters
460 .as_ref()
461 .ok_or(webpki::Error::BadDer)?
462 .as_oid()
463 .map_err(|_| webpki::Error::BadDer)?;
464 if signature_param == OID_EC_P256
465 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA256
466 {
467 return Ok(ECDSA_NISTP256_SHA256);
468 }
469 if signature_param == OID_NIST_EC_P384
470 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA384
471 {
472 return Ok(ECDSA_NISTP384_SHA384);
473 }
474 if signature_param == OID_NIST_EC_P521
475 && signature_algorithm.algorithm == OID_SIG_ECDSA_WITH_SHA512
476 {
477 return Ok(ECDSA_NISTP521_SHA512);
478 }
479 return Err(webpki::Error::UnsupportedSignatureAlgorithm);
480 }
481
482 if signature_algorithm.algorithm == OID_SIG_ED25519 {
483 return Ok(ED25519);
484 }
485 if signature_algorithm.algorithm == OID_SIG_ED448 {
486 return Ok(ED448);
487 }
488
489 Err(webpki::Error::UnsupportedSignatureAlgorithm)
490 }
491}
492
493#[cfg(test)]
494mod tests {
495 use hex_literal::hex;
496
497 use super::*;
498
499 #[test]
500 fn sanity_check() {
501 let keypair = identity::Keypair::generate_ed25519();
502
503 let (cert, _) = generate(&keypair).unwrap();
504 let parsed_cert = parse(&cert).unwrap();
505
506 assert!(parsed_cert.verify().is_ok());
507 assert_eq!(keypair.public(), parsed_cert.extension.public_key);
508 }
509
510 macro_rules! check_cert {
511 ($name:ident, $path:literal, $scheme:path) => {
512 #[test]
513 fn $name() {
514 let cert: &[u8] = include_bytes!($path);
515
516 let cert = parse_unverified(cert).unwrap();
517 assert!(cert.verify().is_err()); assert_eq!(cert.signature_scheme(), Ok($scheme));
521 }
522 };
523 }
524
525 check_cert! {ed448, "./test_assets/ed448.der", rustls::SignatureScheme::ED448}
526 check_cert! {ed25519, "./test_assets/ed25519.der", rustls::SignatureScheme::ED25519}
527 check_cert! {rsa_pkcs1_sha256, "./test_assets/rsa_pkcs1_sha256.der", rustls::SignatureScheme::RSA_PKCS1_SHA256}
528 check_cert! {rsa_pkcs1_sha384, "./test_assets/rsa_pkcs1_sha384.der", rustls::SignatureScheme::RSA_PKCS1_SHA384}
529 check_cert! {rsa_pkcs1_sha512, "./test_assets/rsa_pkcs1_sha512.der", rustls::SignatureScheme::RSA_PKCS1_SHA512}
530 check_cert! {nistp256_sha256, "./test_assets/nistp256_sha256.der", rustls::SignatureScheme::ECDSA_NISTP256_SHA256}
531 check_cert! {nistp384_sha384, "./test_assets/nistp384_sha384.der", rustls::SignatureScheme::ECDSA_NISTP384_SHA384}
532 check_cert! {nistp521_sha512, "./test_assets/nistp521_sha512.der", rustls::SignatureScheme::ECDSA_NISTP521_SHA512}
533
534 #[test]
535 fn rsa_pss_sha384() {
536 let cert = rustls::pki_types::CertificateDer::from(
537 include_bytes!("./test_assets/rsa_pss_sha384.der").to_vec(),
538 );
539
540 let cert = parse(&cert).unwrap();
541
542 assert_eq!(
543 cert.signature_scheme(),
544 Ok(rustls::SignatureScheme::RSA_PSS_SHA384)
545 );
546 }
547
548 #[test]
549 fn nistp384_sha256() {
550 let cert: &[u8] = include_bytes!("./test_assets/nistp384_sha256.der");
551
552 let cert = parse_unverified(cert).unwrap();
553
554 assert!(cert.signature_scheme().is_err());
555 }
556
557 #[test]
558 fn can_parse_certificate_with_ed25519_keypair() {
559 let certificate = rustls::pki_types::CertificateDer::from(hex!("308201773082011ea003020102020900f5bd0debaa597f52300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d030107034200046bf9871220d71dcb3483ecdfcbfcc7c103f8509d0974b3c18ab1f1be1302d643103a08f7a7722c1b247ba3876fe2c59e26526f479d7718a85202ddbe47562358a37f307d307b060a2b0601040183a25a01010101ff046a30680424080112207fda21856709c5ae12fd6e8450623f15f11955d384212b89f56e7e136d2e17280440aaa6bffabe91b6f30c35e3aa4f94b1188fed96b0ffdd393f4c58c1c047854120e674ce64c788406d1c2c4b116581fd7411b309881c3c7f20b46e54c7e6fe7f0f300a06082a8648ce3d040302034700304402207d1a1dbd2bda235ff2ec87daf006f9b04ba076a5a5530180cd9c2e8f6399e09d0220458527178c7e77024601dbb1b256593e9b96d961b96349d1f560114f61a87595").to_vec());
560
561 let peer_id = parse(&certificate).unwrap().peer_id();
562
563 assert_eq!(
564 "12D3KooWJRSrypvnpHgc6ZAgyCni4KcSmbV7uGRaMw5LgMKT18fq"
565 .parse::<PeerId>()
566 .unwrap(),
567 peer_id
568 );
569 }
570
571 #[test]
572 fn fails_to_parse_bad_certificate_with_ed25519_keypair() {
573 let certificate = rustls::pki_types::CertificateDer::from(hex!("308201773082011da003020102020830a73c5d896a1109300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d03010703420004bbe62df9a7c1c46b7f1f21d556deec5382a36df146fb29c7f1240e60d7d5328570e3b71d99602b77a65c9b3655f62837f8d66b59f1763b8c9beba3be07778043a37f307d307b060a2b0601040183a25a01010101ff046a3068042408011220ec8094573afb9728088860864f7bcea2d4fd412fef09a8e2d24d482377c20db60440ecabae8354afa2f0af4b8d2ad871e865cb5a7c0c8d3dbdbf42de577f92461a0ebb0a28703e33581af7d2a4f2270fc37aec6261fcc95f8af08f3f4806581c730a300a06082a8648ce3d040302034800304502202dfb17a6fa0f94ee0e2e6a3b9fb6e986f311dee27392058016464bd130930a61022100ba4b937a11c8d3172b81e7cd04aedb79b978c4379c2b5b24d565dd5d67d3cb3c").to_vec());
574
575 let error = parse(&certificate).unwrap_err();
576
577 assert_eq!(format!("{error}"), "UnknownIssuer");
578 }
579
580 #[test]
581 fn can_parse_certificate_with_ecdsa_keypair() {
582 let certificate = rustls::pki_types::CertificateDer::from(hex!("308201c030820166a003020102020900eaf419a6e3edb4a6300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d030107034200048dbf1116c7c608d6d5292bd826c3feb53483a89fce434bf64538a359c8e07538ff71f6766239be6a146dcc1a5f3bb934bcd4ae2ae1d4da28ac68b4a20593f06ba381c63081c33081c0060a2b0601040183a25a01010101ff0481ae3081ab045f0803125b3059301306072a8648ce3d020106082a8648ce3d0301070342000484b93fa456a74bd0153919f036db7bc63c802f055bc7023395d0203de718ee0fc7b570b767cdd858aca6c7c4113ff002e78bd2138ac1a3b26dde3519e06979ad04483046022100bc84014cea5a41feabdf4c161096564b9ccf4b62fbef4fe1cd382c84e11101780221009204f086a84cb8ed8a9ddd7868dc90c792ee434adf62c66f99a08a5eba11615b300a06082a8648ce3d0403020348003045022054b437be9a2edf591312d68ff24bf91367ad4143f76cf80b5658f232ade820da022100e23b48de9df9c25d4c83ddddf75d2676f0b9318ee2a6c88a736d85eab94a912f").to_vec());
583
584 let peer_id = parse(&certificate).unwrap().peer_id();
585
586 assert_eq!(
587 "QmZcrvr3r4S3QvwFdae3c2EWTfo792Y14UpzCZurhmiWeX"
588 .parse::<PeerId>()
589 .unwrap(),
590 peer_id
591 );
592 }
593
594 #[test]
595 fn can_parse_certificate_with_secp256k1_keypair() {
596 let certificate = rustls::pki_types::CertificateDer::from(hex!("3082018230820128a003020102020900f3b305f55622cfdf300a06082a8648ce3d04030230003020170d3735303130313030303030305a180f34303936303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d0301070342000458f7e9581748ff9bdd933b655cc0e5552a1248f840658cc221dec2186b5a2fe4641b86ab7590a3422cdbb1000cf97662f27e5910d7569f22feed8829c8b52e0fa38188308185308182060a2b0601040183a25a01010101ff0471306f042508021221026b053094d1112bce799dc8026040ae6d4eb574157929f1598172061f753d9b1b04463044022040712707e97794c478d93989aaa28ae1f71c03af524a8a4bd2d98424948a782302207b61b7f074b696a25fb9e0059141a811cccc4cc28042d9301b9b2a4015e87470300a06082a8648ce3d04030203480030450220143ae4d86fdc8675d2480bb6912eca5e39165df7f572d836aa2f2d6acfab13f8022100831d1979a98f0c4a6fb5069ca374de92f1a1205c962a6d90ad3d7554cb7d9df4").to_vec());
597
598 let peer_id = parse(&certificate).unwrap().peer_id();
599
600 assert_eq!(
601 "16Uiu2HAm2dSCBFxuge46aEt7U1oejtYuBUZXxASHqmcfVmk4gsbx"
602 .parse::<PeerId>()
603 .unwrap(),
604 peer_id
605 );
606 }
607}