2 * Copyright (C) 2014 Martin Willi
3 * Copyright (C) 2014 revosec AG
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>.
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
21 #include <asn1/asn1.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>
32 * Print PEM encoding of a certificate
34 static void print_pem(certificate_t
*cert
)
38 if (cert
->get_encoding(cert
, CERT_PEM
, &encoding
))
40 printf("%.*s", (int)encoding
.len
, encoding
.ptr
);
45 fprintf(stderr
, "PEM encoding certificate failed\n");
50 * Print public key information
52 static void print_pubkey(public_key_t
*key
, bool has_privkey
)
56 printf("pubkey: %N %d bits", key_type_names
, key
->get_type(key
),
57 key
->get_keysize(key
));
60 printf(", has private key");
63 if (key
->get_fingerprint(key
, KEYID_PUBKEY_INFO_SHA1
, &chunk
))
65 printf("keyid: %#B\n", &chunk
);
67 if (key
->get_fingerprint(key
, KEYID_PUBKEY_SHA1
, &chunk
))
69 printf("subjkey: %#B\n", &chunk
);
74 * Print X509 specific certificate information
76 static void print_x509(x509_t
*x509
)
78 enumerator_t
*enumerator
;
80 traffic_selector_t
*block
;
84 int len
, explicit, inhibit
;
87 x509_cert_policy_t
*policy
;
88 x509_policy_mapping_t
*mapping
;
90 chunk
= chunk_skip_zero(x509
->get_serial(x509
));
91 printf("serial: %#B\n", &chunk
);
94 enumerator
= x509
->create_subjectAltName_enumerator(x509
);
95 while (enumerator
->enumerate(enumerator
, &id
))
112 enumerator
->destroy(enumerator
);
114 flags
= x509
->get_flags(x509
);
120 if (flags
& X509_CRL_SIGN
)
128 if (flags
& X509_OCSP_SIGNER
)
136 if (flags
& X509_SERVER_AUTH
)
138 printf("serverAuth ");
140 if (flags
& X509_CLIENT_AUTH
)
142 printf("clientAuth ");
144 if (flags
& X509_IKE_INTERMEDIATE
)
146 printf("iKEIntermediate ");
148 if (flags
& X509_SELF_SIGNED
)
150 printf("self-signed ");
155 enumerator
= x509
->create_crl_uri_enumerator(x509
);
156 while (enumerator
->enumerate(enumerator
, &cdp
))
160 printf("CRL URIs: %s", cdp
->uri
);
165 printf(" %s", cdp
->uri
);
169 printf(" (CRL issuer: %Y)", cdp
->issuer
);
173 enumerator
->destroy(enumerator
);
176 enumerator
= x509
->create_ocsp_uri_enumerator(x509
);
177 while (enumerator
->enumerate(enumerator
, &uri
))
181 printf("OCSP URIs: %s\n", uri
);
186 printf(" %s\n", uri
);
189 enumerator
->destroy(enumerator
);
191 len
= x509
->get_constraint(x509
, X509_PATH_LEN
);
192 if (len
!= X509_NO_CONSTRAINT
)
194 printf("pathlen: %d\n", len
);
198 enumerator
= x509
->create_name_constraint_enumerator(x509
, TRUE
);
199 while (enumerator
->enumerate(enumerator
, &id
))
203 printf("Permitted NameConstraints:\n");
208 enumerator
->destroy(enumerator
);
210 enumerator
= x509
->create_name_constraint_enumerator(x509
, FALSE
);
211 while (enumerator
->enumerate(enumerator
, &id
))
215 printf("Excluded NameConstraints:\n");
220 enumerator
->destroy(enumerator
);
223 enumerator
= x509
->create_cert_policy_enumerator(x509
);
224 while (enumerator
->enumerate(enumerator
, &policy
))
230 printf("CertificatePolicies:\n");
233 oid
= asn1_oid_to_string(policy
->oid
);
236 printf(" %s\n", oid
);
241 printf(" %#B\n", &policy
->oid
);
245 printf(" CPS: %s\n", policy
->cps_uri
);
247 if (policy
->unotice_text
)
249 printf(" Notice: %s\n", policy
->unotice_text
);
253 enumerator
->destroy(enumerator
);
256 enumerator
= x509
->create_policy_mapping_enumerator(x509
);
257 while (enumerator
->enumerate(enumerator
, &mapping
))
259 char *issuer_oid
, *subject_oid
;
263 printf("PolicyMappings:\n");
266 issuer_oid
= asn1_oid_to_string(mapping
->issuer
);
267 subject_oid
= asn1_oid_to_string(mapping
->subject
);
268 printf(" %s => %s\n", issuer_oid
, subject_oid
);
272 enumerator
->destroy(enumerator
);
274 explicit = x509
->get_constraint(x509
, X509_REQUIRE_EXPLICIT_POLICY
);
275 inhibit
= x509
->get_constraint(x509
, X509_INHIBIT_POLICY_MAPPING
);
276 len
= x509
->get_constraint(x509
, X509_INHIBIT_ANY_POLICY
);
278 if (explicit != X509_NO_CONSTRAINT
|| inhibit
!= X509_NO_CONSTRAINT
||
279 len
!= X509_NO_CONSTRAINT
)
281 printf("PolicyConstraints:\n");
282 if (explicit != X509_NO_CONSTRAINT
)
284 printf(" requireExplicitPolicy: %d\n", explicit);
286 if (inhibit
!= X509_NO_CONSTRAINT
)
288 printf(" inhibitPolicyMapping: %d\n", inhibit
);
290 if (len
!= X509_NO_CONSTRAINT
)
292 printf(" inhibitAnyPolicy: %d\n", len
);
296 chunk
= x509
->get_authKeyIdentifier(x509
);
299 printf("authkeyId: %#B\n", &chunk
);
302 chunk
= x509
->get_subjectKeyIdentifier(x509
);
305 printf("subjkeyId: %#B\n", &chunk
);
307 if (x509
->get_flags(x509
) & X509_IP_ADDR_BLOCKS
)
310 printf("addresses: ");
311 enumerator
= x509
->create_ipAddrBlock_enumerator(x509
);
312 while (enumerator
->enumerate(enumerator
, &block
))
324 enumerator
->destroy(enumerator
);
330 * Print CRL specific information
332 static void print_crl(crl_t
*crl
)
334 enumerator_t
*enumerator
;
344 chunk
= chunk_skip_zero(crl
->get_serial(crl
));
345 printf("serial: %#B\n", &chunk
);
347 if (crl
->is_delta_crl(crl
, &chunk
))
349 chunk
= chunk_skip_zero(chunk
);
350 printf("delta CRL: for serial %#B\n", &chunk
);
352 chunk
= crl
->get_authKeyIdentifier(crl
);
353 printf("authKeyId: %#B\n", &chunk
);
356 enumerator
= crl
->create_delta_crl_uri_enumerator(crl
);
357 while (enumerator
->enumerate(enumerator
, &cdp
))
361 printf("freshest: %s", cdp
->uri
);
366 printf(" %s", cdp
->uri
);
370 printf(" (CRL issuer: %Y)", cdp
->issuer
);
374 enumerator
->destroy(enumerator
);
376 enumerator
= crl
->create_enumerator(crl
);
377 while (enumerator
->enumerate(enumerator
, &chunk
, &ts
, &reason
))
381 enumerator
->destroy(enumerator
);
383 printf("%d revoked certificate%s%s\n", count
,
384 count
== 1 ?
"" : "s", count ?
":" : "");
385 enumerator
= crl
->create_enumerator(crl
);
386 while (enumerator
->enumerate(enumerator
, &chunk
, &ts
, &reason
))
388 chunk
= chunk_skip_zero(chunk
);
389 localtime_r(&ts
, &tm
);
390 strftime(buf
, sizeof(buf
), "%F %T", &tm
);
391 printf(" %#B %N %s\n", &chunk
, crl_reason_names
, reason
, buf
);
394 enumerator
->destroy(enumerator
);
398 * Print AC specific information
400 static void print_ac(ac_t
*ac
)
402 ac_group_type_t type
;
403 identification_t
*id
;
404 enumerator_t
*groups
;
408 chunk
= chunk_skip_zero(ac
->get_serial(ac
));
409 printf("serial: %#B\n", &chunk
);
411 id
= ac
->get_holderIssuer(ac
);
414 printf("hissuer: \"%Y\"\n", id
);
416 chunk
= chunk_skip_zero(ac
->get_holderSerial(ac
));
419 printf("hserial: %#B\n", &chunk
);
421 groups
= ac
->create_group_enumerator(ac
);
422 while (groups
->enumerate(groups
, &type
, &chunk
))
438 case AC_GROUP_TYPE_STRING
:
439 printf("%.*s", (int)chunk
.len
, chunk
.ptr
);
441 case AC_GROUP_TYPE_OID
:
442 oid
= asn1_known_oid(chunk
);
443 if (oid
== OID_UNKNOWN
)
445 str
= asn1_oid_to_string(chunk
);
453 printf("OID:%#B", &chunk
);
458 printf("%s", oid_names
[oid
].name
);
461 case AC_GROUP_TYPE_OCTETS
:
462 printf("%#B", &chunk
);
467 groups
->destroy(groups
);
469 chunk
= ac
->get_authKeyIdentifier(ac
);
472 printf("authkey: %#B\n", &chunk
);
477 * Print certificate information
479 static void print_cert(certificate_t
*cert
, bool has_privkey
)
481 time_t now
, notAfter
, notBefore
;
486 printf("cert: %N\n", certificate_type_names
, cert
->get_type(cert
));
487 if (cert
->get_type(cert
) != CERT_X509_CRL
)
489 printf("subject: \"%Y\"\n", cert
->get_subject(cert
));
491 printf("issuer: \"%Y\"\n", cert
->get_issuer(cert
));
493 cert
->get_validity(cert
, &now
, ¬Before
, ¬After
);
494 printf("validity: not before %T, ", ¬Before
, FALSE
);
497 printf("not valid yet (valid in %V)\n", &now
, ¬Before
);
503 printf(" not after %T, ", ¬After
, FALSE
);
506 printf("expired (%V ago)\n", &now
, ¬After
);
510 printf("ok (expires in %V)\n", &now
, ¬After
);
513 switch (cert
->get_type(cert
))
516 print_x509((x509_t
*)cert
);
519 print_crl((crl_t
*)cert
);
522 print_ac((ac_t
*)cert
);
525 fprintf(stderr
, "parsing certificate subtype %N not implemented\n",
526 certificate_type_names
, cert
->get_type(cert
));
529 key
= cert
->get_public_key(cert
);
532 print_pubkey(key
, has_privkey
);
538 CALLBACK(list_cb
, void,
539 command_format_options_t
*format
, char *name
, vici_res_t
*res
)
541 if (*format
& COMMAND_FORMAT_RAW
)
543 vici_dump(res
, "list-cert event", *format
& COMMAND_FORMAT_PRETTY
,
548 certificate_type_t type
;
554 buf
= vici_find(res
, &len
, "data");
555 has_privkey
= streq(vici_find_str(res
, "no", "has_privkey"), "yes");
556 if (enum_from_name(certificate_type_names
,
557 vici_find_str(res
, "ANY", "type"), &type
) &&
558 type
!= CERT_ANY
&& buf
)
560 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, type
,
561 BUILD_BLOB_ASN1_DER
, chunk_create(buf
, len
),
565 if (*format
& COMMAND_FORMAT_PEM
)
571 print_cert(cert
, has_privkey
);
577 fprintf(stderr
, "parsing certificate failed\n");
582 fprintf(stderr
, "received incomplete certificate data\n");
587 static int list_certs(vici_conn_t
*conn
)
591 command_format_options_t format
= COMMAND_FORMAT_NONE
;
592 char *arg
, *subject
= NULL
, *type
= NULL
;
597 switch (command_getopt(&arg
))
600 return command_usage(NULL
);
608 format
|= COMMAND_FORMAT_PEM
;
611 format
|= COMMAND_FORMAT_PRETTY
;
612 /* fall through to raw */
614 format
|= COMMAND_FORMAT_RAW
;
619 return command_usage("invalid --list-certs option");
623 if (vici_register(conn
, "list-cert", list_cb
, &format
) != 0)
626 fprintf(stderr
, "registering for certificates failed: %s\n",
630 req
= vici_begin("list-certs");
633 vici_add_key_valuef(req
, "type", "%s", type
);
637 vici_add_key_valuef(req
, "subject", "%s", subject
);
639 res
= vici_submit(req
, conn
);
643 fprintf(stderr
, "list-certs request failed: %s\n", strerror(errno
));
646 if (format
& COMMAND_FORMAT_RAW
)
648 vici_dump(res
, "list-certs reply", format
& COMMAND_FORMAT_PRETTY
,
656 * Register the command.
658 static void __attribute__ ((constructor
))reg()
660 command_register((command_t
) {
661 list_certs
, 'x', "list-certs", "list stored certificates",
662 {"[--subject <dn/san>] [--type X509|X509_AC|X509_CRL] [--pem] "
665 {"help", 'h', 0, "show usage information"},
666 {"subject", 's', 1, "filter by certificate subject"},
667 {"type", 't', 1, "filter by certificate type"},
668 {"pem", 'p', 0, "print PEM encoding of certificate"},
669 {"raw", 'r', 0, "dump raw response message"},
670 {"pretty", 'P', 0, "dump raw response message in pretty print"},