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
pkcs8_key_import(const u8 * buf,size_t len)19 struct 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
121 struct crypto_private_key *
pkcs8_enc_key_import(const u8 * buf,size_t len,const char * passwd)122 pkcs8_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