edb309fe4b7c421cec60ec1899fc237866ba3cf9
[strongswan.git] / src / pki / pki.c
1 /*
2 * Copyright (C) 2009 Martin Willi
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 #define _GNU_SOURCE
17 #include <getopt.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <time.h>
27
28 #include <library.h>
29 #include <credentials/keys/private_key.h>
30 #include <credentials/certificates/certificate.h>
31 #include <credentials/certificates/x509.h>
32
33 static int usage(char *error)
34 {
35 FILE *out = stdout;
36
37 if (error)
38 {
39 out = stderr;
40 fprintf(out, "Error: %s\n", error);
41 }
42 fprintf(out, "strongSwan %s PKI tool\n", VERSION);
43 fprintf(out, "usage:\n");
44 fprintf(out, " pki --help\n");
45 fprintf(out, " show this usage information\n");
46 fprintf(out, " pki --gen [--type rsa|ecdsa] [--size bits] [--outform der|pem|pgp]\n");
47 fprintf(out, " generate a new private key\n");
48 fprintf(out, " --type type of key, default: rsa\n");
49 fprintf(out, " --size keylength in bits, default: rsa 2048, ecdsa 384\n");
50 fprintf(out, " --outform encoding of generated private key\n");
51 fprintf(out, " pki --pub [--in file] [--type rsa|ecdsa|x509] [--outform der|pem|pgp]\n");
52 fprintf(out, " extract the public key from a private key/certificate\n");
53 fprintf(out, " --in input file, default: stdin\n");
54 fprintf(out, " --type type of credential, default: rsa\n");
55 fprintf(out, " --outform encoding of extracted public key\n");
56 fprintf(out, " pki --keyid [--in file] [--type rsa-priv|ecdsa-priv|pub|x509]\n");
57 fprintf(out, " calculate key identifiers of a key/certificate\n");
58 fprintf(out, " --in input file, default: stdin\n");
59 fprintf(out, " --type type of key, default: rsa-priv\n");
60 fprintf(out, " pki --self [--in file] [--type rsa|ecdsa] --dn distinguished-name\n");
61 fprintf(out, " [--lifetime days] [--serial hex]\n");
62 fprintf(out, " create a self signed certificate\n");
63 fprintf(out, " --in private key input file, default: stdin\n");
64 fprintf(out, " --type type of input key, default: rsa\n");
65 fprintf(out, " --dn subject and issuer distinguished name\n");
66 fprintf(out, " --lifetime days the certificate is valid, default: 1080\n");
67 fprintf(out, " --serial serial number in hex, default: random\n");
68 fprintf(out, " pki --verify [--in file] [--ca file]\n");
69 fprintf(out, " verify a certificate using the CA certificate\n");
70 fprintf(out, " --in x509 certifcate to verify, default: stdin\n");
71 fprintf(out, " --ca CA certificate, default: verify self signed\n");
72 return !!error;
73 }
74
75 /**
76 * Convert a form string to a encoding type
77 */
78 static bool get_form(char *form, key_encoding_type_t *type, bool pub)
79 {
80 if (streq(form, "der"))
81 {
82 /* der encoded keys usually contain the complete SubjectPublicKeyInfo */
83 *type = pub ? KEY_PUB_SPKI_ASN1_DER : KEY_PRIV_ASN1_DER;
84 }
85 else if (streq(form, "pem"))
86 {
87 *type = pub ? KEY_PUB_PEM : KEY_PRIV_PEM;
88 }
89 else if (streq(form, "pgp"))
90 {
91 *type = pub ? KEY_PUB_PGP : KEY_PRIV_PGP;
92 }
93 else
94 {
95 return FALSE;
96 }
97 return TRUE;
98 }
99
100 /**
101 * Generate a private key
102 */
103 static int gen(int argc, char *argv[])
104 {
105 key_encoding_type_t form = KEY_PRIV_ASN1_DER;
106 key_type_t type = KEY_RSA;
107 u_int size = 0;
108 private_key_t *key;
109 chunk_t encoding;
110
111 struct option long_opts[] = {
112 { "type", required_argument, NULL, 't' },
113 { "size", required_argument, NULL, 's' },
114 { "outform", required_argument, NULL, 'o' },
115 { 0,0,0,0 }
116 };
117 while (TRUE)
118 {
119 switch (getopt_long(argc, argv, "", long_opts, NULL))
120 {
121 case 't':
122 if (streq(optarg, "rsa"))
123 {
124 type = KEY_RSA;
125 }
126 else if (streq(optarg, "ecdsa"))
127 {
128 type = KEY_ECDSA;
129 }
130 else
131 {
132 return usage("invalid key type");
133 }
134 continue;
135 case 'o':
136 if (!get_form(optarg, &form, FALSE))
137 {
138 return usage("invalid key output format");
139 }
140 continue;
141 case 's':
142 size = atoi(optarg);
143 if (!size)
144 {
145 return usage("invalid key size");
146 }
147 continue;
148 case EOF:
149 break;
150 default:
151 return usage("invalid --gen option");
152 }
153 break;
154 }
155 /* default key sizes */
156 if (!size)
157 {
158 switch (type)
159 {
160 case KEY_RSA:
161 size = 2048;
162 break;
163 case KEY_ECDSA:
164 size = 384;
165 break;
166 default:
167 break;
168 }
169 }
170 key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
171 BUILD_KEY_SIZE, size, BUILD_END);
172 if (!key)
173 {
174 fprintf(stderr, "private key generation failed\n");
175 return 1;
176 }
177 if (!key->get_encoding(key, form, &encoding))
178 {
179 fprintf(stderr, "private key encoding failed\n");
180 key->destroy(key);
181 return 1;
182 }
183 key->destroy(key);
184 if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
185 {
186 fprintf(stderr, "writing private key failed\n");
187 free(encoding.ptr);
188 return 1;
189 }
190 free(encoding.ptr);
191 return 0;
192 }
193
194 /**
195 * Extract a public key from a private key/certificate
196 */
197 static int pub(int argc, char *argv[])
198 {
199 key_encoding_type_t form = KEY_PUB_SPKI_ASN1_DER;
200 credential_type_t type = CRED_PRIVATE_KEY;
201 int subtype = KEY_RSA;
202 certificate_t *cert;
203 private_key_t *private;
204 public_key_t *public;
205 chunk_t encoding;
206 char *file = NULL;
207 void *cred;
208
209 struct option long_opts[] = {
210 { "type", required_argument, NULL, 't' },
211 { "outform", required_argument, NULL, 'f' },
212 { "in", required_argument, NULL, 'i' },
213 { 0,0,0,0 }
214 };
215 while (TRUE)
216 {
217 switch (getopt_long(argc, argv, "", long_opts, NULL))
218 {
219 case 't':
220 if (streq(optarg, "rsa"))
221 {
222 type = CRED_PRIVATE_KEY;
223 subtype = KEY_RSA;
224 }
225 else if (streq(optarg, "ecdsa"))
226 {
227 type = CRED_PRIVATE_KEY;
228 subtype = KEY_ECDSA;
229 }
230 else if (streq(optarg, "x509"))
231 {
232 type = CRED_CERTIFICATE;
233 subtype = CERT_X509;
234 }
235 else
236 {
237 return usage("invalid input type");
238 }
239 continue;
240 case 'f':
241 if (!get_form(optarg, &form, TRUE))
242 {
243 return usage("invalid output format");
244 }
245 continue;
246 case 'i':
247 file = optarg;
248 continue;
249 case EOF:
250 break;
251 default:
252 return usage("invalid --pub option");
253 }
254 break;
255 }
256 if (file)
257 {
258 cred = lib->creds->create(lib->creds, type, subtype,
259 BUILD_FROM_FILE, file, BUILD_END);
260 }
261 else
262 {
263 cred = lib->creds->create(lib->creds, type, subtype,
264 BUILD_FROM_FD, 0, BUILD_END);
265 }
266
267 if (type == CRED_PRIVATE_KEY)
268 {
269 private = cred;
270 if (!private)
271 {
272 fprintf(stderr, "parsing private key failed\n");
273 return 1;
274 }
275 public = private->get_public_key(private);
276 private->destroy(private);
277 }
278 else
279 {
280 cert = cred;
281 if (!cert)
282 {
283 fprintf(stderr, "parsing certificate failed\n");
284 return 1;
285 }
286 public = cert->get_public_key(cert);
287 cert->destroy(cert);
288 }
289 if (!public)
290 {
291 fprintf(stderr, "extracting public key failed\n");
292 return 1;
293 }
294 if (!public->get_encoding(public, form, &encoding))
295 {
296 fprintf(stderr, "public key encoding failed\n");
297 public->destroy(public);
298 return 1;
299 }
300 public->destroy(public);
301 if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
302 {
303 fprintf(stderr, "writing public key failed\n");
304 free(encoding.ptr);
305 return 1;
306 }
307 free(encoding.ptr);
308 return 0;
309 }
310
311 /**
312 * Calculate the keyid of a key/certificate
313 */
314 static int keyid(int argc, char *argv[])
315 {
316 credential_type_t type = CRED_PRIVATE_KEY;
317 int subtype = KEY_RSA;
318 certificate_t *cert;
319 private_key_t *private;
320 public_key_t *public;
321 char *file = NULL;
322 void *cred;
323 chunk_t id;
324
325 struct option long_opts[] = {
326 { "type", required_argument, NULL, 't' },
327 { "in", required_argument, NULL, 'i' },
328 { 0,0,0,0 }
329 };
330 while (TRUE)
331 {
332 switch (getopt_long(argc, argv, "", long_opts, NULL))
333 {
334 case 't':
335 if (streq(optarg, "rsa-priv"))
336 {
337 type = CRED_PRIVATE_KEY;
338 subtype = KEY_RSA;
339 }
340 else if (streq(optarg, "ecdsa-priv"))
341 {
342 type = CRED_PRIVATE_KEY;
343 subtype = KEY_ECDSA;
344 }
345 else if (streq(optarg, "pub"))
346 {
347 type = CRED_PUBLIC_KEY;
348 subtype = KEY_ANY;
349 }
350 else if (streq(optarg, "x509"))
351 {
352 type = CRED_CERTIFICATE;
353 subtype = CERT_X509;
354 }
355 else
356 {
357 return usage("invalid input type");
358 }
359 continue;
360 case 'i':
361 file = optarg;
362 continue;
363 case EOF:
364 break;
365 default:
366 return usage("invalid --keyid option");
367 }
368 break;
369 }
370 if (file)
371 {
372 cred = lib->creds->create(lib->creds, type, subtype,
373 BUILD_FROM_FILE, file, BUILD_END);
374 }
375 else
376 {
377 cred = lib->creds->create(lib->creds, type, subtype,
378 BUILD_FROM_FD, 0, BUILD_END);
379 }
380 if (!cred)
381 {
382 fprintf(stderr, "parsing input failed\n");
383 return 1;
384 }
385
386 if (type == CRED_PRIVATE_KEY)
387 {
388 private = cred;
389 if (private->get_fingerprint(private, KEY_ID_PUBKEY_SHA1, &id))
390 {
391 printf("subjectKeyIdentifier: %#B\n", &id);
392 }
393 if (private->get_fingerprint(private, KEY_ID_PUBKEY_INFO_SHA1, &id))
394 {
395 printf("subjectPublicKeyInfo hash: %#B\n", &id);
396 }
397 private->destroy(private);
398 }
399 else if (type == CRED_PUBLIC_KEY)
400 {
401 public = cred;
402 if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &id))
403 {
404 printf("subjectKeyIdentifier: %#B\n", &id);
405 }
406 if (public->get_fingerprint(public, KEY_ID_PUBKEY_INFO_SHA1, &id))
407 {
408 printf("subjectPublicKeyInfo hash: %#B\n", &id);
409 }
410 public->destroy(public);
411 }
412 else
413 {
414 cert = cred;
415 public = cert->get_public_key(cert);
416 if (!public)
417 {
418 fprintf(stderr, "extracting public key from certificate failed");
419 return 1;
420 }
421 if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &id))
422 {
423 printf("subjectKeyIdentifier: %#B\n", &id);
424 }
425 if (public->get_fingerprint(public, KEY_ID_PUBKEY_INFO_SHA1, &id))
426 {
427 printf("subjectPublicKeyInfo hash: %#B\n", &id);
428 }
429 public->destroy(public);
430 cert->destroy(cert);
431 }
432 return 0;
433 }
434
435 /**
436 * Create a self signed certificate.
437 */
438 static int self(int argc, char *argv[])
439 {
440 key_type_t type = KEY_RSA;
441 certificate_t *cert;
442 private_key_t *private;
443 public_key_t *public;
444 char *file = NULL, *dn = NULL, *hex = NULL;
445 identification_t *id;
446 int lifetime = 1080;
447 chunk_t serial, encoding;
448 time_t not_before, not_after;
449
450 struct option long_opts[] = {
451 { "type", required_argument, NULL, 't' },
452 { "in", required_argument, NULL, 'i' },
453 { "dn", required_argument, NULL, 'd' },
454 { "lifetime", required_argument, NULL, 'l' },
455 { "serial", required_argument, NULL, 's' },
456 { 0,0,0,0 }
457 };
458
459 while (TRUE)
460 {
461 switch (getopt_long(argc, argv, "", long_opts, NULL))
462 {
463 case 't':
464 if (streq(optarg, "rsa"))
465 {
466 type = KEY_RSA;
467 }
468 else if (streq(optarg, "ecdsa"))
469 {
470 type = KEY_ECDSA;
471 }
472 else
473 {
474 return usage("invalid input type");
475 }
476 continue;
477 case 'i':
478 file = optarg;
479 continue;
480 case 'd':
481 dn = optarg;
482 continue;
483 case 'l':
484 lifetime = atoi(optarg);
485 if (!lifetime)
486 {
487 return usage("invalid --lifetime value");
488 }
489 continue;
490 case 's':
491 hex = optarg;
492 continue;
493 case EOF:
494 break;
495 default:
496 return usage("invalid --self option");
497 }
498 break;
499 }
500
501 if (!dn)
502 {
503 return usage("--dn is required");
504 }
505 id = identification_create_from_string(dn);
506 if (id->get_type(id) != ID_DER_ASN1_DN)
507 {
508 id->destroy(id);
509 fprintf(stderr, "supplied --dn is not a distinguished name\n");
510 return 1;
511 }
512 if (file)
513 {
514 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
515 BUILD_FROM_FILE, file, BUILD_END);
516 }
517 else
518 {
519 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
520 BUILD_FROM_FD, 0, BUILD_END);
521 }
522 if (!private)
523 {
524 id->destroy(id);
525 fprintf(stderr, "parsing private key failed\n");
526 return 1;
527 }
528 public = private->get_public_key(private);
529 if (!public)
530 {
531 private->destroy(private);
532 id->destroy(id);
533 fprintf(stderr, "extracting public key failed\n");
534 return 1;
535 }
536 if (hex)
537 {
538 serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL);
539 }
540 else
541 {
542 rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
543 if (!rng)
544 {
545 id->destroy(id);
546 private->destroy(private);
547 public->destroy(public);
548 fprintf(stderr, "no random number generator found\n");
549 return 1;
550 }
551 rng->allocate_bytes(rng, 8, &serial);
552 rng->destroy(rng);
553 }
554 not_before = time(NULL);
555 not_after = not_before + lifetime * 24 * 60 * 60;
556 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
557 BUILD_SIGNING_KEY, private, BUILD_PUBLIC_KEY, public,
558 BUILD_SUBJECT, id, BUILD_NOT_BEFORE_TIME, not_before,
559 BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial,
560 BUILD_END);
561 private->destroy(private);
562 public->destroy(public);
563 id->destroy(id);
564 free(serial.ptr);
565 if (!cert)
566 {
567 fprintf(stderr, "generating certificate failed\n");
568 return 1;
569 }
570 encoding = cert->get_encoding(cert);
571 if (!encoding.ptr)
572 {
573 cert->destroy(cert);
574 fprintf(stderr, "encoding certificate failed\n");
575 return 1;
576 }
577 cert->destroy(cert);
578 if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
579 {
580 fprintf(stderr, "writing certificate key failed\n");
581 free(encoding.ptr);
582 return 1;
583 }
584 free(encoding.ptr);
585 return 0;
586 }
587
588 /**
589 * Verify a certificate signature
590 */
591 static int verify(int argc, char *argv[])
592 {
593 certificate_t *cert, *ca;
594 char *file = NULL, *cafile = NULL;
595 bool good = FALSE;
596
597 struct option long_opts[] = {
598 { "in", required_argument, NULL, 'i' },
599 { "ca", required_argument, NULL, 'c' },
600 { 0,0,0,0 }
601 };
602
603 while (TRUE)
604 {
605 switch (getopt_long(argc, argv, "", long_opts, NULL))
606 {
607 case 'i':
608 file = optarg;
609 continue;
610 case 'c':
611 cafile = optarg;
612 continue;
613 case EOF:
614 break;
615 default:
616 return usage("invalid --self option");
617 }
618 break;
619 }
620
621 if (file)
622 {
623 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
624 BUILD_FROM_FILE, file, BUILD_END);
625 }
626 else
627 {
628 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
629 BUILD_FROM_FD, 0, BUILD_END);
630 }
631 if (!cert)
632 {
633 fprintf(stderr, "parsing certificate failed\n");
634 return 1;
635 }
636 if (cafile)
637 {
638 ca = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
639 BUILD_FROM_FILE, cafile,
640 BUILD_X509_FLAG, X509_CA,
641 BUILD_END);
642 if (!ca)
643 {
644 fprintf(stderr, "parsing CA certificate failed\n");
645 return 1;
646 }
647 }
648 else
649 {
650 ca = cert;
651 }
652 if (cert->issued_by(cert, ca))
653 {
654 if (cert->get_validity(cert, NULL, NULL, NULL))
655 {
656 if (cafile)
657 {
658 if (ca->get_validity(ca, NULL, NULL, NULL))
659 {
660 printf("signature good, certificates valid\n");
661 good = TRUE;
662 }
663 else
664 {
665 printf("signature good, CA certificates not valid now\n");
666 }
667 }
668 else
669 {
670 printf("signature good, certificate valid\n");
671 good = TRUE;
672 }
673 }
674 else
675 {
676 printf("certificate not valid now\n");
677 }
678 }
679 else
680 {
681 printf("signature invalid\n");
682 }
683 if (cafile)
684 {
685 ca->destroy(ca);
686 }
687 cert->destroy(cert);
688
689 return good ? 0 : 2;
690 }
691
692 /**
693 * Library initialization and operation parsing
694 */
695 int main(int argc, char *argv[])
696 {
697 struct option long_opts[] = {
698 { "help", no_argument, NULL, 'h' },
699 { "gen", no_argument, NULL, 'g' },
700 { "pub", no_argument, NULL, 'p' },
701 { "keyid", no_argument, NULL, 'k' },
702 { "self", no_argument, NULL, 's' },
703 { "verify", no_argument, NULL, 'v' },
704 { 0,0,0,0 }
705 };
706
707 atexit(library_deinit);
708 if (!library_init(STRONGSWAN_CONF))
709 {
710 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
711 }
712 if (lib->integrity &&
713 !lib->integrity->check_file(lib->integrity, "pki", argv[0]))
714 {
715 fprintf(stderr, "integrity check of pki failed\n");
716 exit(SS_RC_DAEMON_INTEGRITY);
717 }
718 lib->plugins->load(lib->plugins, PLUGINDIR,
719 lib->settings->get_str(lib->settings, "pki.load", PLUGINS));
720
721 switch (getopt_long(argc, argv, "", long_opts, NULL))
722 {
723 case 'h':
724 return usage(NULL);
725 case 'g':
726 return gen(argc, argv);
727 case 'p':
728 return pub(argc, argv);
729 case 'k':
730 return keyid(argc, argv);
731 case 's':
732 return self(argc, argv);
733 case 'v':
734 return verify(argc, argv);
735 default:
736 return usage("invalid operation");
737 }
738 }
739