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