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
19struct 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
121struct crypto_private_key *
122pkcs8_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