e9d55f3b879435dc055811270abe2258b0f64749
[strongswan.git] / src / libstrongswan / plugins / pem / pem_builder.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * Copyright (C) 2001-2008 Andreas Steffen
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "pem_builder.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <stddef.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30
31 #include <utils/debug.h>
32 #include <library.h>
33 #include <utils/lexparser.h>
34 #include <asn1/asn1.h>
35 #include <crypto/hashers/hasher.h>
36 #include <crypto/crypters/crypter.h>
37 #include <credentials/certificates/x509.h>
38
39 #define PKCS5_SALT_LEN 8 /* bytes */
40
41 /**
42 * check the presence of a pattern in a character string, skip if found
43 */
44 static bool present(char* pattern, chunk_t* ch)
45 {
46 u_int len = strlen(pattern);
47
48 if (ch->len >= len && strneq(ch->ptr, pattern, len))
49 {
50 *ch = chunk_skip(*ch, len);
51 return TRUE;
52 }
53 return FALSE;
54 }
55
56 /**
57 * find a boundary of the form -----tag name-----
58 */
59 static bool find_boundary(char* tag, chunk_t *line)
60 {
61 chunk_t name = chunk_empty;
62
63 if (!present("-----", line) ||
64 !present(tag, line) ||
65 *line->ptr != ' ')
66 {
67 return FALSE;
68 }
69 *line = chunk_skip(*line, 1);
70
71 /* extract name */
72 name.ptr = line->ptr;
73 while (line->len > 0)
74 {
75 if (present("-----", line))
76 {
77 DBG2(DBG_ASN, " -----%s %.*s-----", tag, (int)name.len, name.ptr);
78 return TRUE;
79 }
80 line->ptr++; line->len--; name.len++;
81 }
82 return FALSE;
83 }
84
85 /*
86 * decrypts a passphrase protected encrypted data block
87 */
88 static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
89 size_t key_size, chunk_t iv, chunk_t passphrase)
90 {
91 hasher_t *hasher;
92 crypter_t *crypter;
93 chunk_t salt = { iv.ptr, PKCS5_SALT_LEN };
94 chunk_t hash;
95 chunk_t decrypted;
96 chunk_t key = {alloca(key_size), key_size};
97 u_int8_t padding, *last_padding_pos, *first_padding_pos;
98
99 /* build key from passphrase and IV */
100 hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
101 if (hasher == NULL)
102 {
103 DBG1(DBG_ASN, " MD5 hash algorithm not available");
104 return NOT_SUPPORTED;
105 }
106 hash.len = hasher->get_hash_size(hasher);
107 hash.ptr = alloca(hash.len);
108 if (!hasher->get_hash(hasher, passphrase, NULL) ||
109 !hasher->get_hash(hasher, salt, hash.ptr))
110 {
111 return FAILED;
112 }
113 memcpy(key.ptr, hash.ptr, hash.len);
114
115 if (key.len > hash.len)
116 {
117 if (!hasher->get_hash(hasher, hash, NULL) ||
118 !hasher->get_hash(hasher, passphrase, NULL) ||
119 !hasher->get_hash(hasher, salt, hash.ptr))
120 {
121 return FAILED;
122 }
123 memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len);
124 }
125 hasher->destroy(hasher);
126
127 /* decrypt blob */
128 crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size);
129 if (crypter == NULL)
130 {
131 DBG1(DBG_ASN, " %N encryption algorithm not available",
132 encryption_algorithm_names, alg);
133 return NOT_SUPPORTED;
134 }
135
136 if (iv.len != crypter->get_iv_size(crypter) ||
137 blob->len % crypter->get_block_size(crypter))
138 {
139 crypter->destroy(crypter);
140 DBG1(DBG_ASN, " data size is not multiple of block size");
141 return PARSE_ERROR;
142 }
143 if (!crypter->set_key(crypter, key) ||
144 !crypter->decrypt(crypter, *blob, iv, &decrypted))
145 {
146 crypter->destroy(crypter);
147 return FAILED;
148 }
149 crypter->destroy(crypter);
150 memcpy(blob->ptr, decrypted.ptr, blob->len);
151 chunk_free(&decrypted);
152
153 /* determine amount of padding */
154 last_padding_pos = blob->ptr + blob->len - 1;
155 padding = *last_padding_pos;
156 if (padding > blob->len)
157 {
158 first_padding_pos = blob->ptr;
159 }
160 else
161 {
162 first_padding_pos = last_padding_pos - padding;
163 }
164 /* check the padding pattern */
165 while (--last_padding_pos > first_padding_pos)
166 {
167 if (*last_padding_pos != padding)
168 {
169 DBG1(DBG_ASN, " invalid passphrase");
170 return INVALID_ARG;
171 }
172 }
173 /* remove padding */
174 blob->len -= padding;
175 return SUCCESS;
176 }
177
178 /**
179 * Converts a PEM encoded file into its binary form (RFC 1421, RFC 934)
180 */
181 static status_t pem_to_bin(chunk_t *blob, bool *pgp)
182 {
183 typedef enum {
184 PEM_PRE = 0,
185 PEM_MSG = 1,
186 PEM_HEADER = 2,
187 PEM_BODY = 3,
188 PEM_POST = 4,
189 PEM_ABORT = 5
190 } state_t;
191
192 encryption_algorithm_t alg = ENCR_UNDEFINED;
193 size_t key_size = 0;
194 bool encrypted = FALSE;
195 state_t state = PEM_PRE;
196 chunk_t src = *blob;
197 chunk_t dst = *blob;
198 chunk_t line = chunk_empty;
199 chunk_t iv = chunk_empty;
200 u_char iv_buf[HASH_SIZE_MD5];
201 status_t status = NOT_FOUND;
202 enumerator_t *enumerator;
203 shared_key_t *shared;
204
205 dst.len = 0;
206 iv.ptr = iv_buf;
207 iv.len = 0;
208
209 while (fetchline(&src, &line))
210 {
211 if (state == PEM_PRE)
212 {
213 if (find_boundary("BEGIN", &line))
214 {
215 state = PEM_MSG;
216 }
217 continue;
218 }
219 else
220 {
221 if (find_boundary("END", &line))
222 {
223 state = PEM_POST;
224 break;
225 }
226 if (state == PEM_MSG)
227 {
228 state = PEM_HEADER;
229 if (memchr(line.ptr, ':', line.len) == NULL)
230 {
231 state = PEM_BODY;
232 }
233 }
234 if (state == PEM_HEADER)
235 {
236 err_t ugh = NULL;
237 chunk_t name = chunk_empty;
238 chunk_t value = chunk_empty;
239
240 /* an empty line separates HEADER and BODY */
241 if (line.len == 0)
242 {
243 state = PEM_BODY;
244 continue;
245 }
246
247 /* we are looking for a parameter: value pair */
248 DBG2(DBG_ASN, " %.*s", (int)line.len, line.ptr);
249 ugh = extract_parameter_value(&name, &value, &line);
250 if (ugh != NULL)
251 {
252 continue;
253 }
254 if (match("Proc-Type", &name) && *value.ptr == '4')
255 {
256 encrypted = TRUE;
257 }
258 else if (match("DEK-Info", &name))
259 {
260 chunk_t dek;
261
262 if (!extract_token(&dek, ',', &value))
263 {
264 dek = value;
265 }
266 if (match("DES-EDE3-CBC", &dek))
267 {
268 alg = ENCR_3DES;
269 key_size = 24;
270 }
271 else if (match("AES-128-CBC", &dek))
272 {
273 alg = ENCR_AES_CBC;
274 key_size = 16;
275 }
276 else if (match("AES-192-CBC", &dek))
277 {
278 alg = ENCR_AES_CBC;
279 key_size = 24;
280 }
281 else if (match("AES-256-CBC", &dek))
282 {
283 alg = ENCR_AES_CBC;
284 key_size = 32;
285 }
286 else
287 {
288 DBG1(DBG_ASN, " encryption algorithm '%.*s'"
289 " not supported", (int)dek.len, dek.ptr);
290 return NOT_SUPPORTED;
291 }
292 if (!eat_whitespace(&value) || value.len > 2*sizeof(iv_buf))
293 {
294 return PARSE_ERROR;
295 }
296 iv = chunk_from_hex(value, iv_buf);
297 }
298 }
299 else /* state is PEM_BODY */
300 {
301 chunk_t data;
302
303 /* remove any trailing whitespace */
304 if (!extract_token(&data ,' ', &line))
305 {
306 data = line;
307 }
308
309 /* check for PGP armor checksum */
310 if (*data.ptr == '=')
311 {
312 *pgp = TRUE;
313 data.ptr++;
314 data.len--;
315 DBG2(DBG_ASN, " armor checksum: %.*s", (int)data.len,
316 data.ptr);
317 continue;
318 }
319
320 if (blob->len - dst.len < data.len / 4 * 3)
321 {
322 state = PEM_ABORT;
323 }
324 data = chunk_from_base64(data, dst.ptr);
325
326 dst.ptr += data.len;
327 dst.len += data.len;
328 }
329 }
330 }
331 /* set length to size of binary blob */
332 blob->len = dst.len;
333
334 if (state != PEM_POST)
335 {
336 DBG1(DBG_LIB, " file coded in unknown format, discarded");
337 return PARSE_ERROR;
338 }
339 if (!encrypted)
340 {
341 return SUCCESS;
342 }
343
344 enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
345 SHARED_PRIVATE_KEY_PASS, NULL, NULL);
346 while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
347 {
348 chunk_t passphrase, chunk;
349
350 passphrase = shared->get_key(shared);
351 chunk = chunk_clone(*blob);
352 status = pem_decrypt(&chunk, alg, key_size, iv, passphrase);
353 if (status == SUCCESS)
354 {
355 memcpy(blob->ptr, chunk.ptr, chunk.len);
356 blob->len = chunk.len;
357 }
358 free(chunk.ptr);
359 if (status != INVALID_ARG)
360 { /* try again only if passphrase invalid */
361 break;
362 }
363 }
364 enumerator->destroy(enumerator);
365 return status;
366 }
367
368 /**
369 * load the credential from a blob
370 */
371 static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype,
372 identification_t *subject, x509_flag_t flags)
373 {
374 void *cred = NULL;
375 bool pgp = FALSE;
376
377 blob = chunk_clone(blob);
378 if (!is_asn1(blob))
379 {
380 if (pem_to_bin(&blob, &pgp) != SUCCESS)
381 {
382 chunk_clear(&blob);
383 return NULL;
384 }
385 if (pgp && type == CRED_PRIVATE_KEY)
386 {
387 /* PGP encoded keys are parsed with a KEY_ANY key type, as it
388 * can contain any type of key. However, ipsec.secrets uses
389 * RSA for PGP keys, which is actually wrong. */
390 subtype = KEY_ANY;
391 }
392 }
393 /* if CERT_ANY is given, ASN1 encoded blob is handled as X509 */
394 if (type == CRED_CERTIFICATE && subtype == CERT_ANY)
395 {
396 subtype = pgp ? CERT_GPG : CERT_X509;
397 }
398 if (type == CRED_CERTIFICATE && subtype == CERT_TRUSTED_PUBKEY && subject)
399 {
400 cred = lib->creds->create(lib->creds, type, subtype,
401 BUILD_BLOB_ASN1_DER, blob, BUILD_SUBJECT, subject,
402 BUILD_END);
403 }
404 else
405 {
406 cred = lib->creds->create(lib->creds, type, subtype,
407 pgp ? BUILD_BLOB_PGP : BUILD_BLOB_ASN1_DER, blob,
408 flags ? BUILD_X509_FLAG : BUILD_END,
409 flags, BUILD_END);
410 }
411 chunk_clear(&blob);
412 return cred;
413 }
414
415 /**
416 * load the credential from a file
417 */
418 static void *load_from_file(char *file, credential_type_t type, int subtype,
419 identification_t *subject, x509_flag_t flags)
420 {
421 void *cred = NULL;
422 struct stat sb;
423 void *addr;
424 int fd;
425
426 fd = open(file, O_RDONLY);
427 if (fd == -1)
428 {
429 DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno));
430 return NULL;
431 }
432
433 if (fstat(fd, &sb) == -1)
434 {
435 DBG1(DBG_LIB, " getting file size of '%s' failed: %s", file,
436 strerror(errno));
437 close(fd);
438 return NULL;
439 }
440
441 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
442 if (addr == MAP_FAILED)
443 {
444 DBG1(DBG_LIB, " mapping '%s' failed: %s", file, strerror(errno));
445 close(fd);
446 return NULL;
447 }
448
449 cred = load_from_blob(chunk_create(addr, sb.st_size), type, subtype,
450 subject, flags);
451
452 munmap(addr, sb.st_size);
453 close(fd);
454 return cred;
455 }
456
457 /**
458 * load the credential from a file descriptor
459 */
460 static void *load_from_fd(int fd, credential_type_t type, int subtype,
461 identification_t *subject, x509_flag_t flags)
462 {
463 char buf[8096];
464 char *pos = buf;
465 ssize_t len, total = 0;
466
467 while (TRUE)
468 {
469 len = read(fd, pos, buf + sizeof(buf) - pos);
470 if (len < 0)
471 {
472 DBG1(DBG_LIB, "reading from file descriptor failed: %s",
473 strerror(errno));
474 return NULL;
475 }
476 if (len == 0)
477 {
478 break;
479 }
480 total += len;
481 if (total == sizeof(buf))
482 {
483 DBG1(DBG_LIB, "buffer too small to read from file descriptor");
484 return NULL;
485 }
486 }
487 return load_from_blob(chunk_create(buf, total), type, subtype,
488 subject, flags);
489 }
490
491 /**
492 * Load all kind of PEM encoded credentials.
493 */
494 static void *pem_load(credential_type_t type, int subtype, va_list args)
495 {
496 char *file = NULL;
497 int fd = -1;
498 chunk_t pem = chunk_empty;
499 identification_t *subject = NULL;
500 int flags = 0;
501
502 while (TRUE)
503 {
504 switch (va_arg(args, builder_part_t))
505 {
506 case BUILD_FROM_FILE:
507 file = va_arg(args, char*);
508 continue;
509 case BUILD_FROM_FD:
510 fd = va_arg(args, int);
511 continue;
512 case BUILD_BLOB_PEM:
513 pem = va_arg(args, chunk_t);
514 continue;
515 case BUILD_SUBJECT:
516 subject = va_arg(args, identification_t*);
517 continue;
518 case BUILD_X509_FLAG:
519 flags = va_arg(args, int);
520 continue;
521 case BUILD_END:
522 break;
523 default:
524 return NULL;
525 }
526 break;
527 }
528
529 if (pem.len)
530 {
531 return load_from_blob(pem, type, subtype, subject, flags);
532 }
533 if (file)
534 {
535 return load_from_file(file, type, subtype, subject, flags);
536 }
537 if (fd != -1)
538 {
539 return load_from_fd(fd, type, subtype, subject, flags);
540 }
541 return NULL;
542 }
543
544 /**
545 * Private key PEM loader.
546 */
547 private_key_t *pem_private_key_load(key_type_t type, va_list args)
548 {
549 return pem_load(CRED_PRIVATE_KEY, type, args);
550 }
551
552 /**
553 * Public key PEM loader.
554 */
555 public_key_t *pem_public_key_load(key_type_t type, va_list args)
556 {
557 return pem_load(CRED_PUBLIC_KEY, type, args);
558 }
559
560 /**
561 * Certificate PEM loader.
562 */
563 certificate_t *pem_certificate_load(certificate_type_t type, va_list args)
564 {
565 return pem_load(CRED_CERTIFICATE, type, args);
566 }
567
568 /**
569 * Container PEM loader.
570 */
571 container_t *pem_container_load(container_type_t type, va_list args)
572 {
573 return pem_load(CRED_CONTAINER, type, args);
574 }