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