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