6278f66b4ccdec345049beeb4fcc88a6b2f1ee6e
[strongswan.git] / src / swanctl / commands / load_creds.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
4 *
5 * Copyright (C) 2016 Tobias Brunner
6 * Copyright (C) 2015 Andreas Steffen
7 * HSR Hochschule fuer Technik Rapperswil
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25
26 #include "command.h"
27 #include "swanctl.h"
28 #include "load_creds.h"
29
30 #include <credentials/sets/mem_cred.h>
31 #include <credentials/sets/callback_cred.h>
32 #include <credentials/containers/pkcs12.h>
33
34 #include <vici_cert_info.h>
35
36 /**
37 * Load a single certificate over vici
38 */
39 static bool load_cert(vici_conn_t *conn, command_format_options_t format,
40 char *dir, certificate_type_t type, x509_flag_t flag,
41 chunk_t data)
42 {
43 vici_req_t *req;
44 vici_res_t *res;
45 bool ret = TRUE;
46
47 req = vici_begin("load-cert");
48
49 vici_add_key_valuef(req, "type", "%N", certificate_type_names, type);
50 if (type == CERT_X509)
51 {
52 vici_add_key_valuef(req, "flag", "%N", x509_flag_names, flag);
53 }
54 vici_add_key_value(req, "data", data.ptr, data.len);
55
56 res = vici_submit(req, conn);
57 if (!res)
58 {
59 fprintf(stderr, "load-cert request failed: %s\n", strerror(errno));
60 return FALSE;
61 }
62 if (format & COMMAND_FORMAT_RAW)
63 {
64 vici_dump(res, "load-cert reply", format & COMMAND_FORMAT_PRETTY,
65 stdout);
66 }
67 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
68 {
69 fprintf(stderr, "loading '%s' failed: %s\n",
70 dir, vici_find_str(res, "", "errmsg"));
71 ret = FALSE;
72 }
73 else
74 {
75 printf("loaded certificate from '%s'\n", dir);
76 }
77 vici_free_res(res);
78 return ret;
79 }
80
81 /**
82 * Load certficiates from a directory
83 */
84 static void load_certs(vici_conn_t *conn, command_format_options_t format,
85 char *type_str, char *dir)
86 {
87 enumerator_t *enumerator;
88 certificate_type_t type;
89 x509_flag_t flag;
90 struct stat st;
91 chunk_t *map;
92 char *path;
93
94 vici_cert_info_from_str(type_str, &type, &flag);
95
96 enumerator = enumerator_create_directory(dir);
97 if (enumerator)
98 {
99 while (enumerator->enumerate(enumerator, NULL, &path, &st))
100 {
101 if (S_ISREG(st.st_mode))
102 {
103 map = chunk_map(path, FALSE);
104 if (map)
105 {
106 load_cert(conn, format, path, type, flag, *map);
107 chunk_unmap(map);
108 }
109 else
110 {
111 fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
112 path, strerror(errno));
113 }
114 }
115 }
116 enumerator->destroy(enumerator);
117 }
118 }
119
120 /**
121 * Load a single private key over vici
122 */
123 static bool load_key(vici_conn_t *conn, command_format_options_t format,
124 char *dir, char *type, chunk_t data)
125 {
126 vici_req_t *req;
127 vici_res_t *res;
128 bool ret = TRUE;
129
130 req = vici_begin("load-key");
131
132 if (streq(type, "private") ||
133 streq(type, "pkcs8"))
134 { /* as used by vici */
135 vici_add_key_valuef(req, "type", "any");
136 }
137 else
138 {
139 vici_add_key_valuef(req, "type", "%s", type);
140 }
141 vici_add_key_value(req, "data", data.ptr, data.len);
142
143 res = vici_submit(req, conn);
144 if (!res)
145 {
146 fprintf(stderr, "load-key request failed: %s\n", strerror(errno));
147 return FALSE;
148 }
149 if (format & COMMAND_FORMAT_RAW)
150 {
151 vici_dump(res, "load-key reply", format & COMMAND_FORMAT_PRETTY,
152 stdout);
153 }
154 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
155 {
156 fprintf(stderr, "loading '%s' failed: %s\n",
157 dir, vici_find_str(res, "", "errmsg"));
158 ret = FALSE;
159 }
160 else
161 {
162 printf("loaded %s key from '%s'\n", type, dir);
163 }
164 vici_free_res(res);
165 return ret;
166 }
167
168 /**
169 * Load a private key of any type to vici
170 */
171 static bool load_key_anytype(vici_conn_t *conn, command_format_options_t format,
172 char *path, private_key_t *private)
173 {
174 bool loaded = FALSE;
175 chunk_t encoding;
176
177 if (!private->get_encoding(private, PRIVKEY_ASN1_DER, &encoding))
178 {
179 fprintf(stderr, "encoding private key from '%s' failed\n", path);
180 return FALSE;
181 }
182 switch (private->get_type(private))
183 {
184 case KEY_RSA:
185 loaded = load_key(conn, format, path, "rsa", encoding);
186 break;
187 case KEY_ECDSA:
188 loaded = load_key(conn, format, path, "ecdsa", encoding);
189 break;
190 case KEY_BLISS:
191 loaded = load_key(conn, format, path, "bliss", encoding);
192 break;
193 default:
194 fprintf(stderr, "unsupported key type in '%s'\n", path);
195 break;
196 }
197 chunk_clear(&encoding);
198 return loaded;
199 }
200
201 /**
202 * Data passed to password callback
203 */
204 typedef struct {
205 char prompt[128];
206 mem_cred_t *cache;
207 } cb_data_t;
208
209 /**
210 * Callback function to prompt for private key passwords
211 */
212 CALLBACK(password_cb, shared_key_t*,
213 cb_data_t *data, shared_key_type_t type,
214 identification_t *me, identification_t *other,
215 id_match_t *match_me, id_match_t *match_other)
216 {
217 shared_key_t *shared;
218 char *pwd = NULL;
219
220 if (type != SHARED_PRIVATE_KEY_PASS)
221 {
222 return NULL;
223 }
224 #ifdef HAVE_GETPASS
225 pwd = getpass(data->prompt);
226 #endif
227 if (!pwd || strlen(pwd) == 0)
228 {
229 return NULL;
230 }
231 if (match_me)
232 {
233 *match_me = ID_MATCH_PERFECT;
234 }
235 if (match_other)
236 {
237 *match_other = ID_MATCH_PERFECT;
238 }
239 shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
240 /* cache secret if it is required more than once (PKCS#12) */
241 data->cache->add_shared(data->cache, shared, NULL);
242 return shared->get_ref(shared);
243 }
244
245 /**
246 * Determine credential type and subtype from a type string
247 */
248 static bool determine_credtype(char *type, credential_type_t *credtype,
249 int *subtype)
250 {
251 struct {
252 char *type;
253 credential_type_t credtype;
254 int subtype;
255 } map[] = {
256 { "private", CRED_PRIVATE_KEY, KEY_ANY, },
257 { "pkcs8", CRED_PRIVATE_KEY, KEY_ANY, },
258 { "rsa", CRED_PRIVATE_KEY, KEY_RSA, },
259 { "ecdsa", CRED_PRIVATE_KEY, KEY_ECDSA, },
260 { "bliss", CRED_PRIVATE_KEY, KEY_BLISS, },
261 { "pkcs12", CRED_CONTAINER, CONTAINER_PKCS12, },
262 };
263 int i;
264
265 for (i = 0; i < countof(map); i++)
266 {
267 if (streq(map[i].type, type))
268 {
269 *credtype = map[i].credtype;
270 *subtype = map[i].subtype;
271 return TRUE;
272 }
273 }
274 return FALSE;
275 }
276
277 /**
278 * Try to parse a potentially encrypted credential using password prompt
279 */
280 static void* decrypt(char *name, char *type, chunk_t encoding)
281 {
282 credential_type_t credtype;
283 int subtype;
284 void *cred;
285 callback_cred_t *cb;
286 cb_data_t data;
287
288 if (!determine_credtype(type, &credtype, &subtype))
289 {
290 return NULL;
291 }
292
293 snprintf(data.prompt, sizeof(data.prompt), "Password for %s file '%s': ",
294 type, name);
295
296 data.cache = mem_cred_create();
297 lib->credmgr->add_set(lib->credmgr, &data.cache->set);
298 cb = callback_cred_create_shared(password_cb, &data);
299 lib->credmgr->add_set(lib->credmgr, &cb->set);
300
301 cred = lib->creds->create(lib->creds, credtype, subtype,
302 BUILD_BLOB_PEM, encoding, BUILD_END);
303
304 lib->credmgr->remove_set(lib->credmgr, &data.cache->set);
305 data.cache->destroy(data.cache);
306 lib->credmgr->remove_set(lib->credmgr, &cb->set);
307 cb->destroy(cb);
308
309 return cred;
310 }
311
312 /**
313 * Try to parse a potentially encrypted credential using configured secret
314 */
315 static void* decrypt_with_config(settings_t *cfg, char *name, char *type,
316 chunk_t encoding)
317 {
318 credential_type_t credtype;
319 int subtype;
320 enumerator_t *enumerator, *secrets;
321 char *section, *key, *value, *file, buf[128];
322 shared_key_t *shared;
323 void *cred = NULL;
324 mem_cred_t *mem = NULL;
325
326 if (!determine_credtype(type, &credtype, &subtype))
327 {
328 return NULL;
329 }
330
331 /* load all secrets for this key type */
332 enumerator = cfg->create_section_enumerator(cfg, "secrets");
333 while (enumerator->enumerate(enumerator, &section))
334 {
335 if (strpfx(section, type))
336 {
337 file = cfg->get_str(cfg, "secrets.%s.file", NULL, section);
338 if (file && strcaseeq(file, name))
339 {
340 snprintf(buf, sizeof(buf), "secrets.%s", section);
341 secrets = cfg->create_key_value_enumerator(cfg, buf);
342 while (secrets->enumerate(secrets, &key, &value))
343 {
344 if (strpfx(key, "secret"))
345 {
346 if (!mem)
347 {
348 mem = mem_cred_create();
349 }
350 shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
351 chunk_clone(chunk_from_str(value)));
352 mem->add_shared(mem, shared, NULL);
353 }
354 }
355 secrets->destroy(secrets);
356 }
357 }
358 }
359 enumerator->destroy(enumerator);
360
361 if (mem)
362 {
363 lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
364
365 cred = lib->creds->create(lib->creds, credtype, subtype,
366 BUILD_BLOB_PEM, encoding, BUILD_END);
367
368 lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
369
370 if (!cred)
371 {
372 fprintf(stderr, "configured decryption secret for '%s' invalid\n",
373 name);
374 }
375
376 mem->destroy(mem);
377 }
378
379 return cred;
380 }
381
382 /**
383 * Try to decrypt and load a private key
384 */
385 static bool load_encrypted_key(vici_conn_t *conn,
386 command_format_options_t format, settings_t *cfg,
387 char *rel, char *path, char *type, bool noprompt,
388 chunk_t data)
389 {
390 private_key_t *private;
391 bool loaded = FALSE;
392
393 private = decrypt_with_config(cfg, rel, type, data);
394 if (!private && !noprompt)
395 {
396 private = decrypt(rel, type, data);
397 }
398 if (private)
399 {
400 loaded = load_key_anytype(conn, format, path, private);
401 private->destroy(private);
402 }
403 return loaded;
404 }
405
406 /**
407 * Load private keys from a directory
408 */
409 static void load_keys(vici_conn_t *conn, command_format_options_t format,
410 bool noprompt, settings_t *cfg, char *type, char *dir)
411 {
412 enumerator_t *enumerator;
413 struct stat st;
414 chunk_t *map;
415 char *path, *rel;
416
417 enumerator = enumerator_create_directory(dir);
418 if (enumerator)
419 {
420 while (enumerator->enumerate(enumerator, &rel, &path, &st))
421 {
422 if (S_ISREG(st.st_mode))
423 {
424 map = chunk_map(path, FALSE);
425 if (map)
426 {
427 if (!load_encrypted_key(conn, format, cfg, rel, path, type,
428 noprompt, *map))
429 {
430 load_key(conn, format, path, type, *map);
431 }
432 chunk_unmap(map);
433 }
434 else
435 {
436 fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
437 path, strerror(errno));
438 }
439 }
440 }
441 enumerator->destroy(enumerator);
442 }
443 }
444
445 /**
446 * Load credentials from a PKCS#12 container over vici
447 */
448 static bool load_pkcs12(vici_conn_t *conn, command_format_options_t format,
449 char *path, pkcs12_t *p12)
450 {
451 enumerator_t *enumerator;
452 certificate_t *cert;
453 private_key_t *private;
454 chunk_t encoding;
455 bool loaded = TRUE;
456
457 enumerator = p12->create_cert_enumerator(p12);
458 while (loaded && enumerator->enumerate(enumerator, &cert))
459 {
460 loaded = FALSE;
461 if (cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
462 {
463 loaded = load_cert(conn, format, path, CERT_X509, X509_NONE,
464 encoding);
465 if (loaded)
466 {
467 fprintf(stderr, " %Y\n", cert->get_subject(cert));
468 }
469 free(encoding.ptr);
470 }
471 else
472 {
473 fprintf(stderr, "encoding certificate from '%s' failed\n", path);
474 }
475 }
476 enumerator->destroy(enumerator);
477
478 enumerator = p12->create_key_enumerator(p12);
479 while (loaded && enumerator->enumerate(enumerator, &private))
480 {
481 loaded = load_key_anytype(conn, format, path, private);
482 }
483 enumerator->destroy(enumerator);
484
485 return loaded;
486 }
487
488 /**
489 * Try to decrypt and load credentials from a container
490 */
491 static bool load_encrypted_container(vici_conn_t *conn,
492 command_format_options_t format, settings_t *cfg, char *rel,
493 char *path, char *type, bool noprompt, chunk_t data)
494 {
495 container_t *container;
496 bool loaded = FALSE;
497
498 container = decrypt_with_config(cfg, rel, type, data);
499 if (!container && !noprompt)
500 {
501 container = decrypt(rel, type, data);
502 }
503 if (container)
504 {
505 switch (container->get_type(container))
506 {
507 case CONTAINER_PKCS12:
508 loaded = load_pkcs12(conn, format, path, (pkcs12_t*)container);
509 break;
510 default:
511 break;
512 }
513 container->destroy(container);
514 }
515 return loaded;
516 }
517
518 /**
519 * Load credential containers from a directory
520 */
521 static void load_containers(vici_conn_t *conn, command_format_options_t format,
522 bool noprompt, settings_t *cfg, char *type, char *dir)
523 {
524 enumerator_t *enumerator;
525 struct stat st;
526 chunk_t *map;
527 char *path, *rel;
528
529 enumerator = enumerator_create_directory(dir);
530 if (enumerator)
531 {
532 while (enumerator->enumerate(enumerator, &rel, &path, &st))
533 {
534 if (S_ISREG(st.st_mode))
535 {
536 map = chunk_map(path, FALSE);
537 if (map)
538 {
539 load_encrypted_container(conn, format, cfg, rel, path,
540 type, noprompt, *map);
541 chunk_unmap(map);
542 }
543 else
544 {
545 fprintf(stderr, "mapping '%s' failed: %s, skipped\n",
546 path, strerror(errno));
547 }
548 }
549 }
550 enumerator->destroy(enumerator);
551 }
552 }
553
554 /**
555 * Load a single secret over VICI
556 */
557 static bool load_secret(vici_conn_t *conn, settings_t *cfg,
558 char *section, command_format_options_t format)
559 {
560 enumerator_t *enumerator;
561 vici_req_t *req;
562 vici_res_t *res;
563 chunk_t data;
564 char *key, *value, buf[128], *type = NULL;
565 bool ret = TRUE;
566 int i;
567 char *types[] = {
568 "eap",
569 "xauth",
570 "ike",
571 "private",
572 "rsa",
573 "ecdsa",
574 "bliss",
575 "pkcs8",
576 "pkcs12",
577 };
578
579 for (i = 0; i < countof(types); i++)
580 {
581 if (strpfx(section, types[i]))
582 {
583 type = types[i];
584 break;
585 }
586 }
587 if (!type)
588 {
589 fprintf(stderr, "ignoring unsupported secret '%s'\n", section);
590 return FALSE;
591 }
592 if (!streq(type, "eap") && !streq(type, "xauth") && !streq(type, "ike"))
593 { /* skip non-shared secrets */
594 return TRUE;
595 }
596
597 value = cfg->get_str(cfg, "secrets.%s.secret", NULL, section);
598 if (!value)
599 {
600 fprintf(stderr, "missing secret in '%s', ignored\n", section);
601 return FALSE;
602 }
603 if (strcasepfx(value, "0x"))
604 {
605 data = chunk_from_hex(chunk_from_str(value + 2), NULL);
606 }
607 else if (strcasepfx(value, "0s"))
608 {
609 data = chunk_from_base64(chunk_from_str(value + 2), NULL);
610 }
611 else
612 {
613 data = chunk_clone(chunk_from_str(value));
614 }
615
616 req = vici_begin("load-shared");
617
618 vici_add_key_valuef(req, "type", "%s", type);
619 vici_add_key_value(req, "data", data.ptr, data.len);
620 chunk_clear(&data);
621
622 vici_begin_list(req, "owners");
623 snprintf(buf, sizeof(buf), "secrets.%s", section);
624 enumerator = cfg->create_key_value_enumerator(cfg, buf);
625 while (enumerator->enumerate(enumerator, &key, &value))
626 {
627 if (strpfx(key, "id"))
628 {
629 vici_add_list_itemf(req, "%s", value);
630 }
631 }
632 enumerator->destroy(enumerator);
633 vici_end_list(req);
634
635 res = vici_submit(req, conn);
636 if (!res)
637 {
638 fprintf(stderr, "load-shared request failed: %s\n", strerror(errno));
639 return FALSE;
640 }
641 if (format & COMMAND_FORMAT_RAW)
642 {
643 vici_dump(res, "load-shared reply", format & COMMAND_FORMAT_PRETTY,
644 stdout);
645 }
646 else if (!streq(vici_find_str(res, "no", "success"), "yes"))
647 {
648 fprintf(stderr, "loading shared secret failed: %s\n",
649 vici_find_str(res, "", "errmsg"));
650 ret = FALSE;
651 }
652 else
653 {
654 printf("loaded %s secret '%s'\n", type, section);
655 }
656 vici_free_res(res);
657 return ret;
658 }
659
660 /**
661 * Clear all currently loaded credentials
662 */
663 static bool clear_creds(vici_conn_t *conn, command_format_options_t format)
664 {
665 vici_res_t *res;
666
667 res = vici_submit(vici_begin("clear-creds"), conn);
668 if (!res)
669 {
670 fprintf(stderr, "clear-creds request failed: %s\n", strerror(errno));
671 return FALSE;
672 }
673 if (format & COMMAND_FORMAT_RAW)
674 {
675 vici_dump(res, "clear-creds reply", format & COMMAND_FORMAT_PRETTY,
676 stdout);
677 }
678 vici_free_res(res);
679 return TRUE;
680 }
681
682 /**
683 * See header.
684 */
685 int load_creds_cfg(vici_conn_t *conn, command_format_options_t format,
686 settings_t *cfg, bool clear, bool noprompt)
687 {
688 enumerator_t *enumerator;
689 char *section;
690
691 if (clear)
692 {
693 if (!clear_creds(conn, format))
694 {
695 return ECONNREFUSED;
696 }
697 }
698
699 load_certs(conn, format, "x509", SWANCTL_X509DIR);
700 load_certs(conn, format, "x509ca", SWANCTL_X509CADIR);
701 load_certs(conn, format, "x509ocsp", SWANCTL_X509OCSPDIR);
702 load_certs(conn, format, "x509aa", SWANCTL_X509AADIR);
703 load_certs(conn, format, "x509ac", SWANCTL_X509ACDIR);
704 load_certs(conn, format, "x509crl", SWANCTL_X509CRLDIR);
705 load_certs(conn, format, "pubkey", SWANCTL_PUBKEYDIR);
706
707 load_keys(conn, format, noprompt, cfg, "private", SWANCTL_PRIVATEDIR);
708 load_keys(conn, format, noprompt, cfg, "rsa", SWANCTL_RSADIR);
709 load_keys(conn, format, noprompt, cfg, "ecdsa", SWANCTL_ECDSADIR);
710 load_keys(conn, format, noprompt, cfg, "bliss", SWANCTL_BLISSDIR);
711 load_keys(conn, format, noprompt, cfg, "pkcs8", SWANCTL_PKCS8DIR);
712
713 load_containers(conn, format, noprompt, cfg, "pkcs12", SWANCTL_PKCS12DIR);
714
715 enumerator = cfg->create_section_enumerator(cfg, "secrets");
716 while (enumerator->enumerate(enumerator, &section))
717 {
718 load_secret(conn, cfg, section, format);
719 }
720 enumerator->destroy(enumerator);
721
722 return 0;
723 }
724
725 static int load_creds(vici_conn_t *conn)
726 {
727 bool clear = FALSE, noprompt = FALSE;
728 command_format_options_t format = COMMAND_FORMAT_NONE;
729 settings_t *cfg;
730 char *arg;
731 int ret;
732
733 while (TRUE)
734 {
735 switch (command_getopt(&arg))
736 {
737 case 'h':
738 return command_usage(NULL);
739 case 'c':
740 clear = TRUE;
741 continue;
742 case 'n':
743 noprompt = TRUE;
744 continue;
745 case 'P':
746 format |= COMMAND_FORMAT_PRETTY;
747 /* fall through to raw */
748 case 'r':
749 format |= COMMAND_FORMAT_RAW;
750 continue;
751 case EOF:
752 break;
753 default:
754 return command_usage("invalid --load-creds option");
755 }
756 break;
757 }
758
759 cfg = settings_create(SWANCTL_CONF);
760 if (!cfg)
761 {
762 fprintf(stderr, "parsing '%s' failed\n", SWANCTL_CONF);
763 return EINVAL;
764 }
765
766 ret = load_creds_cfg(conn, format, cfg, clear, noprompt);
767
768 cfg->destroy(cfg);
769
770 return ret;
771 }
772
773 /**
774 * Register the command.
775 */
776 static void __attribute__ ((constructor))reg()
777 {
778 command_register((command_t) {
779 load_creds, 's', "load-creds", "(re-)load credentials",
780 {"[--raw|--pretty] [--clear] [--noprompt]"},
781 {
782 {"help", 'h', 0, "show usage information"},
783 {"clear", 'c', 0, "clear previously loaded credentials"},
784 {"noprompt", 'n', 0, "do not prompt for passwords"},
785 {"raw", 'r', 0, "dump raw response message"},
786 {"pretty", 'P', 0, "dump raw response message in pretty print"},
787 }
788 });
789 }