allow choice of digest algorithm in certificate generation
[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 hash_algorithm_t digest = HASH_SHA1;
442 certificate_t *cert;
443 private_key_t *private;
444 public_key_t *public;
445 char *file = NULL, *dn = NULL, *hex = NULL;
446 identification_t *id;
447 int lifetime = 1080;
448 chunk_t serial, encoding;
449 time_t not_before, not_after;
450
451 struct option long_opts[] = {
452 { "type", required_argument, NULL, 't' },
453 { "in", required_argument, NULL, 'i' },
454 { "dn", required_argument, NULL, 'd' },
455 { "lifetime", required_argument, NULL, 'l' },
456 { "serial", required_argument, NULL, 's' },
457 { "digest", required_argument, NULL, 'h' },
458 { 0,0,0,0 }
459 };
460
461 while (TRUE)
462 {
463 switch (getopt_long(argc, argv, "", long_opts, NULL))
464 {
465 case 't':
466 if (streq(optarg, "rsa"))
467 {
468 type = KEY_RSA;
469 }
470 else if (streq(optarg, "ecdsa"))
471 {
472 type = KEY_ECDSA;
473 }
474 else
475 {
476 return usage("invalid input type");
477 }
478 continue;
479 case 'h':
480 if (streq(optarg, "md5"))
481 {
482 digest = HASH_MD5;
483 }
484 else if (streq(optarg, "sha1"))
485 {
486 digest = HASH_SHA1;
487 }
488 else if (streq(optarg, "sha224"))
489 {
490 digest = HASH_SHA224;
491 }
492 else if (streq(optarg, "sha256"))
493 {
494 digest = HASH_SHA256;
495 }
496 else if (streq(optarg, "sha384"))
497 {
498 digest = HASH_SHA384;
499 }
500 else if (streq(optarg, "sha512"))
501 {
502 digest = HASH_SHA512;
503 }
504 else
505 {
506 return usage("invalid --digest type");
507 }
508 continue;
509 case 'i':
510 file = optarg;
511 continue;
512 case 'd':
513 dn = optarg;
514 continue;
515 case 'l':
516 lifetime = atoi(optarg);
517 if (!lifetime)
518 {
519 return usage("invalid --lifetime value");
520 }
521 continue;
522 case 's':
523 hex = optarg;
524 continue;
525 case EOF:
526 break;
527 default:
528 return usage("invalid --self option");
529 }
530 break;
531 }
532
533 if (!dn)
534 {
535 return usage("--dn is required");
536 }
537 id = identification_create_from_string(dn);
538 if (id->get_type(id) != ID_DER_ASN1_DN)
539 {
540 id->destroy(id);
541 fprintf(stderr, "supplied --dn is not a distinguished name\n");
542 return 1;
543 }
544 if (file)
545 {
546 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
547 BUILD_FROM_FILE, file, BUILD_END);
548 }
549 else
550 {
551 private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
552 BUILD_FROM_FD, 0, BUILD_END);
553 }
554 if (!private)
555 {
556 id->destroy(id);
557 fprintf(stderr, "parsing private key failed\n");
558 return 1;
559 }
560 public = private->get_public_key(private);
561 if (!public)
562 {
563 private->destroy(private);
564 id->destroy(id);
565 fprintf(stderr, "extracting public key failed\n");
566 return 1;
567 }
568 if (hex)
569 {
570 serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL);
571 }
572 else
573 {
574 rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
575 if (!rng)
576 {
577 id->destroy(id);
578 private->destroy(private);
579 public->destroy(public);
580 fprintf(stderr, "no random number generator found\n");
581 return 1;
582 }
583 rng->allocate_bytes(rng, 8, &serial);
584 rng->destroy(rng);
585 }
586 not_before = time(NULL);
587 not_after = not_before + lifetime * 24 * 60 * 60;
588 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
589 BUILD_SIGNING_KEY, private, BUILD_PUBLIC_KEY, public,
590 BUILD_SUBJECT, id, BUILD_NOT_BEFORE_TIME, not_before,
591 BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial,
592 BUILD_DIGEST_ALG, digest, BUILD_END);
593 private->destroy(private);
594 public->destroy(public);
595 id->destroy(id);
596 free(serial.ptr);
597 if (!cert)
598 {
599 fprintf(stderr, "generating certificate failed\n");
600 return 1;
601 }
602 encoding = cert->get_encoding(cert);
603 if (!encoding.ptr)
604 {
605 cert->destroy(cert);
606 fprintf(stderr, "encoding certificate failed\n");
607 return 1;
608 }
609 cert->destroy(cert);
610 if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
611 {
612 fprintf(stderr, "writing certificate key failed\n");
613 free(encoding.ptr);
614 return 1;
615 }
616 free(encoding.ptr);
617 return 0;
618 }
619
620 /**
621 * Verify a certificate signature
622 */
623 static int verify(int argc, char *argv[])
624 {
625 certificate_t *cert, *ca;
626 char *file = NULL, *cafile = NULL;
627 bool good = FALSE;
628
629 struct option long_opts[] = {
630 { "in", required_argument, NULL, 'i' },
631 { "ca", required_argument, NULL, 'c' },
632 { 0,0,0,0 }
633 };
634
635 while (TRUE)
636 {
637 switch (getopt_long(argc, argv, "", long_opts, NULL))
638 {
639 case 'i':
640 file = optarg;
641 continue;
642 case 'c':
643 cafile = optarg;
644 continue;
645 case EOF:
646 break;
647 default:
648 return usage("invalid --self option");
649 }
650 break;
651 }
652
653 if (file)
654 {
655 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
656 BUILD_FROM_FILE, file, BUILD_END);
657 }
658 else
659 {
660 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
661 BUILD_FROM_FD, 0, BUILD_END);
662 }
663 if (!cert)
664 {
665 fprintf(stderr, "parsing certificate failed\n");
666 return 1;
667 }
668 if (cafile)
669 {
670 ca = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
671 BUILD_FROM_FILE, cafile,
672 BUILD_X509_FLAG, X509_CA,
673 BUILD_END);
674 if (!ca)
675 {
676 fprintf(stderr, "parsing CA certificate failed\n");
677 return 1;
678 }
679 }
680 else
681 {
682 ca = cert;
683 }
684 if (cert->issued_by(cert, ca))
685 {
686 if (cert->get_validity(cert, NULL, NULL, NULL))
687 {
688 if (cafile)
689 {
690 if (ca->get_validity(ca, NULL, NULL, NULL))
691 {
692 printf("signature good, certificates valid\n");
693 good = TRUE;
694 }
695 else
696 {
697 printf("signature good, CA certificates not valid now\n");
698 }
699 }
700 else
701 {
702 printf("signature good, certificate valid\n");
703 good = TRUE;
704 }
705 }
706 else
707 {
708 printf("certificate not valid now\n");
709 }
710 }
711 else
712 {
713 printf("signature invalid\n");
714 }
715 if (cafile)
716 {
717 ca->destroy(ca);
718 }
719 cert->destroy(cert);
720
721 return good ? 0 : 2;
722 }
723
724 /**
725 * Library initialization and operation parsing
726 */
727 int main(int argc, char *argv[])
728 {
729 struct option long_opts[] = {
730 { "help", no_argument, NULL, 'h' },
731 { "gen", no_argument, NULL, 'g' },
732 { "pub", no_argument, NULL, 'p' },
733 { "keyid", no_argument, NULL, 'k' },
734 { "self", no_argument, NULL, 's' },
735 { "verify", no_argument, NULL, 'v' },
736 { 0,0,0,0 }
737 };
738
739 atexit(library_deinit);
740 if (!library_init(STRONGSWAN_CONF))
741 {
742 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
743 }
744 if (lib->integrity &&
745 !lib->integrity->check_file(lib->integrity, "pki", argv[0]))
746 {
747 fprintf(stderr, "integrity check of pki failed\n");
748 exit(SS_RC_DAEMON_INTEGRITY);
749 }
750 lib->plugins->load(lib->plugins, PLUGINDIR,
751 lib->settings->get_str(lib->settings, "pki.load", PLUGINS));
752
753 switch (getopt_long(argc, argv, "", long_opts, NULL))
754 {
755 case 'h':
756 return usage(NULL);
757 case 'g':
758 return gen(argc, argv);
759 case 'p':
760 return pub(argc, argv);
761 case 'k':
762 return keyid(argc, argv);
763 case 's':
764 return self(argc, argv);
765 case 'v':
766 return verify(argc, argv);
767 default:
768 return usage("invalid operation");
769 }
770 }
771