2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
5 * Copyright (C) 2015 Andreas Steffen
6 * HSR Hochschule fuer Technik Rapperswil
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>.
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
24 #include <asn1/asn1.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>
35 * Print PEM encoding of a certificate
37 static void print_pem(certificate_t
*cert
)
41 if (cert
->get_encoding(cert
, CERT_PEM
, &encoding
))
43 printf("%.*s", (int)encoding
.len
, encoding
.ptr
);
48 fprintf(stderr
, "PEM encoding certificate failed\n");
53 * Print public key information
55 static void print_pubkey(public_key_t
*key
, bool has_privkey
)
59 printf("pubkey: %N %d bits", key_type_names
, key
->get_type(key
),
60 key
->get_keysize(key
));
63 printf(", has private key");
66 if (key
->get_fingerprint(key
, KEYID_PUBKEY_INFO_SHA1
, &chunk
))
68 printf("keyid: %#B\n", &chunk
);
70 if (key
->get_fingerprint(key
, KEYID_PUBKEY_SHA1
, &chunk
))
72 printf("subjkey: %#B\n", &chunk
);
77 * Print X509 specific certificate information
79 static void print_x509(x509_t
*x509
)
81 enumerator_t
*enumerator
;
83 traffic_selector_t
*block
;
87 int len
, explicit, inhibit
;
90 x509_cert_policy_t
*policy
;
91 x509_policy_mapping_t
*mapping
;
93 chunk
= chunk_skip_zero(x509
->get_serial(x509
));
94 printf("serial: %#B\n", &chunk
);
97 enumerator
= x509
->create_subjectAltName_enumerator(x509
);
98 while (enumerator
->enumerate(enumerator
, &id
))
102 printf("altNames: ");
115 enumerator
->destroy(enumerator
);
117 flags
= x509
->get_flags(x509
);
123 if (flags
& X509_CRL_SIGN
)
131 if (flags
& X509_OCSP_SIGNER
)
139 if (flags
& X509_SERVER_AUTH
)
141 printf("serverAuth ");
143 if (flags
& X509_CLIENT_AUTH
)
145 printf("clientAuth ");
147 if (flags
& X509_IKE_INTERMEDIATE
)
149 printf("iKEIntermediate ");
151 if (flags
& X509_SELF_SIGNED
)
153 printf("self-signed ");
158 enumerator
= x509
->create_crl_uri_enumerator(x509
);
159 while (enumerator
->enumerate(enumerator
, &cdp
))
163 printf("CRL URIs: %s", cdp
->uri
);
168 printf(" %s", cdp
->uri
);
172 printf(" (CRL issuer: %Y)", cdp
->issuer
);
176 enumerator
->destroy(enumerator
);
179 enumerator
= x509
->create_ocsp_uri_enumerator(x509
);
180 while (enumerator
->enumerate(enumerator
, &uri
))
184 printf("OCSP URIs: %s\n", uri
);
189 printf(" %s\n", uri
);
192 enumerator
->destroy(enumerator
);
194 len
= x509
->get_constraint(x509
, X509_PATH_LEN
);
195 if (len
!= X509_NO_CONSTRAINT
)
197 printf("pathlen: %d\n", len
);
201 enumerator
= x509
->create_name_constraint_enumerator(x509
, TRUE
);
202 while (enumerator
->enumerate(enumerator
, &id
))
206 printf("Permitted NameConstraints:\n");
211 enumerator
->destroy(enumerator
);
213 enumerator
= x509
->create_name_constraint_enumerator(x509
, FALSE
);
214 while (enumerator
->enumerate(enumerator
, &id
))
218 printf("Excluded NameConstraints:\n");
223 enumerator
->destroy(enumerator
);
226 enumerator
= x509
->create_cert_policy_enumerator(x509
);
227 while (enumerator
->enumerate(enumerator
, &policy
))
233 printf("CertificatePolicies:\n");
236 oid
= asn1_oid_to_string(policy
->oid
);
239 printf(" %s\n", oid
);
244 printf(" %#B\n", &policy
->oid
);
248 printf(" CPS: %s\n", policy
->cps_uri
);
250 if (policy
->unotice_text
)
252 printf(" Notice: %s\n", policy
->unotice_text
);
256 enumerator
->destroy(enumerator
);
259 enumerator
= x509
->create_policy_mapping_enumerator(x509
);
260 while (enumerator
->enumerate(enumerator
, &mapping
))
262 char *issuer_oid
, *subject_oid
;
266 printf("PolicyMappings:\n");
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
);
275 enumerator
->destroy(enumerator
);
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
);
281 if (explicit != X509_NO_CONSTRAINT
|| inhibit
!= X509_NO_CONSTRAINT
||
282 len
!= X509_NO_CONSTRAINT
)
284 printf("PolicyConstraints:\n");
285 if (explicit != X509_NO_CONSTRAINT
)
287 printf(" requireExplicitPolicy: %d\n", explicit);
289 if (inhibit
!= X509_NO_CONSTRAINT
)
291 printf(" inhibitPolicyMapping: %d\n", inhibit
);
293 if (len
!= X509_NO_CONSTRAINT
)
295 printf(" inhibitAnyPolicy: %d\n", len
);
299 chunk
= x509
->get_authKeyIdentifier(x509
);
302 printf("authkeyId: %#B\n", &chunk
);
305 chunk
= x509
->get_subjectKeyIdentifier(x509
);
308 printf("subjkeyId: %#B\n", &chunk
);
310 if (x509
->get_flags(x509
) & X509_IP_ADDR_BLOCKS
)
313 printf("addresses: ");
314 enumerator
= x509
->create_ipAddrBlock_enumerator(x509
);
315 while (enumerator
->enumerate(enumerator
, &block
))
327 enumerator
->destroy(enumerator
);
333 * Print CRL specific information
335 static void print_crl(crl_t
*crl
)
337 enumerator_t
*enumerator
;
347 chunk
= chunk_skip_zero(crl
->get_serial(crl
));
348 printf("serial: %#B\n", &chunk
);
350 if (crl
->is_delta_crl(crl
, &chunk
))
352 chunk
= chunk_skip_zero(chunk
);
353 printf("delta CRL: for serial %#B\n", &chunk
);
355 chunk
= crl
->get_authKeyIdentifier(crl
);
356 printf("authKeyId: %#B\n", &chunk
);
359 enumerator
= crl
->create_delta_crl_uri_enumerator(crl
);
360 while (enumerator
->enumerate(enumerator
, &cdp
))
364 printf("freshest: %s", cdp
->uri
);
369 printf(" %s", cdp
->uri
);
373 printf(" (CRL issuer: %Y)", cdp
->issuer
);
377 enumerator
->destroy(enumerator
);
379 enumerator
= crl
->create_enumerator(crl
);
380 while (enumerator
->enumerate(enumerator
, &chunk
, &ts
, &reason
))
384 enumerator
->destroy(enumerator
);
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
))
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
);
397 enumerator
->destroy(enumerator
);
401 * Print AC specific information
403 static void print_ac(ac_t
*ac
)
405 ac_group_type_t type
;
406 identification_t
*id
;
407 enumerator_t
*groups
;
411 chunk
= chunk_skip_zero(ac
->get_serial(ac
));
412 printf("serial: %#B\n", &chunk
);
414 id
= ac
->get_holderIssuer(ac
);
417 printf("hissuer: \"%Y\"\n", id
);
419 chunk
= chunk_skip_zero(ac
->get_holderSerial(ac
));
422 printf("hserial: %#B\n", &chunk
);
424 groups
= ac
->create_group_enumerator(ac
);
425 while (groups
->enumerate(groups
, &type
, &chunk
))
441 case AC_GROUP_TYPE_STRING
:
442 printf("%.*s", (int)chunk
.len
, chunk
.ptr
);
444 case AC_GROUP_TYPE_OID
:
445 oid
= asn1_known_oid(chunk
);
446 if (oid
== OID_UNKNOWN
)
448 str
= asn1_oid_to_string(chunk
);
456 printf("OID:%#B", &chunk
);
461 printf("%s", oid_names
[oid
].name
);
464 case AC_GROUP_TYPE_OCTETS
:
465 printf("%#B", &chunk
);
470 groups
->destroy(groups
);
472 chunk
= ac
->get_authKeyIdentifier(ac
);
475 printf("authkey: %#B\n", &chunk
);
480 * Print certificate information
482 static void print_cert(certificate_t
*cert
, bool has_privkey
)
484 time_t now
, notAfter
, notBefore
;
489 printf("cert: %N\n", certificate_type_names
, cert
->get_type(cert
));
490 if (cert
->get_type(cert
) != CERT_X509_CRL
)
492 printf("subject: \"%Y\"\n", cert
->get_subject(cert
));
494 printf("issuer: \"%Y\"\n", cert
->get_issuer(cert
));
496 cert
->get_validity(cert
, &now
, ¬Before
, ¬After
);
497 printf("validity: not before %T, ", ¬Before
, FALSE
);
500 printf("not valid yet (valid in %V)\n", &now
, ¬Before
);
506 printf(" not after %T, ", ¬After
, FALSE
);
509 printf("expired (%V ago)\n", &now
, ¬After
);
513 printf("ok (expires in %V)\n", &now
, ¬After
);
516 switch (cert
->get_type(cert
))
519 print_x509((x509_t
*)cert
);
522 print_crl((crl_t
*)cert
);
525 print_ac((ac_t
*)cert
);
528 fprintf(stderr
, "parsing certificate subtype %N not implemented\n",
529 certificate_type_names
, cert
->get_type(cert
));
532 key
= cert
->get_public_key(cert
);
535 print_pubkey(key
, has_privkey
);
541 CALLBACK(list_cb
, void,
542 command_format_options_t
*format
, char *name
, vici_res_t
*res
)
544 if (*format
& COMMAND_FORMAT_RAW
)
546 vici_dump(res
, "list-cert event", *format
& COMMAND_FORMAT_PRETTY
,
551 certificate_type_t type
;
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
)
563 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, type
,
564 BUILD_BLOB_ASN1_DER
, chunk_create(buf
, len
),
568 if (*format
& COMMAND_FORMAT_PEM
)
574 print_cert(cert
, has_privkey
);
580 fprintf(stderr
, "parsing certificate failed\n");
585 fprintf(stderr
, "received incomplete certificate data\n");
590 static int list_certs(vici_conn_t
*conn
)
594 command_format_options_t format
= COMMAND_FORMAT_NONE
;
595 char *arg
, *subject
= NULL
, *type
= NULL
;
600 switch (command_getopt(&arg
))
603 return command_usage(NULL
);
611 format
|= COMMAND_FORMAT_PEM
;
614 format
|= COMMAND_FORMAT_PRETTY
;
615 /* fall through to raw */
617 format
|= COMMAND_FORMAT_RAW
;
622 return command_usage("invalid --list-certs option");
626 if (vici_register(conn
, "list-cert", list_cb
, &format
) != 0)
629 fprintf(stderr
, "registering for certificates failed: %s\n",
633 req
= vici_begin("list-certs");
636 vici_add_key_valuef(req
, "type", "%s", type
);
640 vici_add_key_valuef(req
, "subject", "%s", subject
);
642 res
= vici_submit(req
, conn
);
646 fprintf(stderr
, "list-certs request failed: %s\n", strerror(errno
));
649 if (format
& COMMAND_FORMAT_RAW
)
651 vici_dump(res
, "list-certs reply", format
& COMMAND_FORMAT_PRETTY
,
659 * Register the command.
661 static void __attribute__ ((constructor
))reg()
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] "
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"},