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}