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>
32 #include <vici_version.h>
33 #include <vici_cert_info.h>
38 * Current certificate type info
40 static vici_cert_info_t
*current_cert_info
= NULL
;
43 * Print PEM encoding of a certificate
45 static void print_pem(certificate_t
*cert
)
49 if (cert
->get_encoding(cert
, CERT_PEM
, &encoding
))
51 printf("%.*s", (int)encoding
.len
, encoding
.ptr
);
56 fprintf(stderr
, "PEM encoding certificate failed\n");
61 * Print public key information
63 static void print_pubkey(public_key_t
*key
, bool has_privkey
)
67 printf("pubkey: %N %d bits", key_type_names
, key
->get_type(key
),
68 key
->get_keysize(key
));
71 printf(", has private key");
74 if (key
->get_fingerprint(key
, KEYID_PUBKEY_INFO_SHA1
, &chunk
))
76 printf("keyid: %#B\n", &chunk
);
78 if (key
->get_fingerprint(key
, KEYID_PUBKEY_SHA1
, &chunk
))
80 printf("subjkey: %#B\n", &chunk
);
85 * Print X509 specific certificate information
87 static void print_x509(x509_t
*x509
)
89 enumerator_t
*enumerator
;
91 traffic_selector_t
*block
;
95 int len
, explicit, inhibit
;
98 x509_cert_policy_t
*policy
;
99 x509_policy_mapping_t
*mapping
;
101 chunk
= chunk_skip_zero(x509
->get_serial(x509
));
102 printf("serial: %#B\n", &chunk
);
105 enumerator
= x509
->create_subjectAltName_enumerator(x509
);
106 while (enumerator
->enumerate(enumerator
, &id
))
110 printf("altNames: ");
123 enumerator
->destroy(enumerator
);
125 flags
= x509
->get_flags(x509
);
126 if (flags
!= X509_NONE
)
133 if (flags
& X509_CRL_SIGN
)
137 if (flags
& X509_OCSP_SIGNER
)
139 printf("ocspSigning ");
141 if (flags
& X509_SERVER_AUTH
)
143 printf("serverAuth ");
145 if (flags
& X509_CLIENT_AUTH
)
147 printf("clientAuth ");
149 if (flags
& X509_IKE_INTERMEDIATE
)
151 printf("ikeIntermediate ");
153 if (flags
& X509_MS_SMARTCARD_LOGON
)
155 printf("msSmartcardLogon");
157 if (flags
& X509_SELF_SIGNED
)
159 printf("self-signed ");
165 enumerator
= x509
->create_crl_uri_enumerator(x509
);
166 while (enumerator
->enumerate(enumerator
, &cdp
))
170 printf("CRL URIs: %s", cdp
->uri
);
175 printf(" %s", cdp
->uri
);
179 printf(" (CRL issuer: %Y)", cdp
->issuer
);
183 enumerator
->destroy(enumerator
);
186 enumerator
= x509
->create_ocsp_uri_enumerator(x509
);
187 while (enumerator
->enumerate(enumerator
, &uri
))
191 printf("OCSP URIs: %s\n", uri
);
196 printf(" %s\n", uri
);
199 enumerator
->destroy(enumerator
);
201 len
= x509
->get_constraint(x509
, X509_PATH_LEN
);
202 if (len
!= X509_NO_CONSTRAINT
)
204 printf("pathlen: %d\n", len
);
208 enumerator
= x509
->create_name_constraint_enumerator(x509
, TRUE
);
209 while (enumerator
->enumerate(enumerator
, &id
))
213 printf("Permitted NameConstraints:\n");
218 enumerator
->destroy(enumerator
);
220 enumerator
= x509
->create_name_constraint_enumerator(x509
, FALSE
);
221 while (enumerator
->enumerate(enumerator
, &id
))
225 printf("Excluded NameConstraints:\n");
230 enumerator
->destroy(enumerator
);
233 enumerator
= x509
->create_cert_policy_enumerator(x509
);
234 while (enumerator
->enumerate(enumerator
, &policy
))
240 printf("CertificatePolicies:\n");
243 oid
= asn1_oid_to_string(policy
->oid
);
246 printf(" %s\n", oid
);
251 printf(" %#B\n", &policy
->oid
);
255 printf(" CPS: %s\n", policy
->cps_uri
);
257 if (policy
->unotice_text
)
259 printf(" Notice: %s\n", policy
->unotice_text
);
263 enumerator
->destroy(enumerator
);
266 enumerator
= x509
->create_policy_mapping_enumerator(x509
);
267 while (enumerator
->enumerate(enumerator
, &mapping
))
269 char *issuer_oid
, *subject_oid
;
273 printf("PolicyMappings:\n");
276 issuer_oid
= asn1_oid_to_string(mapping
->issuer
);
277 subject_oid
= asn1_oid_to_string(mapping
->subject
);
278 printf(" %s => %s\n", issuer_oid
, subject_oid
);
282 enumerator
->destroy(enumerator
);
284 explicit = x509
->get_constraint(x509
, X509_REQUIRE_EXPLICIT_POLICY
);
285 inhibit
= x509
->get_constraint(x509
, X509_INHIBIT_POLICY_MAPPING
);
286 len
= x509
->get_constraint(x509
, X509_INHIBIT_ANY_POLICY
);
288 if (explicit != X509_NO_CONSTRAINT
|| inhibit
!= X509_NO_CONSTRAINT
||
289 len
!= X509_NO_CONSTRAINT
)
291 printf("PolicyConstraints:\n");
292 if (explicit != X509_NO_CONSTRAINT
)
294 printf(" requireExplicitPolicy: %d\n", explicit);
296 if (inhibit
!= X509_NO_CONSTRAINT
)
298 printf(" inhibitPolicyMapping: %d\n", inhibit
);
300 if (len
!= X509_NO_CONSTRAINT
)
302 printf(" inhibitAnyPolicy: %d\n", len
);
306 chunk
= x509
->get_authKeyIdentifier(x509
);
309 printf("authkeyId: %#B\n", &chunk
);
312 chunk
= x509
->get_subjectKeyIdentifier(x509
);
315 printf("subjkeyId: %#B\n", &chunk
);
317 if (x509
->get_flags(x509
) & X509_IP_ADDR_BLOCKS
)
320 printf("addresses: ");
321 enumerator
= x509
->create_ipAddrBlock_enumerator(x509
);
322 while (enumerator
->enumerate(enumerator
, &block
))
334 enumerator
->destroy(enumerator
);
340 * Print CRL specific information
342 static void print_crl(crl_t
*crl
)
344 enumerator_t
*enumerator
;
354 chunk
= chunk_skip_zero(crl
->get_serial(crl
));
355 printf("serial: %#B\n", &chunk
);
357 if (crl
->is_delta_crl(crl
, &chunk
))
359 chunk
= chunk_skip_zero(chunk
);
360 printf("delta CRL: for serial %#B\n", &chunk
);
362 chunk
= crl
->get_authKeyIdentifier(crl
);
363 printf("authKeyId: %#B\n", &chunk
);
366 enumerator
= crl
->create_delta_crl_uri_enumerator(crl
);
367 while (enumerator
->enumerate(enumerator
, &cdp
))
371 printf("freshest: %s", cdp
->uri
);
376 printf(" %s", cdp
->uri
);
380 printf(" (CRL issuer: %Y)", cdp
->issuer
);
384 enumerator
->destroy(enumerator
);
386 enumerator
= crl
->create_enumerator(crl
);
387 while (enumerator
->enumerate(enumerator
, &chunk
, &ts
, &reason
))
391 enumerator
->destroy(enumerator
);
393 printf("%d revoked certificate%s%s\n", count
,
394 count
== 1 ?
"" : "s", count ?
":" : "");
395 enumerator
= crl
->create_enumerator(crl
);
396 while (enumerator
->enumerate(enumerator
, &chunk
, &ts
, &reason
))
398 chunk
= chunk_skip_zero(chunk
);
399 localtime_r(&ts
, &tm
);
400 strftime(buf
, sizeof(buf
), "%F %T", &tm
);
401 printf(" %#B: %s, %N\n", &chunk
, buf
, crl_reason_names
, reason
);
404 enumerator
->destroy(enumerator
);
408 * Print AC specific information
410 static void print_ac(ac_t
*ac
)
412 ac_group_type_t type
;
413 identification_t
*id
;
414 enumerator_t
*groups
;
418 chunk
= chunk_skip_zero(ac
->get_serial(ac
));
419 printf("serial: %#B\n", &chunk
);
421 id
= ac
->get_holderIssuer(ac
);
424 printf("hissuer: \"%Y\"\n", id
);
426 chunk
= chunk_skip_zero(ac
->get_holderSerial(ac
));
429 printf("hserial: %#B\n", &chunk
);
431 groups
= ac
->create_group_enumerator(ac
);
432 while (groups
->enumerate(groups
, &type
, &chunk
))
448 case AC_GROUP_TYPE_STRING
:
449 printf("%.*s", (int)chunk
.len
, chunk
.ptr
);
451 case AC_GROUP_TYPE_OID
:
452 oid
= asn1_known_oid(chunk
);
453 if (oid
== OID_UNKNOWN
)
455 str
= asn1_oid_to_string(chunk
);
463 printf("OID:%#B", &chunk
);
468 printf("%s", oid_names
[oid
].name
);
471 case AC_GROUP_TYPE_OCTETS
:
472 printf("%#B", &chunk
);
477 groups
->destroy(groups
);
479 chunk
= ac
->get_authKeyIdentifier(ac
);
482 printf("authkey: %#B\n", &chunk
);
487 * Print certificate information
489 static void print_cert(certificate_t
*cert
, bool has_privkey
)
491 time_t now
, notAfter
, notBefore
;
496 if (cert
->get_type(cert
) != CERT_X509_CRL
&&
497 cert
->get_type(cert
) != CERT_X509_OCSP_RESPONSE
)
499 printf("subject: \"%Y\"\n", cert
->get_subject(cert
));
501 printf("issuer: \"%Y\"\n", cert
->get_issuer(cert
));
503 cert
->get_validity(cert
, &now
, ¬Before
, ¬After
);
504 printf("validity: not before %T, ", ¬Before
, FALSE
);
507 printf("not valid yet (valid in %V)\n", &now
, ¬Before
);
513 printf(" not after %T, ", ¬After
, FALSE
);
516 printf("expired (%V ago)\n", &now
, ¬After
);
520 printf("ok (expires in %V)\n", &now
, ¬After
);
523 switch (cert
->get_type(cert
))
526 print_x509((x509_t
*)cert
);
529 print_crl((crl_t
*)cert
);
532 print_ac((ac_t
*)cert
);
535 fprintf(stderr
, "parsing certificate subtype %N not implemented\n",
536 certificate_type_names
, cert
->get_type(cert
));
539 key
= cert
->get_public_key(cert
);
542 print_pubkey(key
, has_privkey
);
548 CALLBACK(list_cb
, void,
549 command_format_options_t
*format
, char *name
, vici_res_t
*res
)
552 vici_version_t version
;
553 vici_cert_info_t
*cert_info
;
554 bool has_privkey
, first
= FALSE
;
555 char *version_str
, *type_str
;
559 if (*format
& COMMAND_FORMAT_RAW
)
561 vici_dump(res
, "list-cert event", *format
& COMMAND_FORMAT_PRETTY
,
566 version_str
= vici_find_str(res
, "1.0", "vici");
567 if (!enum_from_name(vici_version_names
, version_str
, &version
) ||
570 fprintf(stderr
, "unsupported vici version '%s'\n", version_str
);
574 buf
= vici_find(res
, &len
, "data");
577 fprintf(stderr
, "received incomplete certificate data\n");
580 has_privkey
= streq(vici_find_str(res
, "no", "has_privkey"), "yes");
582 type_str
= vici_find_str(res
, "any", "type");
583 cert_info
= vici_cert_info_retrieve(type_str
);
584 if (!cert_info
|| cert_info
->type
== CERT_ANY
)
586 fprintf(stderr
, "unsupported certificate type '%s'\n", type_str
);
590 /* Detect change of certificate type */
591 if (cert_info
!= current_cert_info
)
594 current_cert_info
= cert_info
;
597 /* Parse certificate data blob */
598 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, cert_info
->type
,
599 BUILD_BLOB_ASN1_DER
, chunk_create(buf
, len
),
603 if (*format
& COMMAND_FORMAT_PEM
)
611 printf("List of %ss:\n\n", cert_info
->caption
);
613 print_cert(cert
, has_privkey
);
619 fprintf(stderr
, "parsing certificate failed\n");
623 static int list_certs(vici_conn_t
*conn
)
627 command_format_options_t format
= COMMAND_FORMAT_NONE
;
628 char *arg
, *subject
= NULL
, *type
= NULL
;
633 switch (command_getopt(&arg
))
636 return command_usage(NULL
);
644 format
|= COMMAND_FORMAT_PEM
;
647 format
|= COMMAND_FORMAT_PRETTY
;
648 /* fall through to raw */
650 format
|= COMMAND_FORMAT_RAW
;
655 return command_usage("invalid --list-certs option");
659 if (vici_register(conn
, "list-cert", list_cb
, &format
) != 0)
662 fprintf(stderr
, "registering for certificates failed: %s\n",
666 req
= vici_begin("list-certs");
667 vici_add_version(req
, VICI_VERSION
);
671 vici_add_key_valuef(req
, "type", "%s", type
);
675 vici_add_key_valuef(req
, "subject", "%s", subject
);
678 res
= vici_submit(req
, conn
);
682 fprintf(stderr
, "list-certs request failed: %s\n", strerror(errno
));
685 if (format
& COMMAND_FORMAT_RAW
)
687 vici_dump(res
, "list-certs reply", format
& COMMAND_FORMAT_PRETTY
,
695 * Register the command.
697 static void __attribute__ ((constructor
))reg()
699 command_register((command_t
) {
700 list_certs
, 'x', "list-certs", "list stored certificates",
701 {"[--subject <dn/san>] "
702 "[--type x509|x509ca|x509aa|x509ac|x509crl|x509ocsp|ocsp] "
703 "[--pem] [--raw|--pretty]"},
705 {"help", 'h', 0, "show usage information"},
706 {"subject", 's', 1, "filter by certificate subject"},
707 {"type", 't', 1, "filter by certificate type"},
708 {"pem", 'p', 0, "print PEM encoding of certificate"},
709 {"raw", 'r', 0, "dump raw response message"},
710 {"pretty", 'P', 0, "dump raw response message in pretty print"},