xref: /aosp_15_r20/external/wpa_supplicant_8/src/tls/pkcs8.c (revision 03f9172ca588f91df233974f4258bab95191f931)
1*03f9172cSAndroid Build Coastguard Worker /*
2*03f9172cSAndroid Build Coastguard Worker  * PKCS #8 (Private-key information syntax)
3*03f9172cSAndroid Build Coastguard Worker  * Copyright (c) 2006-2009, Jouni Malinen <[email protected]>
4*03f9172cSAndroid Build Coastguard Worker  *
5*03f9172cSAndroid Build Coastguard Worker  * This software may be distributed under the terms of the BSD license.
6*03f9172cSAndroid Build Coastguard Worker  * See README for more details.
7*03f9172cSAndroid Build Coastguard Worker  */
8*03f9172cSAndroid Build Coastguard Worker 
9*03f9172cSAndroid Build Coastguard Worker #include "includes.h"
10*03f9172cSAndroid Build Coastguard Worker 
11*03f9172cSAndroid Build Coastguard Worker #include "common.h"
12*03f9172cSAndroid Build Coastguard Worker #include "asn1.h"
13*03f9172cSAndroid Build Coastguard Worker #include "bignum.h"
14*03f9172cSAndroid Build Coastguard Worker #include "rsa.h"
15*03f9172cSAndroid Build Coastguard Worker #include "pkcs5.h"
16*03f9172cSAndroid Build Coastguard Worker #include "pkcs8.h"
17*03f9172cSAndroid Build Coastguard Worker 
18*03f9172cSAndroid Build Coastguard Worker 
pkcs8_key_import(const u8 * buf,size_t len)19*03f9172cSAndroid Build Coastguard Worker struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
20*03f9172cSAndroid Build Coastguard Worker {
21*03f9172cSAndroid Build Coastguard Worker 	struct asn1_hdr hdr;
22*03f9172cSAndroid Build Coastguard Worker 	const u8 *pos, *end;
23*03f9172cSAndroid Build Coastguard Worker 	struct bignum *zero;
24*03f9172cSAndroid Build Coastguard Worker 	struct asn1_oid oid;
25*03f9172cSAndroid Build Coastguard Worker 	char obuf[80];
26*03f9172cSAndroid Build Coastguard Worker 
27*03f9172cSAndroid Build Coastguard Worker 	/* PKCS #8, Chapter 6 */
28*03f9172cSAndroid Build Coastguard Worker 
29*03f9172cSAndroid Build Coastguard Worker 	/* PrivateKeyInfo ::= SEQUENCE */
30*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
31*03f9172cSAndroid Build Coastguard Worker 		asn1_unexpected(&hdr,
32*03f9172cSAndroid Build Coastguard Worker 				"PKCS #8: Does not start with PKCS #8 header (SEQUENCE)");
33*03f9172cSAndroid Build Coastguard Worker 		return NULL;
34*03f9172cSAndroid Build Coastguard Worker 	}
35*03f9172cSAndroid Build Coastguard Worker 	pos = hdr.payload;
36*03f9172cSAndroid Build Coastguard Worker 	end = pos + hdr.length;
37*03f9172cSAndroid Build Coastguard Worker 
38*03f9172cSAndroid Build Coastguard Worker 	/* version Version (Version ::= INTEGER) */
39*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_integer(&hdr)) {
40*03f9172cSAndroid Build Coastguard Worker 		asn1_unexpected(&hdr, "PKCS #8: Expected INTEGER");
41*03f9172cSAndroid Build Coastguard Worker 		return NULL;
42*03f9172cSAndroid Build Coastguard Worker 	}
43*03f9172cSAndroid Build Coastguard Worker 
44*03f9172cSAndroid Build Coastguard Worker 	zero = bignum_init();
45*03f9172cSAndroid Build Coastguard Worker 	if (zero == NULL)
46*03f9172cSAndroid Build Coastguard Worker 		return NULL;
47*03f9172cSAndroid Build Coastguard Worker 
48*03f9172cSAndroid Build Coastguard Worker 	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
49*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
50*03f9172cSAndroid Build Coastguard Worker 		bignum_deinit(zero);
51*03f9172cSAndroid Build Coastguard Worker 		return NULL;
52*03f9172cSAndroid Build Coastguard Worker 	}
53*03f9172cSAndroid Build Coastguard Worker 	pos = hdr.payload + hdr.length;
54*03f9172cSAndroid Build Coastguard Worker 
55*03f9172cSAndroid Build Coastguard Worker 	if (bignum_cmp_d(zero, 0) != 0) {
56*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
57*03f9172cSAndroid Build Coastguard Worker 			   "beginning of private key; not found; assume "
58*03f9172cSAndroid Build Coastguard Worker 			   "PKCS #8 not used");
59*03f9172cSAndroid Build Coastguard Worker 		bignum_deinit(zero);
60*03f9172cSAndroid Build Coastguard Worker 		return NULL;
61*03f9172cSAndroid Build Coastguard Worker 	}
62*03f9172cSAndroid Build Coastguard Worker 	bignum_deinit(zero);
63*03f9172cSAndroid Build Coastguard Worker 
64*03f9172cSAndroid Build Coastguard Worker 	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
65*03f9172cSAndroid Build Coastguard Worker 	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
66*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_next(pos, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
67*03f9172cSAndroid Build Coastguard Worker 		asn1_unexpected(&hdr,
68*03f9172cSAndroid Build Coastguard Worker 				"PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume PKCS #8 not used");
69*03f9172cSAndroid Build Coastguard Worker 		return NULL;
70*03f9172cSAndroid Build Coastguard Worker 	}
71*03f9172cSAndroid Build Coastguard Worker 
72*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
73*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
74*03f9172cSAndroid Build Coastguard Worker 			   "(algorithm); assume PKCS #8 not used");
75*03f9172cSAndroid Build Coastguard Worker 		return NULL;
76*03f9172cSAndroid Build Coastguard Worker 	}
77*03f9172cSAndroid Build Coastguard Worker 
78*03f9172cSAndroid Build Coastguard Worker 	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
79*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
80*03f9172cSAndroid Build Coastguard Worker 
81*03f9172cSAndroid Build Coastguard Worker 	if (oid.len != 7 ||
82*03f9172cSAndroid Build Coastguard Worker 	    oid.oid[0] != 1 /* iso */ ||
83*03f9172cSAndroid Build Coastguard Worker 	    oid.oid[1] != 2 /* member-body */ ||
84*03f9172cSAndroid Build Coastguard Worker 	    oid.oid[2] != 840 /* us */ ||
85*03f9172cSAndroid Build Coastguard Worker 	    oid.oid[3] != 113549 /* rsadsi */ ||
86*03f9172cSAndroid Build Coastguard Worker 	    oid.oid[4] != 1 /* pkcs */ ||
87*03f9172cSAndroid Build Coastguard Worker 	    oid.oid[5] != 1 /* pkcs-1 */ ||
88*03f9172cSAndroid Build Coastguard Worker 	    oid.oid[6] != 1 /* rsaEncryption */) {
89*03f9172cSAndroid Build Coastguard Worker 		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
90*03f9172cSAndroid Build Coastguard Worker 			   "algorithm %s", obuf);
91*03f9172cSAndroid Build Coastguard Worker 		return NULL;
92*03f9172cSAndroid Build Coastguard Worker 	}
93*03f9172cSAndroid Build Coastguard Worker 
94*03f9172cSAndroid Build Coastguard Worker 	pos = hdr.payload + hdr.length;
95*03f9172cSAndroid Build Coastguard Worker 
96*03f9172cSAndroid Build Coastguard Worker 	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
97*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
98*03f9172cSAndroid Build Coastguard Worker 	    !asn1_is_octetstring(&hdr)) {
99*03f9172cSAndroid Build Coastguard Worker 		asn1_unexpected(&hdr,
100*03f9172cSAndroid Build Coastguard Worker 				"PKCS #8: Expected OCTETSTRING (privateKey)");
101*03f9172cSAndroid Build Coastguard Worker 		return NULL;
102*03f9172cSAndroid Build Coastguard Worker 	}
103*03f9172cSAndroid Build Coastguard Worker 	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
104*03f9172cSAndroid Build Coastguard Worker 
105*03f9172cSAndroid Build Coastguard Worker 	return (struct crypto_private_key *)
106*03f9172cSAndroid Build Coastguard Worker 		crypto_rsa_import_private_key(hdr.payload, hdr.length);
107*03f9172cSAndroid Build Coastguard Worker }
108*03f9172cSAndroid Build Coastguard Worker 
109*03f9172cSAndroid Build Coastguard Worker 
110*03f9172cSAndroid Build Coastguard Worker struct crypto_private_key *
pkcs8_enc_key_import(const u8 * buf,size_t len,const char * passwd)111*03f9172cSAndroid Build Coastguard Worker pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
112*03f9172cSAndroid Build Coastguard Worker {
113*03f9172cSAndroid Build Coastguard Worker 	struct asn1_hdr hdr;
114*03f9172cSAndroid Build Coastguard Worker 	const u8 *pos, *end, *enc_alg;
115*03f9172cSAndroid Build Coastguard Worker 	size_t enc_alg_len;
116*03f9172cSAndroid Build Coastguard Worker 	u8 *data;
117*03f9172cSAndroid Build Coastguard Worker 	size_t data_len;
118*03f9172cSAndroid Build Coastguard Worker 
119*03f9172cSAndroid Build Coastguard Worker 	if (passwd == NULL)
120*03f9172cSAndroid Build Coastguard Worker 		return NULL;
121*03f9172cSAndroid Build Coastguard Worker 
122*03f9172cSAndroid Build Coastguard Worker 	/*
123*03f9172cSAndroid Build Coastguard Worker 	 * PKCS #8, Chapter 7
124*03f9172cSAndroid Build Coastguard Worker 	 * EncryptedPrivateKeyInfo ::= SEQUENCE {
125*03f9172cSAndroid Build Coastguard Worker 	 *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
126*03f9172cSAndroid Build Coastguard Worker 	 *   encryptedData EncryptedData }
127*03f9172cSAndroid Build Coastguard Worker 	 * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
128*03f9172cSAndroid Build Coastguard Worker 	 * EncryptedData ::= OCTET STRING
129*03f9172cSAndroid Build Coastguard Worker 	 */
130*03f9172cSAndroid Build Coastguard Worker 
131*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_next(buf, len, &hdr) < 0 || !asn1_is_sequence(&hdr)) {
132*03f9172cSAndroid Build Coastguard Worker 		asn1_unexpected(&hdr,
133*03f9172cSAndroid Build Coastguard Worker 				"PKCS #8: Does not start with PKCS #8 header (SEQUENCE); assume encrypted PKCS #8 not used");
134*03f9172cSAndroid Build Coastguard Worker 		return NULL;
135*03f9172cSAndroid Build Coastguard Worker 	}
136*03f9172cSAndroid Build Coastguard Worker 	pos = hdr.payload;
137*03f9172cSAndroid Build Coastguard Worker 	end = pos + hdr.length;
138*03f9172cSAndroid Build Coastguard Worker 
139*03f9172cSAndroid Build Coastguard Worker 	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
140*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
141*03f9172cSAndroid Build Coastguard Worker 	    !asn1_is_sequence(&hdr)) {
142*03f9172cSAndroid Build Coastguard Worker 		asn1_unexpected(&hdr,
143*03f9172cSAndroid Build Coastguard Worker 				"PKCS #8: Expected SEQUENCE (AlgorithmIdentifier); assume encrypted PKCS #8 not used");
144*03f9172cSAndroid Build Coastguard Worker 		return NULL;
145*03f9172cSAndroid Build Coastguard Worker 	}
146*03f9172cSAndroid Build Coastguard Worker 	enc_alg = hdr.payload;
147*03f9172cSAndroid Build Coastguard Worker 	enc_alg_len = hdr.length;
148*03f9172cSAndroid Build Coastguard Worker 	pos = hdr.payload + hdr.length;
149*03f9172cSAndroid Build Coastguard Worker 
150*03f9172cSAndroid Build Coastguard Worker 	/* encryptedData EncryptedData */
151*03f9172cSAndroid Build Coastguard Worker 	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
152*03f9172cSAndroid Build Coastguard Worker 	    !asn1_is_octetstring(&hdr)) {
153*03f9172cSAndroid Build Coastguard Worker 		asn1_unexpected(&hdr,
154*03f9172cSAndroid Build Coastguard Worker 				"PKCS #8: Expected OCTETSTRING (encryptedData)");
155*03f9172cSAndroid Build Coastguard Worker 		return NULL;
156*03f9172cSAndroid Build Coastguard Worker 	}
157*03f9172cSAndroid Build Coastguard Worker 
158*03f9172cSAndroid Build Coastguard Worker 	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
159*03f9172cSAndroid Build Coastguard Worker 			     passwd, &data_len);
160*03f9172cSAndroid Build Coastguard Worker 	if (data) {
161*03f9172cSAndroid Build Coastguard Worker 		struct crypto_private_key *key;
162*03f9172cSAndroid Build Coastguard Worker 		key = pkcs8_key_import(data, data_len);
163*03f9172cSAndroid Build Coastguard Worker 		os_free(data);
164*03f9172cSAndroid Build Coastguard Worker 		return key;
165*03f9172cSAndroid Build Coastguard Worker 	}
166*03f9172cSAndroid Build Coastguard Worker 
167*03f9172cSAndroid Build Coastguard Worker 	return NULL;
168*03f9172cSAndroid Build Coastguard Worker }
169