swanctl: Stop logging with Ctrl+C on Windows as well
[strongswan.git] / src / swanctl / commands / list_certs.c
1 /*
2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
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 <stdio.h>
18 #include <errno.h>
19 #include <time.h>
20
21 #include <asn1/asn1.h>
22 #include <asn1/oid.h>
23 #include <credentials/certificates/certificate.h>
24 #include <credentials/certificates/x509.h>
25 #include <credentials/certificates/crl.h>
26 #include <credentials/certificates/ac.h>
27 #include <selectors/traffic_selector.h>
28
29 #include "command.h"
30
31 typedef enum {
32 FORMAT_RAW = (1<<0),
33 FORMAT_PEM = (1<<1),
34 } format_options_t;
35
36 /**
37 * Print PEM encoding of a certificate
38 */
39 static void print_pem(certificate_t *cert)
40 {
41 chunk_t encoding;
42
43 if (cert->get_encoding(cert, CERT_PEM, &encoding))
44 {
45 printf("%.*s", (int)encoding.len, encoding.ptr);
46 free(encoding.ptr);
47 }
48 else
49 {
50 fprintf(stderr, "PEM encoding certificate failed\n");
51 }
52 }
53
54 /**
55 * Print public key information
56 */
57 static void print_pubkey(public_key_t *key, bool has_privkey)
58 {
59 chunk_t chunk;
60
61 printf("pubkey: %N %d bits", key_type_names, key->get_type(key),
62 key->get_keysize(key));
63 if (has_privkey)
64 {
65 printf(", has private key");
66 }
67 printf("\n");
68 if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &chunk))
69 {
70 printf("keyid: %#B\n", &chunk);
71 }
72 if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &chunk))
73 {
74 printf("subjkey: %#B\n", &chunk);
75 }
76 }
77
78 /**
79 * Print X509 specific certificate information
80 */
81 static void print_x509(x509_t *x509)
82 {
83 enumerator_t *enumerator;
84 identification_t *id;
85 traffic_selector_t *block;
86 chunk_t chunk;
87 bool first;
88 char *uri;
89 int len, explicit, inhibit;
90 x509_flag_t flags;
91 x509_cdp_t *cdp;
92 x509_cert_policy_t *policy;
93 x509_policy_mapping_t *mapping;
94
95 chunk = chunk_skip_zero(x509->get_serial(x509));
96 printf("serial: %#B\n", &chunk);
97
98 first = TRUE;
99 enumerator = x509->create_subjectAltName_enumerator(x509);
100 while (enumerator->enumerate(enumerator, &id))
101 {
102 if (first)
103 {
104 printf("altNames: ");
105 first = FALSE;
106 }
107 else
108 {
109 printf(", ");
110 }
111 printf("%Y", id);
112 }
113 if (!first)
114 {
115 printf("\n");
116 }
117 enumerator->destroy(enumerator);
118
119 flags = x509->get_flags(x509);
120 printf("flags: ");
121 if (flags & X509_CA)
122 {
123 printf("CA ");
124 }
125 if (flags & X509_CRL_SIGN)
126 {
127 printf("CRLSign ");
128 }
129 if (flags & X509_AA)
130 {
131 printf("AA ");
132 }
133 if (flags & X509_OCSP_SIGNER)
134 {
135 printf("OCSP ");
136 }
137 if (flags & X509_AA)
138 {
139 printf("AA ");
140 }
141 if (flags & X509_SERVER_AUTH)
142 {
143 printf("serverAuth ");
144 }
145 if (flags & X509_CLIENT_AUTH)
146 {
147 printf("clientAuth ");
148 }
149 if (flags & X509_IKE_INTERMEDIATE)
150 {
151 printf("iKEIntermediate ");
152 }
153 if (flags & X509_SELF_SIGNED)
154 {
155 printf("self-signed ");
156 }
157 printf("\n");
158
159 first = TRUE;
160 enumerator = x509->create_crl_uri_enumerator(x509);
161 while (enumerator->enumerate(enumerator, &cdp))
162 {
163 if (first)
164 {
165 printf("CRL URIs: %s", cdp->uri);
166 first = FALSE;
167 }
168 else
169 {
170 printf(" %s", cdp->uri);
171 }
172 if (cdp->issuer)
173 {
174 printf(" (CRL issuer: %Y)", cdp->issuer);
175 }
176 printf("\n");
177 }
178 enumerator->destroy(enumerator);
179
180 first = TRUE;
181 enumerator = x509->create_ocsp_uri_enumerator(x509);
182 while (enumerator->enumerate(enumerator, &uri))
183 {
184 if (first)
185 {
186 printf("OCSP URIs: %s\n", uri);
187 first = FALSE;
188 }
189 else
190 {
191 printf(" %s\n", uri);
192 }
193 }
194 enumerator->destroy(enumerator);
195
196 len = x509->get_constraint(x509, X509_PATH_LEN);
197 if (len != X509_NO_CONSTRAINT)
198 {
199 printf("pathlen: %d\n", len);
200 }
201
202 first = TRUE;
203 enumerator = x509->create_name_constraint_enumerator(x509, TRUE);
204 while (enumerator->enumerate(enumerator, &id))
205 {
206 if (first)
207 {
208 printf("Permitted NameConstraints:\n");
209 first = FALSE;
210 }
211 printf(" %Y\n", id);
212 }
213 enumerator->destroy(enumerator);
214 first = TRUE;
215 enumerator = x509->create_name_constraint_enumerator(x509, FALSE);
216 while (enumerator->enumerate(enumerator, &id))
217 {
218 if (first)
219 {
220 printf("Excluded NameConstraints:\n");
221 first = FALSE;
222 }
223 printf(" %Y\n", id);
224 }
225 enumerator->destroy(enumerator);
226
227 first = TRUE;
228 enumerator = x509->create_cert_policy_enumerator(x509);
229 while (enumerator->enumerate(enumerator, &policy))
230 {
231 char *oid;
232
233 if (first)
234 {
235 printf("CertificatePolicies:\n");
236 first = FALSE;
237 }
238 oid = asn1_oid_to_string(policy->oid);
239 if (oid)
240 {
241 printf(" %s\n", oid);
242 free(oid);
243 }
244 else
245 {
246 printf(" %#B\n", &policy->oid);
247 }
248 if (policy->cps_uri)
249 {
250 printf(" CPS: %s\n", policy->cps_uri);
251 }
252 if (policy->unotice_text)
253 {
254 printf(" Notice: %s\n", policy->unotice_text);
255
256 }
257 }
258 enumerator->destroy(enumerator);
259
260 first = TRUE;
261 enumerator = x509->create_policy_mapping_enumerator(x509);
262 while (enumerator->enumerate(enumerator, &mapping))
263 {
264 char *issuer_oid, *subject_oid;
265
266 if (first)
267 {
268 printf("PolicyMappings:\n");
269 first = FALSE;
270 }
271 issuer_oid = asn1_oid_to_string(mapping->issuer);
272 subject_oid = asn1_oid_to_string(mapping->subject);
273 printf(" %s => %s\n", issuer_oid, subject_oid);
274 free(issuer_oid);
275 free(subject_oid);
276 }
277 enumerator->destroy(enumerator);
278
279 explicit = x509->get_constraint(x509, X509_REQUIRE_EXPLICIT_POLICY);
280 inhibit = x509->get_constraint(x509, X509_INHIBIT_POLICY_MAPPING);
281 len = x509->get_constraint(x509, X509_INHIBIT_ANY_POLICY);
282
283 if (explicit != X509_NO_CONSTRAINT || inhibit != X509_NO_CONSTRAINT ||
284 len != X509_NO_CONSTRAINT)
285 {
286 printf("PolicyConstraints:\n");
287 if (explicit != X509_NO_CONSTRAINT)
288 {
289 printf(" requireExplicitPolicy: %d\n", explicit);
290 }
291 if (inhibit != X509_NO_CONSTRAINT)
292 {
293 printf(" inhibitPolicyMapping: %d\n", inhibit);
294 }
295 if (len != X509_NO_CONSTRAINT)
296 {
297 printf(" inhibitAnyPolicy: %d\n", len);
298 }
299 }
300
301 chunk = x509->get_authKeyIdentifier(x509);
302 if (chunk.ptr)
303 {
304 printf("authkeyId: %#B\n", &chunk);
305 }
306
307 chunk = x509->get_subjectKeyIdentifier(x509);
308 if (chunk.ptr)
309 {
310 printf("subjkeyId: %#B\n", &chunk);
311 }
312 if (x509->get_flags(x509) & X509_IP_ADDR_BLOCKS)
313 {
314 first = TRUE;
315 printf("addresses: ");
316 enumerator = x509->create_ipAddrBlock_enumerator(x509);
317 while (enumerator->enumerate(enumerator, &block))
318 {
319 if (first)
320 {
321 first = FALSE;
322 }
323 else
324 {
325 printf(", ");
326 }
327 printf("%R", block);
328 }
329 enumerator->destroy(enumerator);
330 printf("\n");
331 }
332 }
333
334 /**
335 * Print CRL specific information
336 */
337 static void print_crl(crl_t *crl)
338 {
339 enumerator_t *enumerator;
340 time_t ts;
341 crl_reason_t reason;
342 chunk_t chunk;
343 int count = 0;
344 bool first;
345 char buf[64];
346 struct tm tm;
347 x509_cdp_t *cdp;
348
349 chunk = chunk_skip_zero(crl->get_serial(crl));
350 printf("serial: %#B\n", &chunk);
351
352 if (crl->is_delta_crl(crl, &chunk))
353 {
354 chunk = chunk_skip_zero(chunk);
355 printf("delta CRL: for serial %#B\n", &chunk);
356 }
357 chunk = crl->get_authKeyIdentifier(crl);
358 printf("authKeyId: %#B\n", &chunk);
359
360 first = TRUE;
361 enumerator = crl->create_delta_crl_uri_enumerator(crl);
362 while (enumerator->enumerate(enumerator, &cdp))
363 {
364 if (first)
365 {
366 printf("freshest: %s", cdp->uri);
367 first = FALSE;
368 }
369 else
370 {
371 printf(" %s", cdp->uri);
372 }
373 if (cdp->issuer)
374 {
375 printf(" (CRL issuer: %Y)", cdp->issuer);
376 }
377 printf("\n");
378 }
379 enumerator->destroy(enumerator);
380
381 enumerator = crl->create_enumerator(crl);
382 while (enumerator->enumerate(enumerator, &chunk, &ts, &reason))
383 {
384 count++;
385 }
386 enumerator->destroy(enumerator);
387
388 printf("%d revoked certificate%s%s\n", count,
389 count == 1 ? "" : "s", count ? ":" : "");
390 enumerator = crl->create_enumerator(crl);
391 while (enumerator->enumerate(enumerator, &chunk, &ts, &reason))
392 {
393 chunk = chunk_skip_zero(chunk);
394 localtime_r(&ts, &tm);
395 strftime(buf, sizeof(buf), "%F %T", &tm);
396 printf(" %#B %N %s\n", &chunk, crl_reason_names, reason, buf);
397 count++;
398 }
399 enumerator->destroy(enumerator);
400 }
401
402 /**
403 * Print AC specific information
404 */
405 static void print_ac(ac_t *ac)
406 {
407 ac_group_type_t type;
408 identification_t *id;
409 enumerator_t *groups;
410 chunk_t chunk;
411 bool first = TRUE;
412
413 chunk = chunk_skip_zero(ac->get_serial(ac));
414 printf("serial: %#B\n", &chunk);
415
416 id = ac->get_holderIssuer(ac);
417 if (id)
418 {
419 printf("hissuer: \"%Y\"\n", id);
420 }
421 chunk = chunk_skip_zero(ac->get_holderSerial(ac));
422 if (chunk.ptr)
423 {
424 printf("hserial: %#B\n", &chunk);
425 }
426 groups = ac->create_group_enumerator(ac);
427 while (groups->enumerate(groups, &type, &chunk))
428 {
429 int oid;
430 char *str;
431
432 if (first)
433 {
434 printf("groups: ");
435 first = FALSE;
436 }
437 else
438 {
439 printf(" ");
440 }
441 switch (type)
442 {
443 case AC_GROUP_TYPE_STRING:
444 printf("%.*s", (int)chunk.len, chunk.ptr);
445 break;
446 case AC_GROUP_TYPE_OID:
447 oid = asn1_known_oid(chunk);
448 if (oid == OID_UNKNOWN)
449 {
450 str = asn1_oid_to_string(chunk);
451 if (str)
452 {
453 printf("%s", str);
454 free(str);
455 }
456 else
457 {
458 printf("OID:%#B", &chunk);
459 }
460 }
461 else
462 {
463 printf("%s", oid_names[oid].name);
464 }
465 break;
466 case AC_GROUP_TYPE_OCTETS:
467 printf("%#B", &chunk);
468 break;
469 }
470 printf("\n");
471 }
472 groups->destroy(groups);
473
474 chunk = ac->get_authKeyIdentifier(ac);
475 if (chunk.ptr)
476 {
477 printf("authkey: %#B\n", &chunk);
478 }
479 }
480
481 /**
482 * Print certificate information
483 */
484 static void print_cert(certificate_t *cert, bool has_privkey)
485 {
486 time_t now, notAfter, notBefore;
487 public_key_t *key;
488
489 now = time(NULL);
490
491 printf("cert: %N\n", certificate_type_names, cert->get_type(cert));
492 if (cert->get_type(cert) != CERT_X509_CRL)
493 {
494 printf("subject: \"%Y\"\n", cert->get_subject(cert));
495 }
496 printf("issuer: \"%Y\"\n", cert->get_issuer(cert));
497
498 cert->get_validity(cert, &now, &notBefore, &notAfter);
499 printf("validity: not before %T, ", &notBefore, FALSE);
500 if (now < notBefore)
501 {
502 printf("not valid yet (valid in %V)\n", &now, &notBefore);
503 }
504 else
505 {
506 printf("ok\n");
507 }
508 printf(" not after %T, ", &notAfter, FALSE);
509 if (now > notAfter)
510 {
511 printf("expired (%V ago)\n", &now, &notAfter);
512 }
513 else
514 {
515 printf("ok (expires in %V)\n", &now, &notAfter);
516 }
517
518 switch (cert->get_type(cert))
519 {
520 case CERT_X509:
521 print_x509((x509_t*)cert);
522 break;
523 case CERT_X509_CRL:
524 print_crl((crl_t*)cert);
525 break;
526 case CERT_X509_AC:
527 print_ac((ac_t*)cert);
528 break;
529 default:
530 fprintf(stderr, "parsing certificate subtype %N not implemented\n",
531 certificate_type_names, cert->get_type(cert));
532 break;
533 }
534 key = cert->get_public_key(cert);
535 if (key)
536 {
537 print_pubkey(key, has_privkey);
538 key->destroy(key);
539 }
540 printf("\n");
541 }
542
543 CALLBACK(list_cb, void,
544 format_options_t *format, char *name, vici_res_t *res)
545 {
546 if (*format & FORMAT_RAW)
547 {
548 vici_dump(res, "list-cert event", stdout);
549 }
550 else
551 {
552 certificate_type_t type;
553 certificate_t *cert;
554 void *buf;
555 int len;
556 bool has_privkey;
557
558 buf = vici_find(res, &len, "data");
559 has_privkey = streq(vici_find_str(res, "no", "has_privkey"), "yes");
560 if (enum_from_name(certificate_type_names,
561 vici_find_str(res, "ANY", "type"), &type) &&
562 type != CERT_ANY && buf)
563 {
564 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, type,
565 BUILD_BLOB_ASN1_DER, chunk_create(buf, len),
566 BUILD_END);
567 if (cert)
568 {
569 if (*format & FORMAT_PEM)
570 {
571 print_pem(cert);
572 }
573 else
574 {
575 print_cert(cert, has_privkey);
576 }
577 cert->destroy(cert);
578 }
579 else
580 {
581 fprintf(stderr, "parsing certificate failed\n");
582 }
583 }
584 else
585 {
586 fprintf(stderr, "received incomplete certificate data\n");
587 }
588 }
589 }
590
591 static int list_certs(vici_conn_t *conn)
592 {
593 vici_req_t *req;
594 vici_res_t *res;
595 format_options_t format = 0;
596 char *arg, *subject = NULL, *type = NULL;
597
598 while (TRUE)
599 {
600 switch (command_getopt(&arg))
601 {
602 case 'h':
603 return command_usage(NULL);
604 case 's':
605 subject = arg;
606 continue;
607 case 't':
608 type = arg;
609 continue;
610 case 'p':
611 format |= FORMAT_PEM;
612 continue;
613 case 'r':
614 format |= FORMAT_RAW;
615 continue;
616 case EOF:
617 break;
618 default:
619 return command_usage("invalid --list-certs option");
620 }
621 break;
622 }
623 if (vici_register(conn, "list-cert", list_cb, &format) != 0)
624 {
625 fprintf(stderr, "registering for certificates failed: %s\n",
626 strerror(errno));
627 return errno;
628 }
629 req = vici_begin("list-certs");
630 if (type)
631 {
632 vici_add_key_valuef(req, "type", "%s", type);
633 }
634 if (subject)
635 {
636 vici_add_key_valuef(req, "subject", "%s", subject);
637 }
638 res = vici_submit(req, conn);
639 if (!res)
640 {
641 fprintf(stderr, "list-certs request failed: %s\n", strerror(errno));
642 return errno;
643 }
644 if (format & FORMAT_RAW)
645 {
646 vici_dump(res, "list-certs reply", stdout);
647 }
648 vici_free_res(res);
649 return 0;
650 }
651
652 /**
653 * Register the command.
654 */
655 static void __attribute__ ((constructor))reg()
656 {
657 command_register((command_t) {
658 list_certs, 'x', "list-certs", "list stored certificates",
659 {"[--subject <dn/san>] [--type X509|X509_AC|X509_CRL] [--pem] [--raw]"},
660 {
661 {"help", 'h', 0, "show usage information"},
662 {"subject", 's', 1, "filter by certificate subject"},
663 {"type", 't', 1, "filter by certificate type"},
664 {"pem", 'p', 0, "print PEM encoding of certificate"},
665 {"raw", 'r', 0, "dump raw response message"},
666 }
667 });
668 }