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