Added support for encrypted PKCS#8 files (for some PKCS#5 v1.5 schemes).
[strongswan.git] / src / libstrongswan / plugins / pkcs8 / pkcs8_builder.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pkcs8_builder.h"
17
18 #include <debug.h>
19 #include <asn1/oid.h>
20 #include <asn1/asn1.h>
21 #include <asn1/asn1_parser.h>
22 #include <credentials/keys/private_key.h>
23
24 /**
25 * ASN.1 definition of a privateKeyInfo structure
26 */
27 static const asn1Object_t pkinfoObjects[] = {
28 { 0, "privateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
29 { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
30 { 1, "privateKeyAlgorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
31 { 1, "privateKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
32 { 1, "attributes", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
33 { 1, "end opt", ASN1_EOC, ASN1_END }, /* 5 */
34 { 0, "exit", ASN1_EOC, ASN1_EXIT }
35 };
36 #define PKINFO_PRIVATE_KEY_ALGORITHM 2
37 #define PKINFO_PRIVATE_KEY 3
38
39 /**
40 * Load a generic private key from an ASN.1 encoded blob
41 */
42 static private_key_t *parse_private_key(chunk_t blob)
43 {
44 asn1_parser_t *parser;
45 chunk_t object, params = chunk_empty;
46 int objectID;
47 private_key_t *key = NULL;
48 key_type_t type = KEY_ANY;
49
50 parser = asn1_parser_create(pkinfoObjects, blob);
51 parser->set_flags(parser, FALSE, TRUE);
52
53 while (parser->iterate(parser, &objectID, &object))
54 {
55 switch (objectID)
56 {
57 case PKINFO_PRIVATE_KEY_ALGORITHM:
58 {
59 int oid = asn1_parse_algorithmIdentifier(object,
60 parser->get_level(parser) + 1, &params);
61
62 switch (oid)
63 {
64 case OID_RSA_ENCRYPTION:
65 type = KEY_RSA;
66 break;
67 case OID_EC_PUBLICKEY:
68 type = KEY_ECDSA;
69 break;
70 default:
71 /* key type not supported */
72 goto end;
73 }
74 break;
75 }
76 case PKINFO_PRIVATE_KEY:
77 {
78 DBG2(DBG_ASN, "-- > --");
79 if (params.ptr)
80 {
81 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
82 type, BUILD_BLOB_ALGID_PARAMS,
83 params, BUILD_BLOB_ASN1_DER,
84 object, BUILD_END);
85 }
86 else
87 {
88 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
89 type, BUILD_BLOB_ASN1_DER, object,
90 BUILD_END);
91 }
92 DBG2(DBG_ASN, "-- < --");
93 break;
94 }
95 }
96 }
97
98 end:
99 parser->destroy(parser);
100 return key;
101 }
102
103 /**
104 * Verify padding of decrypted blob.
105 * Length of blob is adjusted accordingly.
106 */
107 static bool verify_padding(chunk_t *blob)
108 {
109 u_int8_t padding, count;
110
111 padding = count = blob->ptr[blob->len - 1];
112 if (padding > 8)
113 {
114 return FALSE;
115 }
116 for (; blob->len && count; --blob->len, --count)
117 {
118 if (blob->ptr[blob->len - 1] != padding)
119 {
120 return FALSE;
121 }
122 }
123 return TRUE;
124 }
125
126 /**
127 * PBKDF1 key derivation function
128 */
129 static void pbkdf1(hasher_t *hasher, chunk_t password, chunk_t salt,
130 u_int64_t iterations, chunk_t key)
131 {
132 chunk_t hash;
133 u_int64_t i;
134
135 hash = chunk_alloca(hasher->get_hash_size(hasher));
136 hasher->get_hash(hasher, password, NULL);
137 hasher->get_hash(hasher, salt, hash.ptr);
138
139 for (i = 1; i < iterations; i++)
140 {
141 hasher->get_hash(hasher, hash, hash.ptr);
142 }
143
144 memcpy(key.ptr, hash.ptr, key.len);
145 }
146
147 /**
148 * Decrypt an encrypted PKCS#8 encoded private key
149 */
150 static private_key_t *decrypt_private_key(chunk_t blob,
151 encryption_algorithm_t encr, size_t key_size,
152 hash_algorithm_t hash, chunk_t salt,
153 u_int64_t iterations)
154 {
155 enumerator_t *enumerator;
156 shared_key_t *shared;
157 private_key_t *private_key = NULL;
158 crypter_t *crypter = NULL;
159 hasher_t *hasher = NULL;
160 chunk_t keymat, key, iv;
161
162 hasher = lib->crypto->create_hasher(lib->crypto, hash);
163 if (!hasher)
164 {
165 DBG1(DBG_ASN, " %N hash algorithm not available",
166 hash_algorithm_names, hash);
167 goto end;
168 }
169 if (hasher->get_hash_size(hasher) < key_size)
170 {
171 goto end;
172 }
173
174 crypter = lib->crypto->create_crypter(lib->crypto, encr, key_size);
175 if (!crypter)
176 {
177 DBG1(DBG_ASN, " %N encryption algorithm not available",
178 encryption_algorithm_names, encr);
179 goto end;
180 }
181 if (blob.len % crypter->get_block_size(crypter))
182 {
183 DBG1(DBG_ASN, " data size is not a multiple of block size");
184 goto end;
185 }
186
187 keymat = chunk_alloca(key_size * 2);
188 key.len = key_size;
189 key.ptr = keymat.ptr;
190 iv.len = key_size;
191 iv.ptr = keymat.ptr + key_size;
192
193 enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
194 SHARED_PRIVATE_KEY_PASS, NULL, NULL);
195 while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
196 {
197 chunk_t decrypted;
198
199 pbkdf1(hasher, shared->get_key(shared), salt, iterations, keymat);
200
201 crypter->set_key(crypter, key);
202 crypter->decrypt(crypter, blob, iv, &decrypted);
203 if (verify_padding(&decrypted))
204 {
205 private_key = parse_private_key(decrypted);
206 if (private_key)
207 {
208 chunk_clear(&decrypted);
209 break;
210 }
211 }
212 chunk_free(&decrypted);
213 }
214 enumerator->destroy(enumerator);
215
216 end:
217 DESTROY_IF(crypter);
218 DESTROY_IF(hasher);
219 return private_key;
220 }
221
222 /**
223 * ASN.1 definition of a PBEParameter structure
224 */
225 static const asn1Object_t pbeParameterObjects[] = {
226 { 0, "PBEParameter", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
227 { 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
228 { 1, "iterationCount", ASN1_INTEGER, ASN1_BODY }, /* 2 */
229 { 0, "exit", ASN1_EOC, ASN1_EXIT }
230 };
231 #define PBEPARAM_SALT 1
232 #define PBEPARAM_ITERATION_COUNT 2
233
234 /**
235 * Parse a PBEParameter structure
236 */
237 static void parse_pbe_parameters(chunk_t blob, chunk_t *salt,
238 u_int64_t *iterations)
239 {
240 asn1_parser_t *parser;
241 chunk_t object;
242 int objectID;
243
244 parser = asn1_parser_create(pbeParameterObjects, blob);
245
246 while (parser->iterate(parser, &objectID, &object))
247 {
248 switch (objectID)
249 {
250 case PBEPARAM_SALT:
251 {
252 *salt = object;
253 break;
254 }
255 case PBEPARAM_ITERATION_COUNT:
256 {
257 u_int64_t val = 0;
258 int i;
259
260 for (i = 0; i < object.len; i++)
261 { /* if it is longer than 8 bytes, we just use the 8 LSBs */
262 val <<= 8;
263 val |= (u_int64_t)object.ptr[i];
264 }
265 *iterations = val;
266 break;
267 }
268 }
269 }
270
271 parser->destroy(parser);
272 }
273
274 /**
275 * ASN.1 definition of an encryptedPrivateKeyInfo structure
276 */
277 static const asn1Object_t encryptedPKIObjects[] = {
278 { 0, "encryptedPrivateKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
279 { 1, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
280 { 1, "encryptedData", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
281 { 0, "exit", ASN1_EOC, ASN1_EXIT }
282 };
283 #define EPKINFO_ENCRYPTION_ALGORITHM 1
284 #define EPKINFO_ENCRYPTED_DATA 2
285
286 /**
287 * Load an encrypted private key from an ASN.1 encoded blob
288 * Schemes per PKCS#5 (RFC 2898), currently only a subset of PBES1 is supported
289 */
290 static private_key_t *parse_encrypted_private_key(chunk_t blob)
291 {
292 asn1_parser_t *parser;
293 chunk_t object, params = chunk_empty, salt;
294 u_int64_t iterations;
295 int objectID;
296 encryption_algorithm_t encr = ENCR_UNDEFINED;
297 hash_algorithm_t hash = HASH_UNKNOWN;
298 private_key_t *key = NULL;
299 size_t key_size;
300
301 parser = asn1_parser_create(encryptedPKIObjects, blob);
302
303 while (parser->iterate(parser, &objectID, &object))
304 {
305 switch (objectID)
306 {
307 case EPKINFO_ENCRYPTION_ALGORITHM:
308 {
309 int oid = asn1_parse_algorithmIdentifier(object,
310 parser->get_level(parser) + 1, &params);
311
312 switch (oid)
313 {
314 case OID_PBE_MD5_DES_CBC:
315 encr = ENCR_DES;
316 hash = HASH_MD5;
317 key_size = 8;
318 parse_pbe_parameters(params, &salt, &iterations);
319 break;
320 case OID_PBE_SHA1_DES_CBC:
321 encr = ENCR_DES;
322 hash = HASH_SHA1;
323 key_size = 8;
324 parse_pbe_parameters(params, &salt, &iterations);
325 break;
326 default:
327 /* encryption scheme not supported */
328 goto end;
329 }
330 break;
331 }
332 case EPKINFO_ENCRYPTED_DATA:
333 {
334 key = decrypt_private_key(object, encr, key_size, hash, salt,
335 iterations);
336 break;
337 }
338 }
339 }
340
341 end:
342 parser->destroy(parser);
343 return key;
344 }
345
346 /**
347 * See header.
348 */
349 private_key_t *pkcs8_private_key_load(key_type_t type, va_list args)
350 {
351 chunk_t blob = chunk_empty;
352 private_key_t *key;
353
354 while (TRUE)
355 {
356 switch (va_arg(args, builder_part_t))
357 {
358 case BUILD_BLOB_ASN1_DER:
359 blob = va_arg(args, chunk_t);
360 continue;
361 case BUILD_END:
362 break;
363 default:
364 return NULL;
365 }
366 break;
367 }
368 /* we don't know whether it is encrypted or not, try both ways */
369 key = parse_encrypted_private_key(blob);
370 if (!key)
371 {
372 key = parse_private_key(blob);
373 }
374 return key;
375 }
376