Skip to main content

crypto/encoding/
pkcs8.rs

1use crate::p256::{PRIVATE_KEY_SIZE, PUBLIC_KEY_UNCOMPRESSED_SIZE, PrivateKey};
2
3const PKCS8_DER_LEN: usize = 138;
4
5const EC_PUBLIC_KEY_OID: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
6const SECP256R1_OID: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Pkcs8Error {
10    InvalidLength,
11    InvalidSequence,
12    InvalidVersion,
13    InvalidAlgorithmIdentifier,
14    InvalidOctetString,
15    InvalidEcPrivateKey,
16    InvalidEcVersion,
17    InvalidPrivateKeyOctet,
18    InvalidPublicKeyExplicit,
19    InvalidPublicKeyBitString,
20    InvalidPublicKeyPrefix,
21    KeyDerivationFailed,
22}
23
24#[cfg(feature = "alloc")]
25impl core::fmt::Display for Pkcs8Error {
26    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
27        match self {
28            Pkcs8Error::InvalidLength => write!(f, "invalid DER length"),
29            Pkcs8Error::InvalidSequence => write!(f, "invalid outer SEQUENCE"),
30            Pkcs8Error::InvalidVersion => write!(f, "invalid version"),
31            Pkcs8Error::InvalidAlgorithmIdentifier => write!(f, "invalid AlgorithmIdentifier"),
32            Pkcs8Error::InvalidOctetString => write!(f, "invalid OCTET STRING wrapping"),
33            Pkcs8Error::InvalidEcPrivateKey => write!(f, "invalid ECPrivateKey SEQUENCE"),
34            Pkcs8Error::InvalidEcVersion => write!(f, "invalid EC version"),
35            Pkcs8Error::InvalidPrivateKeyOctet => write!(f, "invalid private key OCTET STRING"),
36            Pkcs8Error::InvalidPublicKeyExplicit => write!(f, "invalid public key [1] EXPLICIT"),
37            Pkcs8Error::InvalidPublicKeyBitString => write!(f, "invalid public key BIT STRING"),
38            Pkcs8Error::InvalidPublicKeyPrefix => write!(f, "invalid public key prefix"),
39            Pkcs8Error::KeyDerivationFailed => write!(f, "key derivation failed"),
40        }
41    }
42}
43
44fn validate_fixed_prefix(der: &[u8]) -> Result<(), Pkcs8Error> {
45    if der.len() != PKCS8_DER_LEN {
46        return Err(Pkcs8Error::InvalidLength);
47    }
48
49    // Outer SEQUENCE: 30 81 87
50    if der[0] != 0x30 || der[1] != 0x81 || der[2] != 0x87 {
51        return Err(Pkcs8Error::InvalidSequence);
52    }
53    // INTEGER version=0: 02 01 00
54    if der[3] != 0x02 || der[4] != 0x01 || der[5] != 0x00 {
55        return Err(Pkcs8Error::InvalidVersion);
56    }
57    // AlgorithmIdentifier SEQUENCE: 30 13
58    if der[6] != 0x30 || der[7] != 0x13 {
59        return Err(Pkcs8Error::InvalidAlgorithmIdentifier);
60    }
61    // ecPublicKey OID: 06 07 <7 bytes>
62    if der[8] != 0x06 || der[9] != 0x07 || der[10..17] != *EC_PUBLIC_KEY_OID {
63        return Err(Pkcs8Error::InvalidAlgorithmIdentifier);
64    }
65    // secp256r1 OID: 06 08 <8 bytes>
66    if der[17] != 0x06 || der[18] != 0x08 || der[19..27] != *SECP256R1_OID {
67        return Err(Pkcs8Error::InvalidAlgorithmIdentifier);
68    }
69    // OCTET STRING: 04 6d (109 bytes)
70    if der[27] != 0x04 || der[28] != 0x6d {
71        return Err(Pkcs8Error::InvalidOctetString);
72    }
73    // ECPrivateKey SEQUENCE: 30 6b
74    if der[29] != 0x30 || der[30] != 0x6b {
75        return Err(Pkcs8Error::InvalidEcPrivateKey);
76    }
77    // EC version: 02 01 01
78    if der[31] != 0x02 || der[32] != 0x01 || der[33] != 0x01 {
79        return Err(Pkcs8Error::InvalidEcVersion);
80    }
81    // private key OCTET STRING: 04 20
82    if der[34] != 0x04 || der[35] != 0x20 {
83        return Err(Pkcs8Error::InvalidPrivateKeyOctet);
84    }
85    // [1] EXPLICIT: a1 44
86    if der[68] != 0xa1 || der[69] != 0x44 {
87        return Err(Pkcs8Error::InvalidPublicKeyExplicit);
88    }
89    // BIT STRING: 03 42 00
90    if der[70] != 0x03 || der[71] != 0x42 || der[72] != 0x00 {
91        return Err(Pkcs8Error::InvalidPublicKeyBitString);
92    }
93    // public key must start with 0x04 (uncompressed)
94    if der[73] != 0x04 {
95        return Err(Pkcs8Error::InvalidPublicKeyPrefix);
96    }
97
98    Ok(())
99}
100
101static TEMPLATE: [u8; PKCS8_DER_LEN] = [
102    // PrivateKeyInfo SEQUENCE (135 bytes content)
103    0x30, 0x81, 0x87, // version INTEGER 0
104    0x02, 0x01, 0x00, // AlgorithmIdentifier SEQUENCE (19 bytes)
105    0x30, 0x13, // ecPublicKey OID (1.2.840.10045.2.1)
106    0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // secp256r1 OID (1.2.840.10045.3.1.7)
107    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
108    // OCTET STRING wrapping ECPrivateKey (109 bytes)
109    0x04, 0x6d, // ECPrivateKey SEQUENCE (107 bytes)
110    0x30, 0x6b, // EC version INTEGER 1
111    0x02, 0x01, 0x01, // private key OCTET STRING (32 bytes) -- placeholder zeros
112    0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114    // [1] EXPLICIT public key wrapper (68 bytes)
115    0xa1, 0x44, // BIT STRING with unused_bits=0, length=66 (65 bytes data + 1 byte unused_bits)
116    0x03, 0x42, 0x00,
117    // uncompressed public key (65 bytes = 0x04 || 32-byte X || 32-byte Y) -- placeholder zeros
118    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122];
123
124const PRIVATE_KEY_OFFSET: usize = 36;
125const PUBLIC_KEY_OFFSET: usize = 73;
126
127pub fn encode_p256_pkcs8_der(key: &PrivateKey) -> Result<[u8; PKCS8_DER_LEN], Pkcs8Error> {
128    let public_key = key.public_key();
129    let pub_bytes = public_key.to_bytes();
130    let priv_bytes = key.to_bytes();
131
132    let mut der = TEMPLATE;
133    der[PUBLIC_KEY_OFFSET..PUBLIC_KEY_OFFSET + PUBLIC_KEY_UNCOMPRESSED_SIZE].copy_from_slice(&pub_bytes);
134    der[PRIVATE_KEY_OFFSET..PRIVATE_KEY_OFFSET + PRIVATE_KEY_SIZE].copy_from_slice(&priv_bytes);
135
136    Ok(der)
137}
138
139pub fn decode_p256_pkcs8_der(der: &[u8]) -> Result<PrivateKey, Pkcs8Error> {
140    validate_fixed_prefix(der)?;
141
142    let mut private_key = [0u8; PRIVATE_KEY_SIZE];
143    private_key.copy_from_slice(&der[PRIVATE_KEY_OFFSET..PRIVATE_KEY_OFFSET + PRIVATE_KEY_SIZE]);
144
145    let mut public_key = [0u8; PUBLIC_KEY_UNCOMPRESSED_SIZE];
146    public_key.copy_from_slice(&der[PUBLIC_KEY_OFFSET..PUBLIC_KEY_OFFSET + PUBLIC_KEY_UNCOMPRESSED_SIZE]);
147
148    PrivateKey::from_bytes(&private_key).map_err(|_| Pkcs8Error::KeyDerivationFailed)
149}
150
151#[cfg(test)]
152mod tests {
153    use super::*;
154
155    // Known test vector from acme crate:
156    // Private key: 255582fd0cce4c24b9bedb09a76206f940dcf1c7437dea0ab71499c5ace733e9
157    // Public key:  041e9c23e81a03c54dd3c9ed52cb2ade7a4713e5613d703579c7739e0f132060dcbc4a687d3eb09917d262fc2f23c476c7cbfcecf84f11e458b246ad756d3617c7
158    const TEST_PRIVATE_KEY: [u8; 32] = [
159        0x25, 0x55, 0x82, 0xfd, 0x0c, 0xce, 0x4c, 0x24, 0xb9, 0xbe, 0xdb, 0x09, 0xa7, 0x62, 0x06, 0xf9, 0x40, 0xdc,
160        0xf1, 0xc7, 0x43, 0x7d, 0xea, 0x0a, 0xb7, 0x14, 0x99, 0xc5, 0xac, 0xe7, 0x33, 0xe9,
161    ];
162
163    const TEST_PUBLIC_KEY: [u8; 65] = [
164        0x04, 0x1e, 0x9c, 0x23, 0xe8, 0x1a, 0x03, 0xc5, 0x4d, 0xd3, 0xc9, 0xed, 0x52, 0xcb, 0x2a, 0xde, 0x7a, 0x47,
165        0x13, 0xe5, 0x61, 0x3d, 0x70, 0x35, 0x79, 0xc7, 0x73, 0x9e, 0x0f, 0x13, 0x20, 0x60, 0xdc, 0xbc, 0x4a, 0x68,
166        0x7d, 0x3e, 0xb0, 0x99, 0x17, 0xd2, 0x62, 0xfc, 0x2f, 0x23, 0xc4, 0x76, 0xc7, 0xcb, 0xfc, 0xec, 0xf8, 0x4f,
167        0x11, 0xe4, 0x58, 0xb2, 0x46, 0xad, 0x75, 0x6d, 0x36, 0x17, 0xc7,
168    ];
169
170    fn decode_hex(hex_str: &str) -> Vec<u8> {
171        (0..hex_str.len())
172            .step_by(2)
173            .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16).unwrap())
174            .collect()
175    }
176
177    const TEST_DER_HEX: &str = "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420255582fd0cce4c24b9bedb09a76206f940dcf1c7437dea0ab71499c5ace733e9a144034200041e9c23e81a03c54dd3c9ed52cb2ade7a4713e5613d703579c7739e0f132060dcbc4a687d3eb09917d262fc2f23c476c7cbfcecf84f11e458b246ad756d3617c7";
178
179    #[test]
180    fn encode_round_trip() {
181        let key = PrivateKey::from_bytes(&TEST_PRIVATE_KEY).unwrap();
182        let der = encode_p256_pkcs8_der(&key).unwrap();
183        let decoded = decode_p256_pkcs8_der(&der).unwrap();
184        assert_eq!(decoded.to_bytes(), TEST_PRIVATE_KEY);
185        assert_eq!(decoded.public_key().to_bytes(), TEST_PUBLIC_KEY);
186    }
187
188    #[test]
189    fn decode_known_vector() {
190        let der_bytes = decode_hex(TEST_DER_HEX);
191        let key = decode_p256_pkcs8_der(&der_bytes).unwrap();
192        assert_eq!(key.to_bytes(), TEST_PRIVATE_KEY);
193        assert_eq!(key.public_key().to_bytes(), TEST_PUBLIC_KEY);
194    }
195
196    #[test]
197    fn encode_matches_known_der() {
198        let key = PrivateKey::from_bytes(&TEST_PRIVATE_KEY).unwrap();
199        let der = encode_p256_pkcs8_der(&key).unwrap();
200        let expected = decode_hex(TEST_DER_HEX);
201        assert_eq!(der.as_slice(), expected.as_slice());
202    }
203
204    #[test]
205    fn decode_too_short() {
206        assert_eq!(decode_p256_pkcs8_der(&[0u8; 100]), Err(Pkcs8Error::InvalidLength));
207    }
208
209    #[test]
210    fn decode_too_long() {
211        assert_eq!(decode_p256_pkcs8_der(&[0u8; 200]), Err(Pkcs8Error::InvalidLength));
212    }
213
214    #[test]
215    fn decode_bad_sequence() {
216        let mut der = decode_hex(TEST_DER_HEX);
217        der[0] = 0x31;
218        assert_eq!(decode_p256_pkcs8_der(&der), Err(Pkcs8Error::InvalidSequence));
219    }
220
221    #[test]
222    fn decode_bad_version() {
223        let mut der = decode_hex(TEST_DER_HEX);
224        der[5] = 0x01;
225        assert_eq!(decode_p256_pkcs8_der(&der), Err(Pkcs8Error::InvalidVersion));
226    }
227
228    #[test]
229    fn decode_bad_algo_identifier() {
230        let mut der = decode_hex(TEST_DER_HEX);
231        der[10] = 0x00;
232        assert_eq!(decode_p256_pkcs8_der(&der), Err(Pkcs8Error::InvalidAlgorithmIdentifier));
233    }
234
235    #[test]
236    fn decode_bad_ec_version() {
237        let mut der = decode_hex(TEST_DER_HEX);
238        der[33] = 0x02;
239        assert_eq!(decode_p256_pkcs8_der(&der), Err(Pkcs8Error::InvalidEcVersion));
240    }
241
242    #[test]
243    fn decode_missing_public_key() {
244        let mut der = decode_hex(TEST_DER_HEX);
245        der[68] = 0x00;
246        assert_eq!(decode_p256_pkcs8_der(&der), Err(Pkcs8Error::InvalidPublicKeyExplicit));
247    }
248
249    #[test]
250    fn decode_bad_public_key_prefix() {
251        let mut der = decode_hex(TEST_DER_HEX);
252        der[73] = 0x02;
253        assert_eq!(decode_p256_pkcs8_der(&der), Err(Pkcs8Error::InvalidPublicKeyPrefix));
254    }
255
256    #[test]
257    fn encode_round_trip_random_keys() {
258        for _ in 0..10 {
259            let priv_key: [u8; 32] = rand::random();
260            let key = match PrivateKey::from_bytes(&priv_key) {
261                Ok(k) => k,
262                Err(_) => continue,
263            };
264            let der = encode_p256_pkcs8_der(&key).unwrap();
265            let decoded = decode_p256_pkcs8_der(&der).unwrap();
266            assert_eq!(decoded.to_bytes(), key.to_bytes());
267            assert_eq!(decoded.public_key().to_bytes().len(), 65);
268            assert_eq!(decoded.public_key().to_bytes()[0], 0x04);
269        }
270    }
271
272    #[test]
273    fn encode_rejects_invalid_key() {
274        let invalid = [0u8; 32];
275        assert!(PrivateKey::from_bytes(&invalid).is_err());
276    }
277}