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
25struct 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
127struct crypto_private_key *
128pkcs8_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