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