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