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