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