1214501Srpaulo/*
2214501Srpaulo * PKCS #8 (Private-key information syntax)
3214501Srpaulo * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5214501Srpaulo * This program is free software; you can redistribute it and/or modify
6214501Srpaulo * it under the terms of the GNU General Public License version 2 as
7214501Srpaulo * published by the Free Software Foundation.
8214501Srpaulo *
9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD
10214501Srpaulo * license.
11214501Srpaulo *
12214501Srpaulo * See README and COPYING for more details.
13214501Srpaulo */
14214501Srpaulo
15214501Srpaulo#include "includes.h"
16214501Srpaulo
17214501Srpaulo#include "common.h"
18214501Srpaulo#include "asn1.h"
19214501Srpaulo#include "bignum.h"
20214501Srpaulo#include "rsa.h"
21214501Srpaulo#include "pkcs5.h"
22214501Srpaulo#include "pkcs8.h"
23214501Srpaulo
24214501Srpaulo
25214501Srpaulostruct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
26214501Srpaulo{
27214501Srpaulo	struct asn1_hdr hdr;
28214501Srpaulo	const u8 *pos, *end;
29214501Srpaulo	struct bignum *zero;
30214501Srpaulo	struct asn1_oid oid;
31214501Srpaulo	char obuf[80];
32214501Srpaulo
33214501Srpaulo	/* PKCS #8, Chapter 6 */
34214501Srpaulo
35214501Srpaulo	/* PrivateKeyInfo ::= SEQUENCE */
36214501Srpaulo	if (asn1_get_next(buf, len, &hdr) < 0 ||
37214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
38214501Srpaulo	    hdr.tag != ASN1_TAG_SEQUENCE) {
39214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
40214501Srpaulo			   "header (SEQUENCE); assume PKCS #8 not used");
41214501Srpaulo		return NULL;
42214501Srpaulo	}
43214501Srpaulo	pos = hdr.payload;
44214501Srpaulo	end = pos + hdr.length;
45214501Srpaulo
46214501Srpaulo	/* version Version (Version ::= INTEGER) */
47214501Srpaulo	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
48214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
49214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
50214501Srpaulo			   "class %d tag 0x%x; assume PKCS #8 not used",
51214501Srpaulo			   hdr.class, hdr.tag);
52214501Srpaulo		return NULL;
53214501Srpaulo	}
54214501Srpaulo
55214501Srpaulo	zero = bignum_init();
56214501Srpaulo	if (zero == NULL)
57214501Srpaulo		return NULL;
58214501Srpaulo
59214501Srpaulo	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
60214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
61214501Srpaulo		bignum_deinit(zero);
62214501Srpaulo		return NULL;
63214501Srpaulo	}
64214501Srpaulo	pos = hdr.payload + hdr.length;
65214501Srpaulo
66214501Srpaulo	if (bignum_cmp_d(zero, 0) != 0) {
67214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
68214501Srpaulo			   "beginning of private key; not found; assume "
69214501Srpaulo			   "PKCS #8 not used");
70214501Srpaulo		bignum_deinit(zero);
71214501Srpaulo		return NULL;
72214501Srpaulo	}
73214501Srpaulo	bignum_deinit(zero);
74214501Srpaulo
75214501Srpaulo	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
76214501Srpaulo	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
77214501Srpaulo	if (asn1_get_next(pos, len, &hdr) < 0 ||
78214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
79214501Srpaulo	    hdr.tag != ASN1_TAG_SEQUENCE) {
80214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
81214501Srpaulo			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
82214501Srpaulo			   "assume PKCS #8 not used",
83214501Srpaulo			   hdr.class, hdr.tag);
84214501Srpaulo		return NULL;
85214501Srpaulo	}
86214501Srpaulo
87214501Srpaulo	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
88214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
89214501Srpaulo			   "(algorithm); assume PKCS #8 not used");
90214501Srpaulo		return NULL;
91214501Srpaulo	}
92214501Srpaulo
93214501Srpaulo	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
94214501Srpaulo	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
95214501Srpaulo
96214501Srpaulo	if (oid.len != 7 ||
97214501Srpaulo	    oid.oid[0] != 1 /* iso */ ||
98214501Srpaulo	    oid.oid[1] != 2 /* member-body */ ||
99214501Srpaulo	    oid.oid[2] != 840 /* us */ ||
100214501Srpaulo	    oid.oid[3] != 113549 /* rsadsi */ ||
101214501Srpaulo	    oid.oid[4] != 1 /* pkcs */ ||
102214501Srpaulo	    oid.oid[5] != 1 /* pkcs-1 */ ||
103214501Srpaulo	    oid.oid[6] != 1 /* rsaEncryption */) {
104214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
105214501Srpaulo			   "algorithm %s", obuf);
106214501Srpaulo		return NULL;
107214501Srpaulo	}
108214501Srpaulo
109214501Srpaulo	pos = hdr.payload + hdr.length;
110214501Srpaulo
111214501Srpaulo	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
112214501Srpaulo	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
113214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
114214501Srpaulo	    hdr.tag != ASN1_TAG_OCTETSTRING) {
115214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
116214501Srpaulo			   "(privateKey) - found class %d tag 0x%x",
117214501Srpaulo			   hdr.class, hdr.tag);
118214501Srpaulo		return NULL;
119214501Srpaulo	}
120214501Srpaulo	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
121214501Srpaulo
122214501Srpaulo	return (struct crypto_private_key *)
123214501Srpaulo		crypto_rsa_import_private_key(hdr.payload, hdr.length);
124214501Srpaulo}
125214501Srpaulo
126214501Srpaulo
127214501Srpaulostruct crypto_private_key *
128214501Srpaulopkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
129214501Srpaulo{
130214501Srpaulo	struct asn1_hdr hdr;
131214501Srpaulo	const u8 *pos, *end, *enc_alg;
132214501Srpaulo	size_t enc_alg_len;
133214501Srpaulo	u8 *data;
134214501Srpaulo	size_t data_len;
135214501Srpaulo
136214501Srpaulo	if (passwd == NULL)
137214501Srpaulo		return NULL;
138214501Srpaulo
139214501Srpaulo	/*
140214501Srpaulo	 * PKCS #8, Chapter 7
141214501Srpaulo	 * EncryptedPrivateKeyInfo ::= SEQUENCE {
142214501Srpaulo	 *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
143214501Srpaulo	 *   encryptedData EncryptedData }
144214501Srpaulo	 * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
145214501Srpaulo	 * EncryptedData ::= OCTET STRING
146214501Srpaulo	 */
147214501Srpaulo
148214501Srpaulo	if (asn1_get_next(buf, len, &hdr) < 0 ||
149214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
150214501Srpaulo	    hdr.tag != ASN1_TAG_SEQUENCE) {
151214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
152214501Srpaulo			   "header (SEQUENCE); assume encrypted PKCS #8 not "
153214501Srpaulo			   "used");
154214501Srpaulo		return NULL;
155214501Srpaulo	}
156214501Srpaulo	pos = hdr.payload;
157214501Srpaulo	end = pos + hdr.length;
158214501Srpaulo
159214501Srpaulo	/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
160214501Srpaulo	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
161214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
162214501Srpaulo	    hdr.tag != ASN1_TAG_SEQUENCE) {
163214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
164214501Srpaulo			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
165214501Srpaulo			   "assume encrypted PKCS #8 not used",
166214501Srpaulo			   hdr.class, hdr.tag);
167214501Srpaulo		return NULL;
168214501Srpaulo	}
169214501Srpaulo	enc_alg = hdr.payload;
170214501Srpaulo	enc_alg_len = hdr.length;
171214501Srpaulo	pos = hdr.payload + hdr.length;
172214501Srpaulo
173214501Srpaulo	/* encryptedData EncryptedData */
174214501Srpaulo	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
175214501Srpaulo	    hdr.class != ASN1_CLASS_UNIVERSAL ||
176214501Srpaulo	    hdr.tag != ASN1_TAG_OCTETSTRING) {
177214501Srpaulo		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
178214501Srpaulo			   "(encryptedData) - found class %d tag 0x%x",
179214501Srpaulo			   hdr.class, hdr.tag);
180214501Srpaulo		return NULL;
181214501Srpaulo	}
182214501Srpaulo
183214501Srpaulo	data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
184214501Srpaulo			     passwd, &data_len);
185214501Srpaulo	if (data) {
186214501Srpaulo		struct crypto_private_key *key;
187214501Srpaulo		key = pkcs8_key_import(data, data_len);
188214501Srpaulo		os_free(data);
189214501Srpaulo		return key;
190214501Srpaulo	}
191214501Srpaulo
192214501Srpaulo	return NULL;
193214501Srpaulo}
194