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