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