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