solana_tls_utils/tls_certificates.rs
1use {
2 solana_keypair::Keypair,
3 solana_pubkey::Pubkey,
4 solana_signer::Signer,
5 x509_parser::{prelude::*, public_key::PublicKey},
6};
7
8pub fn new_dummy_x509_certificate(
9 keypair: &Keypair,
10) -> (
11 rustls::pki_types::CertificateDer<'static>,
12 rustls::pki_types::PrivateKeyDer<'static>,
13) {
14 // Unfortunately, rustls does not accept a "raw" Ed25519 key.
15 // We have to convert it to DER and pass it to the library.
16
17 // Convert private key into PKCS#8 v1 object.
18 // RFC 8410, Section 7: Private Key Format
19 // https://www.rfc-editor.org/rfc/rfc8410#section-7
20 //
21 // The hardcoded prefix decodes to the following ASN.1 structure:
22 //
23 // PrivateKeyInfo SEQUENCE (3 elem)
24 // version Version INTEGER 0
25 // privateKeyAlgorithm AlgorithmIdentifier SEQUENCE (1 elem)
26 // algorithm OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm)
27 // privateKey PrivateKey OCTET STRING (34 byte)
28 const PKCS8_PREFIX: [u8; 16] = [
29 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04,
30 0x20,
31 ];
32
33 let key_pkcs8_der = {
34 let keypair_secret_bytes = keypair.secret().as_bytes();
35 let keypair_secret_len = keypair_secret_bytes.len();
36 if keypair_secret_len != 32 {
37 panic!("Unexpected secret key length!");
38 }
39 let buffer_size = PKCS8_PREFIX
40 .len()
41 .checked_add(keypair_secret_len) //clippy being overly guarded here but optimizer will elide checked_add
42 .expect("Unexpected secret key length!");
43 let mut key_pkcs8_der = Vec::<u8>::with_capacity(buffer_size);
44 key_pkcs8_der.extend_from_slice(&PKCS8_PREFIX);
45 key_pkcs8_der.extend_from_slice(keypair_secret_bytes);
46 key_pkcs8_der
47 };
48
49 // Create a dummy certificate. Only the SubjectPublicKeyInfo field
50 // is relevant to the peer-to-peer protocols. The signature of the
51 // X.509 certificate is deliberately invalid. (Peer authenticity is
52 // checked in the TLS 1.3 CertificateVerify)
53 // See https://www.itu.int/rec/T-REC-X.509-201910-I/en for detailed definitions.
54
55 let mut cert_der = Vec::<u8>::with_capacity(0xf4);
56 // Certificate SEQUENCE (3 elem)
57 // tbsCertificate TBSCertificate SEQUENCE (8 elem)
58 // version [0] (1 elem)
59 // INTEGER 2
60 // serialNumber CertificateSerialNumber INTEGER (62 bit)
61 // signature AlgorithmIdentifier SEQUENCE (1 elem)
62 // algorithm OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm)
63 // issuer Name SEQUENCE (1 elem)
64 // RelativeDistinguishedName SET (1 elem)
65 // AttributeTypeAndValue SEQUENCE (2 elem)
66 // type AttributeType OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component)
67 // value AttributeValue [?] UTF8String Solana
68 // validity Validity SEQUENCE (2 elem)
69 // notBefore Time UTCTime 1970-01-01 00:00:00 UTC
70 // notAfter Time GeneralizedTime 4096-01-01 00:00:00 UTC
71 // subject Name SEQUENCE (0 elem)
72 // subjectPublicKeyInfo SubjectPublicKeyInfo SEQUENCE (2 elem)
73 // algorithm AlgorithmIdentifier SEQUENCE (1 elem)
74 // algorithm OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm)
75 // subjectPublicKey BIT STRING (256 bit)
76 cert_der.extend_from_slice(&[
77 0x30, 0x81, 0xf6, 0x30, 0x81, 0xa9, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x01, 0x01,
78 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x30, 0x16,
79 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0b, 0x53, 0x6f, 0x6c, 0x61,
80 0x6e, 0x61, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x30, 0x20, 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31,
81 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x34, 0x30, 0x39, 0x36,
82 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x00, 0x30, 0x2a,
83 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
84 ]);
85 cert_der.extend_from_slice(&keypair.pubkey().to_bytes());
86 // extensions [3] (1 elem)
87 // Extensions SEQUENCE (2 elem)
88 // Extension SEQUENCE (3 elem)
89 // extnID OBJECT IDENTIFIER 2.5.29.17 subjectAltName (X.509 extension)
90 // critical BOOLEAN true
91 // extnValue OCTET STRING (13 byte) encapsulating
92 // SEQUENCE (1 elem)
93 // [2] (9 byte) localhost
94 // Extension SEQUENCE (3 elem)
95 // extnID OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension)
96 // critical BOOLEAN true
97 // extnValue OCTET STRING (2 byte) encapsulating
98 // SEQUENCE (0 elem)
99 // signatureAlgorithm AlgorithmIdentifier SEQUENCE (1 elem)
100 // algorithm OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm)
101 // signature BIT STRING (512 bit)
102 cert_der.extend_from_slice(&[
103 0xa3, 0x29, 0x30, 0x27, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01, 0xff, 0x04,
104 0x0d, 0x30, 0x0b, 0x82, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x30,
105 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x05,
106 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x41, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
109 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
111 ]);
112
113 (
114 rustls::pki_types::CertificateDer::from(cert_der),
115 rustls::pki_types::PrivateKeyDer::try_from(key_pkcs8_der).unwrap(),
116 )
117}
118
119pub fn get_pubkey_from_tls_certificate(
120 der_cert: &rustls::pki_types::CertificateDer,
121) -> Option<Pubkey> {
122 let (_, cert) = X509Certificate::from_der(der_cert.as_ref()).ok()?;
123 match cert.public_key().parsed().ok()? {
124 PublicKey::Unknown(key) => Pubkey::try_from(key).ok(),
125 _ => None,
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use {super::*, solana_signer::Signer};
132
133 #[test]
134 fn test_generate_tls_certificate() {
135 let keypair = Keypair::new();
136 let (cert, _) = new_dummy_x509_certificate(&keypair);
137 if let Some(pubkey) = get_pubkey_from_tls_certificate(&cert) {
138 assert_eq!(pubkey, keypair.pubkey());
139 } else {
140 panic!("Failed to get certificate pubkey");
141 }
142 }
143}