2 * Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <hxtool-commands.h>
39 #include <parse_time.h>
41 static hx509_context context
;
43 static char *stat_file_string
;
44 static int version_flag
;
47 struct getargs args
[] = {
48 { "statistic-file", 0, arg_string
, &stat_file_string
, NULL
, NULL
},
49 { "version", 0, arg_flag
, &version_flag
, NULL
, NULL
},
50 { "help", 0, arg_flag
, &help_flag
, NULL
, NULL
}
52 int num_args
= sizeof(args
) / sizeof(args
[0]);
57 arg_printusage(args
, num_args
, NULL
, "command");
58 printf("Use \"%s help\" to get more help\n", getprogname());
67 lock_strings(hx509_lock lock
, getarg_strings
*pass
)
70 for (i
= 0; i
< pass
->num_strings
; i
++) {
71 int ret
= hx509_lock_command_string(lock
, pass
->strings
[i
]);
73 errx(1, "hx509_lock_command_string: %s: %d",
74 pass
->strings
[i
], ret
);
79 fix_store_name(hx509_context contextp
, const char *sn
, const char *def_type
)
81 const char *residue
= strchr(sn
, ':');
86 s
[residue
- sn
] = '\0';
87 if (_hx509_ks_type(contextp
, s
)) {
94 if (asprintf(&s
, "%s:%s", def_type
, sn
) == -1 || s
== NULL
)
95 err(1, "Out of memory");
100 fix_csr_name(const char *cn
, const char *def_type
)
104 if (strncmp(cn
, "PKCS10:", sizeof("PKCS10:") - 1) == 0 || strchr(cn
, ':'))
106 if (asprintf(&s
, "%s:%s", def_type
, cn
) == -1 || s
== NULL
)
107 err(1, "Out of memory");
116 certs_strings(hx509_context contextp
, const char *type
, hx509_certs certs
,
117 hx509_lock lock
, const getarg_strings
*s
)
121 for (i
= 0; i
< s
->num_strings
; i
++) {
122 char *sn
= fix_store_name(contextp
, s
->strings
[i
], "FILE");
124 ret
= hx509_certs_append(contextp
, certs
, lock
, sn
);
126 hx509_err(contextp
, 1, ret
,
127 "hx509_certs_append: %s %s", type
, sn
);
137 parse_oid(const char *str
, const heim_oid
*def
, heim_oid
*oid
)
142 const heim_oid
*found
= NULL
;
144 ret
= der_find_heim_oid_by_name(str
, &found
);
146 ret
= der_copy_oid(found
, oid
);
148 ret
= der_parse_heim_oid(str
, " .", oid
);
150 ret
= der_copy_oid(def
, oid
);
153 errx(1, "parse_oid failed for: %s", str
? str
: "default oid");
161 peer_strings(hx509_context contextp
,
162 hx509_peer_info
*peer
,
163 const getarg_strings
*s
)
165 AlgorithmIdentifier
*val
;
168 ret
= hx509_peer_info_alloc(contextp
, peer
);
170 hx509_err(contextp
, 1, ret
, "hx509_peer_info_alloc");
172 val
= calloc(s
->num_strings
, sizeof(*val
));
176 for (i
= 0; i
< s
->num_strings
; i
++)
177 parse_oid(s
->strings
[i
], NULL
, &val
[i
].algorithm
);
179 ret
= hx509_peer_info_set_cms_algs(contextp
, *peer
, val
, s
->num_strings
);
181 hx509_err(contextp
, 1, ret
, "hx509_peer_info_set_cms_algs");
183 for (i
= 0; i
< s
->num_strings
; i
++)
184 free_AlgorithmIdentifier(&val
[i
]);
193 heim_octet_string
*os
;
198 pem_reader(hx509_context contextp
, const char *type
,
199 const hx509_pem_header
*headers
,
200 const void *data
, size_t length
, void *ctx
)
202 struct pem_data
*p
= (struct pem_data
*)ctx
;
205 p
->os
->data
= malloc(length
);
206 if (p
->os
->data
== NULL
)
208 memcpy(p
->os
->data
, data
, length
);
209 p
->os
->length
= length
;
211 h
= hx509_pem_find_header(headers
, "Content-disposition");
212 if (h
&& strcasecmp(h
, "detached") == 0)
213 p
->detached_data
= 1;
223 cms_verify_sd(struct cms_verify_sd_options
*opt
, int argc
, char **argv
)
225 hx509_verify_ctx ctx
= NULL
;
227 heim_octet_string c
, co
, signeddata
, *sd
= NULL
;
228 hx509_certs store
= NULL
;
229 hx509_certs signers
= NULL
;
230 hx509_certs anchors
= NULL
;
237 if (opt
->missing_revoke_flag
)
238 hx509_context_set_missing_revoke(context
, 1);
240 hx509_lock_init(context
, &lock
);
241 lock_strings(lock
, &opt
->pass_strings
);
243 ret
= hx509_verify_init_ctx(context
, &ctx
);
245 hx509_err(context
, 1, ret
, "hx509_verify_init_ctx");
247 ret
= hx509_certs_init(context
, "MEMORY:cms-anchors", 0, NULL
, &anchors
);
249 hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
250 ret
= hx509_certs_init(context
, "MEMORY:cert-store", 0, NULL
, &store
);
252 hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
254 certs_strings(context
, "anchors", anchors
, lock
, &opt
->anchors_strings
);
255 certs_strings(context
, "store", store
, lock
, &opt
->certificate_strings
);
262 pd
.detached_data
= 0;
264 f
= fopen(argv
[0], "r");
266 err(1, "Failed to open file %s", argv
[0]);
268 ret
= hx509_pem_read(context
, f
, pem_reader
, &pd
);
271 errx(1, "PEM reader failed: %d", ret
);
273 if (pd
.detached_data
&& opt
->signed_content_string
== NULL
) {
274 char *r
= strrchr(argv
[0], '.');
275 if (r
&& strcasecmp(r
, ".pem") == 0) {
276 char *s
= strdup(argv
[0]);
278 errx(1, "malloc: out of memory");
279 s
[r
- argv
[0]] = '\0';
280 ret
= _hx509_map_file_os(s
, &signeddata
);
282 errx(1, "map_file: %s: %d", s
, ret
);
289 ret
= rk_undumpdata(argv
[0], &p
, &sz
);
291 err(1, "map_file: %s: %d", argv
[0], ret
);
297 if (opt
->signed_content_string
) {
298 ret
= _hx509_map_file_os(opt
->signed_content_string
, &signeddata
);
300 errx(1, "map_file: %s: %d", opt
->signed_content_string
, ret
);
304 if (opt
->content_info_flag
) {
305 heim_octet_string uwco
;
308 ret
= hx509_cms_unwrap_ContentInfo(&co
, &oid
, &uwco
, NULL
);
310 errx(1, "hx509_cms_unwrap_ContentInfo: %d", ret
);
312 if (der_heim_oid_cmp(&oid
, &asn1_oid_id_pkcs7_signedData
) != 0)
313 errx(1, "Content is not SignedData");
317 der_free_octet_string(&co
);
325 hx509_verify_attach_anchors(ctx
, anchors
);
327 if (!opt
->signer_allowed_flag
)
328 flags
|= HX509_CMS_VS_ALLOW_ZERO_SIGNER
;
329 if (opt
->allow_wrong_oid_flag
)
330 flags
|= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH
;
332 ret
= hx509_cms_verify_signed(context
, ctx
, flags
, co
.data
, co
.length
, sd
,
333 store
, &type
, &c
, &signers
);
335 der_free_octet_string(&co
);
339 hx509_err(context
, 1, ret
, "hx509_cms_verify_signed");
343 if (opt
->oid_sym_flag
)
344 der_print_heim_oid_sym(&type
, '.', &str
);
346 der_print_heim_oid(&type
, '.', &str
);
347 printf("type: %s\n", str
);
351 if (signers
== NULL
) {
352 printf("unsigned\n");
354 printf("signers:\n");
355 hx509_certs_iter_f(context
, signers
, hx509_ci_print_names
, stdout
);
358 hx509_verify_destroy_ctx(ctx
);
360 hx509_certs_free(&store
);
361 hx509_certs_free(&signers
);
362 hx509_certs_free(&anchors
);
364 hx509_lock_free(lock
);
367 ret
= _hx509_write_file(argv
[1], c
.data
, c
.length
);
369 errx(1, "hx509_write_file: %d", ret
);
372 der_free_octet_string(&c
);
375 _hx509_unmap_file_os(sd
);
380 static int HX509_LIB_CALL
381 print_signer(hx509_context contextp
, void *ctx
, hx509_cert cert
)
383 hx509_pem_header
**header
= ctx
;
384 char *signer_name
= NULL
;
388 ret
= hx509_cert_get_subject(cert
, &name
);
390 errx(1, "hx509_cert_get_subject");
392 ret
= hx509_name_to_string(name
, &signer_name
);
393 hx509_name_free(&name
);
395 errx(1, "hx509_name_to_string");
397 hx509_pem_add_header(header
, "Signer", signer_name
);
404 cms_create_sd(struct cms_create_sd_options
*opt
, int argc
, char **argv
)
406 heim_oid contentType
;
407 hx509_peer_info peer
= NULL
;
411 hx509_certs store
, pool
, anchors
, signer
= NULL
;
415 char *infile
, *outfile
= NULL
;
417 memset(&contentType
, 0, sizeof(contentType
));
422 ret
= asprintf(&outfile
, "%s.%s", infile
,
423 opt
->pem_flag
? "pem" : "cms-signeddata");
424 if (ret
== -1 || outfile
== NULL
)
425 errx(1, "out of memory");
429 hx509_lock_init(context
, &lock
);
430 lock_strings(lock
, &opt
->pass_strings
);
432 ret
= hx509_certs_init(context
, "MEMORY:cert-store", 0, NULL
, &store
);
433 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
434 ret
= hx509_certs_init(context
, "MEMORY:cert-pool", 0, NULL
, &pool
);
435 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
437 certs_strings(context
, "store", store
, lock
, &opt
->certificate_strings
);
438 certs_strings(context
, "pool", pool
, lock
, &opt
->pool_strings
);
440 if (opt
->anchors_strings
.num_strings
) {
441 ret
= hx509_certs_init(context
, "MEMORY:cert-anchors",
443 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
444 certs_strings(context
, "anchors", anchors
, lock
, &opt
->anchors_strings
);
448 if (opt
->detached_signature_flag
)
449 flags
|= HX509_CMS_SIGNATURE_DETACHED
;
450 if (opt
->id_by_name_flag
)
451 flags
|= HX509_CMS_SIGNATURE_ID_NAME
;
452 if (!opt
->signer_flag
) {
453 flags
|= HX509_CMS_SIGNATURE_NO_SIGNER
;
457 if (opt
->signer_flag
) {
458 ret
= hx509_query_alloc(context
, &q
);
460 errx(1, "hx509_query_alloc: %d", ret
);
462 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
463 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
465 if (opt
->signer_string
)
466 hx509_query_match_friendly_name(q
, opt
->signer_string
);
468 ret
= hx509_certs_filter(context
, store
, q
, &signer
);
469 hx509_query_free(context
, q
);
471 hx509_err(context
, 1, ret
, "hx509_certs_find");
473 if (!opt
->embedded_certs_flag
)
474 flags
|= HX509_CMS_SIGNATURE_NO_CERTS
;
475 if (opt
->embed_leaf_only_flag
)
476 flags
|= HX509_CMS_SIGNATURE_LEAF_ONLY
;
478 ret
= rk_undumpdata(infile
, &p
, &sz
);
480 err(1, "map_file: %s: %d", infile
, ret
);
482 if (opt
->peer_alg_strings
.num_strings
)
483 peer_strings(context
, &peer
, &opt
->peer_alg_strings
);
485 parse_oid(opt
->content_type_string
, &asn1_oid_id_pkcs7_data
, &contentType
);
487 ret
= hx509_cms_create_signed(context
,
499 hx509_err(context
, 1, ret
, "hx509_cms_create_signed: %d", ret
);
501 hx509_certs_free(&anchors
);
502 hx509_certs_free(&pool
);
503 hx509_certs_free(&store
);
505 hx509_lock_free(lock
);
506 hx509_peer_info_free(peer
);
507 der_free_oid(&contentType
);
509 if (opt
->content_info_flag
) {
510 heim_octet_string wo
;
512 ret
= hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData
, &o
, &wo
);
514 errx(1, "hx509_cms_wrap_ContentInfo: %d", ret
);
516 der_free_octet_string(&o
);
521 hx509_pem_header
*header
= NULL
;
524 hx509_pem_add_header(&header
, "Content-disposition",
525 opt
->detached_signature_flag
?
526 "detached" : "inline");
528 ret
= hx509_certs_iter_f(context
, signer
, print_signer
, header
);
530 hx509_err(context
, 1, ret
, "print signer");
533 f
= fopen(outfile
, "w");
535 err(1, "open %s", outfile
);
537 ret
= hx509_pem_write(context
, "CMS SIGNEDDATA", header
, f
,
540 hx509_pem_free_header(header
);
542 errx(1, "hx509_pem_write: %d", ret
);
545 ret
= _hx509_write_file(outfile
, o
.data
, o
.length
);
547 errx(1, "hx509_write_file: %d", ret
);
550 hx509_certs_free(&signer
);
557 cms_unenvelope(struct cms_unenvelope_options
*opt
, int argc
, char **argv
)
559 heim_oid contentType
= { 0, NULL
};
560 heim_octet_string o
, co
;
568 hx509_lock_init(context
, &lock
);
569 lock_strings(lock
, &opt
->pass_strings
);
571 ret
= rk_undumpdata(argv
[0], &p
, &sz
);
573 err(1, "map_file: %s: %d", argv
[0], ret
);
578 if (opt
->content_info_flag
) {
579 heim_octet_string uwco
;
582 ret
= hx509_cms_unwrap_ContentInfo(&co
, &oid
, &uwco
, NULL
);
584 errx(1, "hx509_cms_unwrap_ContentInfo: %d", ret
);
586 if (der_heim_oid_cmp(&oid
, &asn1_oid_id_pkcs7_envelopedData
) != 0)
587 errx(1, "Content is not SignedData");
593 ret
= hx509_certs_init(context
, "MEMORY:cert-store", 0, NULL
, &certs
);
595 errx(1, "hx509_certs_init: MEMORY: %d", ret
);
597 certs_strings(context
, "store", certs
, lock
, &opt
->certificate_strings
);
599 if (opt
->allow_weak_crypto_flag
)
600 flags
|= HX509_CMS_UE_ALLOW_WEAK
;
602 ret
= hx509_cms_unenvelope(context
, certs
, flags
, co
.data
, co
.length
,
603 NULL
, 0, &contentType
, &o
);
605 der_free_octet_string(&co
);
607 hx509_err(context
, 1, ret
, "hx509_cms_unenvelope");
610 hx509_lock_free(lock
);
611 hx509_certs_free(&certs
);
612 der_free_oid(&contentType
);
614 ret
= _hx509_write_file(argv
[1], o
.data
, o
.length
);
616 errx(1, "hx509_write_file: %d", ret
);
618 der_free_octet_string(&o
);
624 cms_create_enveloped(struct cms_envelope_options
*opt
, int argc
, char **argv
)
626 heim_oid contentType
;
628 const heim_oid
*enctype
= NULL
;
638 memset(&contentType
, 0, sizeof(contentType
));
640 hx509_lock_init(context
, &lock
);
641 lock_strings(lock
, &opt
->pass_strings
);
643 ret
= rk_undumpdata(argv
[0], &p
, &sz
);
645 err(1, "map_file: %s: %d", argv
[0], ret
);
647 ret
= hx509_certs_init(context
, "MEMORY:cert-store", 0, NULL
, &certs
);
648 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
650 certs_strings(context
, "store", certs
, lock
, &opt
->certificate_strings
);
652 if (opt
->allow_weak_crypto_flag
)
653 flags
|= HX509_CMS_EV_ALLOW_WEAK
;
655 if (opt
->encryption_type_string
) {
656 enctype
= hx509_crypto_enctype_by_name(opt
->encryption_type_string
);
658 errx(1, "encryption type: %s no found",
659 opt
->encryption_type_string
);
662 ret
= hx509_query_alloc(context
, &q
);
664 errx(1, "hx509_query_alloc: %d", ret
);
666 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_ENCIPHERMENT
);
668 ret
= hx509_certs_find(context
, certs
, q
, &cert
);
669 hx509_query_free(context
, q
);
671 errx(1, "hx509_certs_find: %d", ret
);
673 parse_oid(opt
->content_type_string
, &asn1_oid_id_pkcs7_data
, &contentType
);
675 ret
= hx509_cms_envelope_1(context
, flags
, cert
, p
, sz
, enctype
,
678 errx(1, "hx509_cms_envelope_1: %d", ret
);
680 hx509_cert_free(cert
);
681 hx509_certs_free(&certs
);
683 der_free_oid(&contentType
);
685 if (opt
->content_info_flag
) {
686 heim_octet_string wo
;
688 ret
= hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_envelopedData
, &o
, &wo
);
690 errx(1, "hx509_cms_wrap_ContentInfo: %d", ret
);
692 der_free_octet_string(&o
);
696 hx509_lock_free(lock
);
698 ret
= _hx509_write_file(argv
[1], o
.data
, o
.length
);
700 errx(1, "hx509_write_file: %d", ret
);
702 der_free_octet_string(&o
);
708 print_certificate(hx509_context hxcontext
, hx509_cert cert
, int verbose
)
713 fn
= hx509_cert_get_friendly_name(cert
);
715 printf(" friendly name: %s\n", fn
);
716 printf(" private key: %s\n",
717 _hx509_cert_private_key(cert
) ? "yes" : "no");
719 ret
= hx509_print_cert(hxcontext
, cert
, stdout
);
721 errx(1, "failed to print cert");
724 hx509_validate_ctx vctx
;
726 hx509_validate_ctx_init(hxcontext
, &vctx
);
727 hx509_validate_ctx_set_print(vctx
, hx509_print_stdout
, stdout
);
728 hx509_validate_ctx_add_flags(vctx
, HX509_VALIDATE_F_VALIDATE
);
729 hx509_validate_ctx_add_flags(vctx
, HX509_VALIDATE_F_VERBOSE
);
731 hx509_validate_cert(hxcontext
, vctx
, cert
);
733 hx509_validate_ctx_free(vctx
);
743 static int HX509_LIB_CALL
744 print_f(hx509_context hxcontext
, void *ctx
, hx509_cert cert
)
746 struct print_s
*s
= ctx
;
748 printf("cert: %d\n", s
->counter
++);
749 print_certificate(context
, cert
, s
->verbose
);
754 static int HX509_LIB_CALL
755 print_fjson(hx509_context hxcontext
, void *ctx
, hx509_cert cert
)
757 #ifdef ASN1_PRINTING_WORKS
758 const Certificate
*c
= NULL
;
761 c
= _hx509_get_cert(cert
);
763 json
= print_Certificate(c
, ASN1_PRINT_INDENT
);
765 printf("%s\n", json
);
767 hx509_err(context
, 1, errno
, "Could not format certificate as JSON");
771 err(1, "JSON printing of certificates not supported; try enabling or "
772 "not disabling ASN.1 templating in Heimdal build configuration");
778 pcert_print(struct print_options
*opt
, int argc
, char **argv
)
785 s
.verbose
= opt
->content_flag
;
787 hx509_lock_init(context
, &lock
);
788 lock_strings(lock
, &opt
->pass_strings
);
791 char *sn
= fix_store_name(context
, argv
[0], "FILE");
794 ret
= hx509_certs_init(context
, sn
, 0, lock
, &certs
);
797 if (opt
->never_fail_flag
) {
798 printf("ignoreing failure: %d\n", ret
);
801 hx509_err(context
, 1, ret
, "hx509_certs_init");
803 if (opt
->raw_json_flag
) {
804 hx509_certs_iter_f(context
, certs
, print_fjson
, &s
);
807 hx509_certs_info(context
, certs
, NULL
, NULL
);
808 hx509_certs_iter_f(context
, certs
, print_f
, &s
);
810 hx509_certs_free(&certs
);
814 hx509_lock_free(lock
);
820 static int HX509_LIB_CALL
821 validate_f(hx509_context hxcontext
, void *ctx
, hx509_cert c
)
823 hx509_validate_cert(hxcontext
, ctx
, c
);
828 pcert_validate(struct validate_options
*opt
, int argc
, char **argv
)
830 hx509_validate_ctx ctx
;
834 hx509_lock_init(context
, &lock
);
835 lock_strings(lock
, &opt
->pass_strings
);
837 hx509_validate_ctx_init(context
, &ctx
);
838 hx509_validate_ctx_set_print(ctx
, hx509_print_stdout
, stdout
);
839 hx509_validate_ctx_add_flags(ctx
, HX509_VALIDATE_F_VALIDATE
);
842 char *sn
= fix_store_name(context
, argv
[0], "FILE");
845 ret
= hx509_certs_init(context
, sn
, 0, lock
, &certs
);
847 errx(1, "hx509_certs_init: %d", ret
);
848 hx509_certs_iter_f(context
, certs
, validate_f
, ctx
);
849 hx509_certs_free(&certs
);
852 hx509_validate_ctx_free(ctx
);
854 hx509_lock_free(lock
);
860 certificate_copy(struct certificate_copy_options
*opt
, int argc
, char **argv
)
863 hx509_lock inlock
, outlock
= NULL
;
867 hx509_lock_init(context
, &inlock
);
868 lock_strings(inlock
, &opt
->in_pass_strings
);
870 if (opt
->out_pass_string
) {
871 hx509_lock_init(context
, &outlock
);
872 ret
= hx509_lock_command_string(outlock
, opt
->out_pass_string
);
874 errx(1, "hx509_lock_command_string: %s: %d",
875 opt
->out_pass_string
, ret
);
878 sn
= fix_store_name(context
, argv
[argc
- 1], "FILE");
879 ret
= hx509_certs_init(context
, sn
,
880 HX509_CERTS_CREATE
, inlock
, &certs
);
882 hx509_err(context
, 1, ret
, "hx509_certs_init %s", sn
);
888 sn
= fix_store_name(context
, argv
[0], "FILE");
889 retx
= hx509_certs_append(context
, certs
, inlock
, sn
);
891 hx509_err(context
, 1, retx
, "hx509_certs_append %s", sn
);
896 ret
= hx509_certs_store(context
, certs
, 0, outlock
);
898 hx509_err(context
, 1, ret
, "hx509_certs_store");
900 hx509_certs_free(&certs
);
901 hx509_lock_free(inlock
);
902 hx509_lock_free(outlock
);
908 hx509_verify_ctx ctx
;
910 const char *hostname
;
915 static int HX509_LIB_CALL
916 verify_f(hx509_context hxcontext
, void *ctx
, hx509_cert c
)
918 struct verify
*v
= ctx
;
921 ret
= hx509_verify_path(hxcontext
, v
->ctx
, c
, v
->chain
);
923 char *s
= hx509_get_error_string(hxcontext
, ret
);
924 printf("verify_path: %s: %d\n", s
, ret
);
925 hx509_free_error_string(s
);
933 ret
= hx509_verify_hostname(hxcontext
, c
, 0, HX509_HN_HOSTNAME
,
934 v
->hostname
, NULL
, 0);
936 printf("verify_hostname: %d\n", ret
);
945 pcert_verify(struct verify_options
*opt
, int argc
, char **argv
)
947 hx509_certs anchors
, chain
, certs
;
948 hx509_revoke_ctx revoke_ctx
;
949 hx509_verify_ctx ctx
;
953 memset(&v
, 0, sizeof(v
));
955 if (opt
->missing_revoke_flag
)
956 hx509_context_set_missing_revoke(context
, 1);
958 ret
= hx509_verify_init_ctx(context
, &ctx
);
960 hx509_err(context
, 1, ret
, "hx509_verify_init_ctx");
961 ret
= hx509_certs_init(context
, "MEMORY:anchors", 0, NULL
, &anchors
);
963 hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
964 ret
= hx509_certs_init(context
, "MEMORY:chain", 0, NULL
, &chain
);
966 hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
967 ret
= hx509_certs_init(context
, "MEMORY:certs", 0, NULL
, &certs
);
969 hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
971 if (opt
->allow_proxy_certificate_flag
)
972 hx509_verify_set_proxy_certificate(ctx
, 1);
974 if (opt
->time_string
) {
979 memset(&tm
, 0, sizeof(tm
));
981 p
= strptime (opt
->time_string
, "%Y-%m-%d", &tm
);
983 errx(1, "Failed to parse time %s, need to be on format %%Y-%%m-%%d",
988 hx509_verify_set_time(ctx
, t
);
991 if (opt
->hostname_string
)
992 v
.hostname
= opt
->hostname_string
;
993 if (opt
->max_depth_integer
)
994 hx509_verify_set_max_depth(ctx
, opt
->max_depth_integer
);
996 ret
= hx509_revoke_init(context
, &revoke_ctx
);
998 errx(1, "hx509_revoke_init: %d", ret
);
1001 const char *s
= *argv
++;
1004 if (strncmp(s
, "chain:", 6) == 0) {
1007 sn
= fix_store_name(context
, s
, "FILE");
1008 ret
= hx509_certs_append(context
, chain
, NULL
, sn
);
1010 hx509_err(context
, 1, ret
, "hx509_certs_append: chain: %s: %d",
1013 } else if (strncmp(s
, "anchor:", 7) == 0) {
1016 sn
= fix_store_name(context
, s
, "FILE");
1017 ret
= hx509_certs_append(context
, anchors
, NULL
, sn
);
1019 hx509_err(context
, 1, ret
,
1020 "hx509_certs_append: anchor: %s: %d", sn
, ret
);
1022 } else if (strncmp(s
, "cert:", 5) == 0) {
1025 sn
= fix_store_name(context
, s
, "FILE");
1026 ret
= hx509_certs_append(context
, certs
, NULL
, sn
);
1028 hx509_err(context
, 1, ret
, "hx509_certs_append: certs: %s: %d",
1031 } else if (strncmp(s
, "crl:", 4) == 0) {
1034 ret
= hx509_revoke_add_crl(context
, revoke_ctx
, s
);
1036 errx(1, "hx509_revoke_add_crl: %s: %d", s
, ret
);
1038 } else if (strncmp(s
, "ocsp:", 5) == 0) {
1041 ret
= hx509_revoke_add_ocsp(context
, revoke_ctx
, s
);
1043 errx(1, "hx509_revoke_add_ocsp: %s: %d", s
, ret
);
1046 errx(1, "unknown option to verify: `%s'\n", s
);
1051 hx509_verify_attach_anchors(ctx
, anchors
);
1052 hx509_verify_attach_revoke(ctx
, revoke_ctx
);
1057 hx509_certs_iter_f(context
, certs
, verify_f
, &v
);
1059 hx509_verify_destroy_ctx(ctx
);
1061 hx509_certs_free(&certs
);
1062 hx509_certs_free(&chain
);
1063 hx509_certs_free(&anchors
);
1065 hx509_revoke_free(&revoke_ctx
);
1069 printf("no certs verify at all\n");
1074 printf("failed verifing %d checks\n", v
.errors
);
1082 query(struct query_options
*opt
, int argc
, char **argv
)
1090 ret
= hx509_query_alloc(context
, &q
);
1092 errx(1, "hx509_query_alloc: %d", ret
);
1094 hx509_lock_init(context
, &lock
);
1095 lock_strings(lock
, &opt
->pass_strings
);
1097 ret
= hx509_certs_init(context
, "MEMORY:cert-store", 0, NULL
, &certs
);
1098 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
1101 char *sn
= fix_store_name(context
, argv
[0], "FILE");
1103 ret
= hx509_certs_append(context
, certs
, lock
, sn
);
1105 errx(1, "hx509_certs_append: %s: %d", sn
, ret
);
1112 if (opt
->friendlyname_string
)
1113 hx509_query_match_friendly_name(q
, opt
->friendlyname_string
);
1115 if (opt
->eku_string
) {
1118 parse_oid(opt
->eku_string
, NULL
, &oid
);
1120 ret
= hx509_query_match_eku(q
, &oid
);
1122 errx(1, "hx509_query_match_eku: %d", ret
);
1126 if (opt
->private_key_flag
)
1127 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
1129 if (opt
->keyEncipherment_flag
)
1130 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_ENCIPHERMENT
);
1132 if (opt
->digitalSignature_flag
)
1133 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
1135 if (opt
->expr_string
)
1136 hx509_query_match_expr(context
, q
, opt
->expr_string
);
1138 ret
= hx509_certs_find(context
, certs
, q
, &c
);
1139 hx509_query_free(context
, q
);
1141 printf("no match found (%d)\n", ret
);
1143 printf("match found\n");
1144 if (opt
->print_flag
)
1145 print_certificate(context
, c
, 0);
1149 hx509_certs_free(&certs
);
1151 hx509_lock_free(lock
);
1157 ocsp_fetch(struct ocsp_fetch_options
*opt
, int argc
, char **argv
)
1159 hx509_certs reqcerts
, pool
;
1160 heim_octet_string req
, nonce_data
, *nonce
= &nonce_data
;
1164 const char *url
= "/";
1166 memset(&nonce
, 0, sizeof(nonce
));
1168 hx509_lock_init(context
, &lock
);
1169 lock_strings(lock
, &opt
->pass_strings
);
1172 if (!opt
->nonce_flag
)
1175 if (opt
->url_path_string
)
1176 url
= opt
->url_path_string
;
1178 ret
= hx509_certs_init(context
, "MEMORY:ocsp-pool", 0, NULL
, &pool
);
1179 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
1181 certs_strings(context
, "ocsp-pool", pool
, lock
, &opt
->pool_strings
);
1185 ret
= hx509_certs_init(context
, "MEMORY:ocsp-req", 0, NULL
, &reqcerts
);
1186 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
1188 for (i
= 1; i
< argc
; i
++) {
1189 char *sn
= fix_store_name(context
, argv
[i
], "FILE");
1191 ret
= hx509_certs_append(context
, reqcerts
, lock
, sn
);
1193 errx(1, "hx509_certs_append: req: %s: %d", sn
, ret
);
1197 ret
= hx509_ocsp_request(context
, reqcerts
, pool
, NULL
, NULL
, &req
, nonce
);
1199 errx(1, "hx509_ocsp_request: req: %d", ret
);
1204 f
= fopen(file
, "w");
1209 "POST %s HTTP/1.0\r\n"
1210 "Content-Type: application/ocsp-request\r\n"
1211 "Content-Length: %ld\r\n"
1214 (unsigned long)req
.length
);
1215 fwrite(req
.data
, req
.length
, 1, f
);
1220 der_free_octet_string(nonce
);
1222 hx509_certs_free(&reqcerts
);
1223 hx509_certs_free(&pool
);
1229 ocsp_print(struct ocsp_print_options
*opt
, int argc
, char **argv
)
1231 hx509_revoke_ocsp_print(context
, argv
[0], stdout
);
1236 revoke_print(struct revoke_print_options
*opt
, int argc
, char **argv
)
1238 hx509_revoke_ctx revoke_ctx
;
1241 ret
= hx509_revoke_init(context
, &revoke_ctx
);
1243 errx(1, "hx509_revoke_init: %d", ret
);
1248 if (strncmp(s
, "crl:", 4) == 0) {
1251 ret
= hx509_revoke_add_crl(context
, revoke_ctx
, s
);
1253 errx(1, "hx509_revoke_add_crl: %s: %d", s
, ret
);
1255 } else if (strncmp(s
, "ocsp:", 5) == 0) {
1258 ret
= hx509_revoke_add_ocsp(context
, revoke_ctx
, s
);
1260 errx(1, "hx509_revoke_add_ocsp: %s: %d", s
, ret
);
1263 errx(1, "unknown option to verify: `%s'\n", s
);
1267 ret
= hx509_revoke_print(context
, revoke_ctx
, stdout
);
1269 warnx("hx509_revoke_print: %d", ret
);
1278 static int HX509_LIB_CALL
1279 verify_o(hx509_context hxcontext
, void *ctx
, hx509_cert c
)
1281 heim_octet_string
*os
= ctx
;
1285 ret
= hx509_ocsp_verify(context
, 0, c
, 0,
1286 os
->data
, os
->length
, &expiration
);
1288 char *s
= hx509_get_error_string(hxcontext
, ret
);
1289 printf("ocsp_verify: %s: %d\n", s
, ret
);
1290 hx509_free_error_string(s
);
1292 printf("expire: %d\n", (int)expiration
);
1299 ocsp_verify(struct ocsp_verify_options
*opt
, int argc
, char **argv
)
1304 heim_octet_string os
;
1306 hx509_lock_init(context
, &lock
);
1308 if (opt
->ocsp_file_string
== NULL
)
1309 errx(1, "no ocsp file given");
1311 ret
= _hx509_map_file_os(opt
->ocsp_file_string
, &os
);
1313 err(1, "map_file: %s: %d", argv
[0], ret
);
1315 ret
= hx509_certs_init(context
, "MEMORY:test-certs", 0, NULL
, &certs
);
1316 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
1318 for (i
= 0; i
< argc
; i
++) {
1319 char *sn
= fix_store_name(context
, argv
[i
], "FILE");
1321 ret
= hx509_certs_append(context
, certs
, lock
, sn
);
1323 hx509_err(context
, 1, ret
, "hx509_certs_append: %s", sn
);
1327 ret
= hx509_certs_iter_f(context
, certs
, verify_o
, &os
);
1329 hx509_certs_free(&certs
);
1330 _hx509_unmap_file_os(&os
);
1331 hx509_lock_free(lock
);
1337 read_private_key(const char *fn
, hx509_private_key
*key
)
1339 hx509_private_key
*keys
;
1341 char *sn
= fix_store_name(context
, fn
, "FILE");
1346 ret
= hx509_certs_init(context
, sn
, 0, NULL
, &certs
);
1348 hx509_err(context
, 1, ret
, "hx509_certs_init: %s", sn
);
1350 ret
= _hx509_certs_keys_get(context
, certs
, &keys
);
1351 hx509_certs_free(&certs
);
1353 hx509_err(context
, 1, ret
, "hx509_certs_keys_get");
1354 if (keys
[0] == NULL
)
1355 errx(1, "no keys in key store: %s", sn
);
1358 *key
= _hx509_private_key_ref(keys
[0]);
1359 _hx509_certs_keys_free(context
, keys
);
1365 get_key(const char *fn
, const char *type
, int optbits
,
1366 hx509_private_key
*signer
)
1371 struct hx509_generate_private_context
*gen_ctx
;
1373 if (strcasecmp(type
, "rsa") != 0)
1374 errx(1, "can only handle rsa keys for now");
1376 ret
= _hx509_generate_private_key_init(context
,
1377 ASN1_OID_ID_PKCS1_RSAENCRYPTION
,
1380 ret
= _hx509_generate_private_key_bits(context
, gen_ctx
, optbits
);
1382 ret
= _hx509_generate_private_key(context
, gen_ctx
, signer
);
1384 hx509_err(context
, 1, ret
, "failed to generate private key of type %s", type
);
1387 char *sn
= fix_store_name(context
, fn
, "FILE");
1388 hx509_certs certs
= NULL
;
1389 hx509_cert cert
= NULL
;
1391 cert
= hx509_cert_init_private_key(context
, *signer
, NULL
);
1393 ret
= hx509_certs_init(context
, sn
,
1394 HX509_CERTS_CREATE
|
1395 HX509_CERTS_UNPROTECT_ALL
,
1398 ret
= hx509_certs_add(context
, certs
, cert
);
1400 ret
= hx509_certs_store(context
, certs
, 0, NULL
);
1402 hx509_err(context
, 1, ret
, "failed to store generated private "
1406 hx509_certs_free(&certs
);
1408 hx509_cert_free(cert
);
1413 err(1, "no private key");
1414 ret
= read_private_key(fn
, signer
);
1416 hx509_err(context
, 1, ret
, "failed to read private key from %s",
1422 generate_key(struct generate_key_options
*opt
, int argc
, char **argv
)
1424 hx509_private_key signer
;
1425 const char *type
= opt
->type_string
? opt
->type_string
: "rsa";
1426 int bits
= opt
->key_bits_integer
? opt
->key_bits_integer
: 2048;
1428 get_key(argv
[0], type
, bits
, &signer
);
1429 hx509_private_key_free(&signer
);
1434 request_create(struct request_create_options
*opt
, int argc
, char **argv
)
1436 heim_octet_string request
;
1439 hx509_private_key signer
;
1440 SubjectPublicKeyInfo key
;
1441 const char *outfile
= argv
[0];
1443 memset(&key
, 0, sizeof(key
));
1445 get_key(opt
->key_string
,
1446 opt
->generate_key_string
,
1447 opt
->key_bits_integer
,
1450 hx509_request_init(context
, &req
);
1452 if (opt
->subject_string
) {
1453 hx509_name name
= NULL
;
1455 ret
= hx509_parse_name(context
, opt
->subject_string
, &name
);
1457 errx(1, "hx509_parse_name: %d\n", ret
);
1458 hx509_request_set_name(context
, req
, name
);
1460 if (opt
->verbose_flag
) {
1462 hx509_name_to_string(name
, &s
);
1466 hx509_name_free(&name
);
1469 for (i
= 0; i
< opt
->email_strings
.num_strings
; i
++) {
1470 ret
= hx509_request_add_email(context
, req
,
1471 opt
->email_strings
.strings
[i
]);
1473 hx509_err(context
, 1, ret
, "hx509_request_add_email");
1476 for (i
= 0; i
< opt
->jid_strings
.num_strings
; i
++) {
1477 ret
= hx509_request_add_xmpp_name(context
, req
,
1478 opt
->jid_strings
.strings
[i
]);
1480 hx509_err(context
, 1, ret
, "hx509_request_add_xmpp_name");
1483 for (i
= 0; i
< opt
->dnsname_strings
.num_strings
; i
++) {
1484 ret
= hx509_request_add_dns_name(context
, req
,
1485 opt
->dnsname_strings
.strings
[i
]);
1487 hx509_err(context
, 1, ret
, "hx509_request_add_dns_name");
1490 for (i
= 0; i
< opt
->kerberos_strings
.num_strings
; i
++) {
1491 ret
= hx509_request_add_pkinit(context
, req
,
1492 opt
->kerberos_strings
.strings
[i
]);
1494 hx509_err(context
, 1, ret
, "hx509_request_add_pkinit");
1497 for (i
= 0; i
< opt
->ms_kerberos_strings
.num_strings
; i
++) {
1498 ret
= hx509_request_add_ms_upn_name(context
, req
,
1499 opt
->ms_kerberos_strings
.strings
[i
]);
1501 hx509_err(context
, 1, ret
, "hx509_request_add_ms_upn_name");
1504 for (i
= 0; i
< opt
->registered_strings
.num_strings
; i
++) {
1507 parse_oid(opt
->registered_strings
.strings
[i
], NULL
, &oid
);
1508 ret
= hx509_request_add_registered(context
, req
, &oid
);
1511 hx509_err(context
, 1, ret
, "hx509_request_add_registered");
1514 for (i
= 0; i
< opt
->eku_strings
.num_strings
; i
++) {
1517 parse_oid(opt
->eku_strings
.strings
[i
], NULL
, &oid
);
1518 ret
= hx509_request_add_eku(context
, req
, &oid
);
1521 hx509_err(context
, 1, ret
, "hx509_request_add_eku");
1525 ret
= hx509_private_key2SPKI(context
, signer
, &key
);
1527 errx(1, "hx509_private_key2SPKI: %d\n", ret
);
1529 ret
= hx509_request_set_SubjectPublicKeyInfo(context
,
1532 free_SubjectPublicKeyInfo(&key
);
1534 hx509_err(context
, 1, ret
, "hx509_request_set_SubjectPublicKeyInfo");
1536 ret
= hx509_request_to_pkcs10(context
,
1541 hx509_err(context
, 1, ret
, "hx509_request_to_pkcs10");
1543 hx509_private_key_free(&signer
);
1544 hx509_request_free(&req
);
1547 rk_dumpdata(outfile
, request
.data
, request
.length
);
1548 der_free_octet_string(&request
);
1554 request_print(struct request_print_options
*opt
, int argc
, char **argv
)
1558 printf("request print\n");
1560 for (i
= 0; i
< argc
; i
++) {
1562 char *cn
= fix_csr_name(argv
[i
], "PKCS10");
1564 ret
= hx509_request_parse(context
, cn
, &req
);
1566 hx509_err(context
, 1, ret
, "parse_request: %s", cn
);
1568 ret
= hx509_request_print(context
, req
, stdout
);
1569 hx509_request_free(&req
);
1571 hx509_err(context
, 1, ret
, "Failed to print file %s", cn
);
1579 info(void *opt
, int argc
, char **argv
)
1582 ENGINE_add_conf_module();
1585 const RSA_METHOD
*m
= RSA_get_default_method();
1587 printf("rsa: %s\n", m
->name
);
1590 const DH_METHOD
*m
= DH_get_default_method();
1592 printf("dh: %s\n", m
->name
);
1594 #ifdef HAVE_HCRYPTO_W_OPENSSL
1596 printf("ecdsa: ECDSA_METHOD-not-export\n");
1600 printf("ecdsa: hcrypto null\n");
1604 int ret
= RAND_status();
1605 printf("rand: %s\n", ret
== 1 ? "ok" : "not available");
1612 random_data(void *opt
, int argc
, char **argv
)
1617 len
= parse_bytes(argv
[0], "byte");
1619 fprintf(stderr
, "bad argument to random-data\n");
1625 fprintf(stderr
, "out of memory\n");
1629 ret
= RAND_bytes(ptr
, len
);
1632 fprintf(stderr
, "did not get cryptographic strong random\n");
1636 fwrite(ptr
, len
, 1, stdout
);
1645 crypto_available(struct crypto_available_options
*opt
, int argc
, char **argv
)
1647 AlgorithmIdentifier
*val
;
1648 unsigned int len
, i
;
1649 int ret
, type
= HX509_SELECT_ALL
;
1651 if (opt
->type_string
) {
1652 if (strcmp(opt
->type_string
, "all") == 0)
1653 type
= HX509_SELECT_ALL
;
1654 else if (strcmp(opt
->type_string
, "digest") == 0)
1655 type
= HX509_SELECT_DIGEST
;
1656 else if (strcmp(opt
->type_string
, "public-sig") == 0)
1657 type
= HX509_SELECT_PUBLIC_SIG
;
1658 else if (strcmp(opt
->type_string
, "secret") == 0)
1659 type
= HX509_SELECT_SECRET_ENC
;
1661 errx(1, "unknown type: %s", opt
->type_string
);
1664 ret
= hx509_crypto_available(context
, type
, NULL
, &val
, &len
);
1666 errx(1, "hx509_crypto_available");
1668 for (i
= 0; i
< len
; i
++) {
1670 if (opt
->oid_syms_flag
)
1671 der_print_heim_oid_sym(&val
[i
].algorithm
, '.', &s
);
1673 der_print_heim_oid(&val
[i
].algorithm
, '.', &s
);
1678 hx509_crypto_free_algs(val
, len
);
1684 crypto_select(struct crypto_select_options
*opt
, int argc
, char **argv
)
1686 hx509_peer_info peer
= NULL
;
1687 AlgorithmIdentifier selected
;
1688 int ret
, type
= HX509_SELECT_DIGEST
;
1691 if (opt
->type_string
) {
1692 if (strcmp(opt
->type_string
, "digest") == 0)
1693 type
= HX509_SELECT_DIGEST
;
1694 else if (strcmp(opt
->type_string
, "public-sig") == 0)
1695 type
= HX509_SELECT_PUBLIC_SIG
;
1696 else if (strcmp(opt
->type_string
, "secret") == 0)
1697 type
= HX509_SELECT_SECRET_ENC
;
1699 errx(1, "unknown type: %s", opt
->type_string
);
1702 if (opt
->peer_cmstype_strings
.num_strings
)
1703 peer_strings(context
, &peer
, &opt
->peer_cmstype_strings
);
1705 ret
= hx509_crypto_select(context
, type
, NULL
, peer
, &selected
);
1707 errx(1, "hx509_crypto_available");
1709 if (opt
->oid_sym_flag
)
1710 der_print_heim_oid_sym(&selected
.algorithm
, '.', &s
);
1712 der_print_heim_oid(&selected
.algorithm
, '.', &s
);
1715 free_AlgorithmIdentifier(&selected
);
1717 hx509_peer_info_free(peer
);
1723 hxtool_hex(struct hex_options
*opt
, int argc
, char **argv
)
1726 if (opt
->decode_flag
) {
1727 char buf
[1024], buf2
[1024], *p
;
1730 while(fgets(buf
, sizeof(buf
), stdin
) != NULL
) {
1731 buf
[strcspn(buf
, "\r\n")] = '\0';
1733 while(isspace(*(unsigned char *)p
))
1735 len
= hex_decode(p
, buf2
, strlen(p
));
1737 errx(1, "hex_decode failed");
1738 if (fwrite(buf2
, 1, len
, stdout
) != (size_t)len
)
1739 errx(1, "fwrite failed");
1745 while((len
= fread(buf
, 1, sizeof(buf
), stdin
)) != 0) {
1746 len
= hex_encode(buf
, len
, &p
);
1749 fprintf(stdout
, "%s\n", p
);
1756 struct cert_type_opt
{
1762 https_server(hx509_context contextp
, hx509_ca_tbs tbs
, struct cert_type_opt
*opt
)
1764 return hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkix_kp_serverAuth
);
1768 https_negotiate_server(hx509_context contextp
, hx509_ca_tbs tbs
, struct cert_type_opt
*opt
)
1770 int ret
= hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkekuoid
);
1772 ret
= hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkix_kp_serverAuth
);
1778 https_client(hx509_context contextp
, hx509_ca_tbs tbs
, struct cert_type_opt
*opt
)
1780 return hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkix_kp_clientAuth
);
1784 peap_server(hx509_context contextp
, hx509_ca_tbs tbs
, struct cert_type_opt
*opt
)
1786 return hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkix_kp_serverAuth
);
1790 pkinit_kdc(hx509_context contextp
, hx509_ca_tbs tbs
, struct cert_type_opt
*opt
)
1793 return hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkkdcekuoid
);
1797 pkinit_client(hx509_context contextp
, hx509_ca_tbs tbs
, struct cert_type_opt
*opt
)
1803 ret
= hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkekuoid
);
1807 ret
= hx509_ca_tbs_add_eku(context
, tbs
, &asn1_oid_id_pkix_kp_clientAuth
);
1811 return hx509_ca_tbs_add_eku(context
, tbs
, &asn1_oid_id_pkinit_ms_eku
);
1815 email_client(hx509_context contextp
, hx509_ca_tbs tbs
, struct cert_type_opt
*opt
)
1817 return hx509_ca_tbs_add_eku(contextp
, tbs
, &asn1_oid_id_pkix_kp_emailProtection
);
1823 int (*eval
)(hx509_context
, hx509_ca_tbs
, struct cert_type_opt
*);
1827 "Used for HTTPS server and many other TLS server certificate types",
1832 "Used for HTTPS client certificates",
1837 "Certificate will be use for email",
1842 "Certificate used for Kerberos PK-INIT client certificates",
1847 "Certificates used for Kerberos PK-INIT KDC certificates",
1851 "https-negotiate-server",
1852 "Used for HTTPS server and many other TLS server certificate types",
1853 https_negotiate_server
1857 "Certificate used for Radius PEAP (Protected EAP)",
1863 print_eval_types(FILE *out
)
1868 table
= rtbl_create();
1869 rtbl_add_column_by_id (table
, 0, "Name", 0);
1870 rtbl_add_column_by_id (table
, 1, "Description", 0);
1872 for (i
= 0; i
< sizeof(certtypes
)/sizeof(certtypes
[0]); i
++) {
1873 rtbl_add_column_entry_by_id(table
, 0, certtypes
[i
].type
);
1874 rtbl_add_column_entry_by_id(table
, 1, certtypes
[i
].desc
);
1877 rtbl_format (table
, out
);
1878 rtbl_destroy (table
);
1882 eval_types(hx509_context contextp
,
1884 const struct certificate_sign_options
*opt
)
1886 struct cert_type_opt ctopt
;
1891 memset(&ctopt
, 0, sizeof(ctopt
));
1893 for (i
= 0; i
< opt
->type_strings
.num_strings
; i
++) {
1894 const char *type
= opt
->type_strings
.strings
[i
];
1896 for (j
= 0; j
< sizeof(certtypes
)/sizeof(certtypes
[0]); j
++) {
1897 if (strcasecmp(type
, certtypes
[j
].type
) == 0) {
1898 ret
= (*certtypes
[j
].eval
)(contextp
, tbs
, &ctopt
);
1900 hx509_err(contextp
, 1, ret
,
1901 "Failed to evaluate cert type %s", type
);
1905 if (j
>= sizeof(certtypes
)/sizeof(certtypes
[0])) {
1906 fprintf(stderr
, "Unknown certificate type %s\n\n", type
);
1907 fprintf(stderr
, "Available types:\n");
1908 print_eval_types(stderr
);
1913 for (i
= 0; i
< opt
->pk_init_principal_strings
.num_strings
; i
++) {
1914 const char *pk_init_princ
= opt
->pk_init_principal_strings
.strings
[i
];
1917 errx(1, "pk-init principal given but no pk-init oid");
1919 ret
= hx509_ca_tbs_add_san_pkinit(contextp
, tbs
, pk_init_princ
);
1921 hx509_err(contextp
, 1, ret
, "hx509_ca_tbs_add_san_pkinit");
1924 if (opt
->ms_upn_string
) {
1926 errx(1, "MS upn given but no pk-init oid");
1928 ret
= hx509_ca_tbs_add_san_ms_upn(contextp
, tbs
, opt
->ms_upn_string
);
1930 hx509_err(contextp
, 1, ret
, "hx509_ca_tbs_add_san_ms_upn");
1934 for (i
= 0; i
< opt
->hostname_strings
.num_strings
; i
++) {
1935 const char *hostname
= opt
->hostname_strings
.strings
[i
];
1937 ret
= hx509_ca_tbs_add_san_hostname(contextp
, tbs
, hostname
);
1939 hx509_err(contextp
, 1, ret
, "hx509_ca_tbs_add_san_hostname");
1942 for (i
= 0; i
< opt
->dnssrv_strings
.num_strings
; i
++) {
1943 const char *dnssrv
= opt
->dnssrv_strings
.strings
[i
];
1945 ret
= hx509_ca_tbs_add_san_dnssrv(contextp
, tbs
, dnssrv
);
1947 hx509_err(contextp
, 1, ret
, "hx509_ca_tbs_add_san_dnssrv");
1950 for (i
= 0; i
< opt
->email_strings
.num_strings
; i
++) {
1951 const char *email
= opt
->email_strings
.strings
[i
];
1953 ret
= hx509_ca_tbs_add_san_rfc822name(contextp
, tbs
, email
);
1955 hx509_err(contextp
, 1, ret
, "hx509_ca_tbs_add_san_hostname");
1957 ret
= hx509_ca_tbs_add_eku(contextp
, tbs
,
1958 &asn1_oid_id_pkix_kp_emailProtection
);
1960 hx509_err(contextp
, 1, ret
, "hx509_ca_tbs_add_eku");
1963 if (opt
->jid_string
) {
1964 ret
= hx509_ca_tbs_add_san_jid(contextp
, tbs
, opt
->jid_string
);
1966 hx509_err(contextp
, 1, ret
, "hx509_ca_tbs_add_san_jid");
1973 hxtool_ca(struct certificate_sign_options
*opt
, int argc
, char **argv
)
1977 hx509_cert signer
= NULL
, cert
= NULL
;
1978 hx509_private_key private_key
= NULL
;
1979 hx509_private_key cert_key
= NULL
;
1980 hx509_name subject
= NULL
;
1981 SubjectPublicKeyInfo spki
;
1986 memset(&oid
, 0, sizeof(oid
));
1987 memset(&spki
, 0, sizeof(spki
));
1989 if (opt
->ca_certificate_string
== NULL
&& !opt
->self_signed_flag
)
1990 errx(1, "--ca-certificate argument missing (not using --self-signed)");
1991 if (opt
->ca_private_key_string
== NULL
&& opt
->generate_key_string
== NULL
&& opt
->self_signed_flag
)
1992 errx(1, "--ca-private-key argument missing (using --self-signed)");
1993 if (opt
->certificate_string
== NULL
)
1994 errx(1, "--certificate argument missing");
1996 if (opt
->template_certificate_string
&& opt
->template_fields_string
== NULL
)
1997 errx(1, "--template-certificate used but no --template-fields given");
1999 if (opt
->lifetime_string
) {
2000 delta
= parse_time(opt
->lifetime_string
, "day");
2002 errx(1, "Invalid lifetime: %s", opt
->lifetime_string
);
2005 if (opt
->ca_certificate_string
) {
2006 hx509_certs cacerts
= NULL
;
2008 char *sn
= fix_store_name(context
, opt
->ca_certificate_string
, "FILE");
2010 ret
= hx509_certs_init(context
, sn
, 0, NULL
, &cacerts
);
2012 hx509_err(context
, 1, ret
, "hx509_certs_init: %s", sn
);
2014 ret
= hx509_query_alloc(context
, &q
);
2016 errx(1, "hx509_query_alloc: %d", ret
);
2018 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
2019 if (!opt
->issue_proxy_flag
)
2020 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_KEYCERTSIGN
);
2022 ret
= hx509_certs_find(context
, cacerts
, q
, &signer
);
2023 hx509_query_free(context
, q
);
2024 hx509_certs_free(&cacerts
);
2026 hx509_err(context
, 1, ret
, "no CA certificate found");
2028 } else if (opt
->self_signed_flag
) {
2029 if (opt
->generate_key_string
== NULL
2030 && opt
->ca_private_key_string
== NULL
)
2031 errx(1, "no signing private key");
2033 if (opt
->req_string
)
2034 errx(1, "can't be self-signing and have a request at the same time");
2036 errx(1, "missing ca key");
2038 if (opt
->ca_private_key_string
) {
2040 ret
= read_private_key(opt
->ca_private_key_string
, &private_key
);
2042 err(1, "read_private_key");
2044 ret
= hx509_private_key2SPKI(context
, private_key
, &spki
);
2046 errx(1, "hx509_private_key2SPKI: %d\n", ret
);
2048 if (opt
->self_signed_flag
)
2049 cert_key
= private_key
;
2052 if (opt
->req_string
) {
2054 char *cn
= fix_csr_name(opt
->req_string
, "PKCS10");
2057 * Extract the CN and other attributes we want to preserve from the
2058 * requested subjectName and then set them in the hx509_env for the
2061 ret
= hx509_request_parse(context
, cn
, &req
);
2063 hx509_err(context
, 1, ret
, "parse_request: %s", cn
);
2064 ret
= hx509_request_get_name(context
, req
, &subject
);
2066 hx509_err(context
, 1, ret
, "get name");
2067 ret
= hx509_request_get_SubjectPublicKeyInfo(context
, req
, &spki
);
2069 hx509_err(context
, 1, ret
, "get spki");
2070 hx509_request_free(&req
);
2074 if (opt
->generate_key_string
) {
2075 struct hx509_generate_private_context
*keyctx
;
2077 ret
= _hx509_generate_private_key_init(context
,
2078 &asn1_oid_id_pkcs1_rsaEncryption
,
2081 hx509_err(context
, 1, ret
, "generate private key");
2083 if (opt
->issue_ca_flag
)
2084 _hx509_generate_private_key_is_ca(context
, keyctx
);
2086 if (opt
->key_bits_integer
)
2087 _hx509_generate_private_key_bits(context
, keyctx
,
2088 opt
->key_bits_integer
);
2090 ret
= _hx509_generate_private_key(context
, keyctx
,
2092 _hx509_generate_private_key_free(&keyctx
);
2094 hx509_err(context
, 1, ret
, "generate private key");
2096 ret
= hx509_private_key2SPKI(context
, cert_key
, &spki
);
2098 errx(1, "hx509_private_key2SPKI: %d\n", ret
);
2100 if (opt
->self_signed_flag
)
2101 private_key
= cert_key
;
2104 if (opt
->certificate_private_key_string
) {
2105 ret
= read_private_key(opt
->certificate_private_key_string
, &cert_key
);
2107 err(1, "read_private_key for certificate");
2110 if (opt
->subject_string
) {
2112 hx509_name_free(&subject
);
2113 ret
= hx509_parse_name(context
, opt
->subject_string
, &subject
);
2115 hx509_err(context
, 1, ret
, "hx509_parse_name");
2122 ret
= hx509_ca_tbs_init(context
, &tbs
);
2124 hx509_err(context
, 1, ret
, "hx509_ca_tbs_init");
2126 for (i
= 0; i
< opt
->eku_strings
.num_strings
; i
++) {
2127 parse_oid(opt
->eku_strings
.strings
[i
], NULL
, &oid
);
2128 ret
= hx509_ca_tbs_add_eku(context
, tbs
, &oid
);
2130 hx509_err(context
, 1, ret
, "hx509_request_add_eku");
2133 if (opt
->ku_strings
.num_strings
) {
2134 const struct units
*kus
= asn1_KeyUsage_units();
2135 const struct units
*kup
;
2138 for (i
= 0; i
< opt
->ku_strings
.num_strings
; i
++) {
2139 for (kup
= kus
; kup
->name
; kup
++) {
2140 if (strcmp(kup
->name
, opt
->ku_strings
.strings
[i
]))
2146 ret
= hx509_ca_tbs_add_ku(context
, tbs
, int2KeyUsage(n
));
2148 hx509_err(context
, 1, ret
, "hx509_request_add_ku");
2150 if (opt
->signature_algorithm_string
) {
2151 const AlgorithmIdentifier
*sigalg
;
2152 if (strcasecmp(opt
->signature_algorithm_string
, "rsa-with-sha1") == 0)
2153 sigalg
= hx509_signature_rsa_with_sha1();
2154 else if (strcasecmp(opt
->signature_algorithm_string
, "rsa-with-sha256") == 0)
2155 sigalg
= hx509_signature_rsa_with_sha256();
2157 errx(1, "unsupported sigature algorithm");
2158 hx509_ca_tbs_set_signature_algorithm(context
, tbs
, sigalg
);
2161 if (opt
->template_certificate_string
) {
2162 hx509_cert
template;
2164 char *sn
= fix_store_name(context
, opt
->template_certificate_string
,
2168 ret
= hx509_certs_init(context
, sn
, 0, NULL
, &tcerts
);
2170 hx509_err(context
, 1, ret
, "hx509_certs_init: %s", sn
);
2172 ret
= hx509_get_one_cert(context
, tcerts
, &template);
2174 hx509_certs_free(&tcerts
);
2176 hx509_err(context
, 1, ret
, "no template certificate found");
2178 flags
= parse_units(opt
->template_fields_string
,
2179 hx509_ca_tbs_template_units(), "");
2181 ret
= hx509_ca_tbs_set_template(context
, tbs
, flags
, template);
2183 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_template");
2185 hx509_cert_free(template);
2189 if (opt
->serial_number_string
) {
2190 heim_integer serialNumber
;
2192 ret
= der_parse_hex_heim_integer(opt
->serial_number_string
,
2195 err(1, "der_parse_hex_heim_integer");
2196 ret
= hx509_ca_tbs_set_serialnumber(context
, tbs
, &serialNumber
);
2198 hx509_err(context
, 1, ret
, "hx509_ca_tbs_init");
2199 der_free_heim_integer(&serialNumber
);
2202 if (spki
.subjectPublicKey
.length
) {
2203 ret
= hx509_ca_tbs_set_spki(context
, tbs
, &spki
);
2205 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_spki");
2209 ret
= hx509_ca_tbs_set_subject(context
, tbs
, subject
);
2211 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_subject");
2214 if (opt
->crl_uri_string
) {
2215 ret
= hx509_ca_tbs_add_crl_dp_uri(context
, tbs
,
2216 opt
->crl_uri_string
, NULL
);
2218 hx509_err(context
, 1, ret
, "hx509_ca_tbs_add_crl_dp_uri");
2221 eval_types(context
, tbs
, opt
);
2223 if (opt
->permanent_id_string
) {
2224 ret
= hx509_ca_tbs_add_san_permanentIdentifier_string(context
, tbs
,
2225 opt
->permanent_id_string
);
2227 hx509_err(context
, 1, ret
, "hx509_ca_tbs_add_san_permanentIdentifier");
2230 if (opt
->hardware_module_name_string
) {
2231 ret
= hx509_ca_tbs_add_san_hardwareModuleName_string(context
, tbs
,
2232 opt
->hardware_module_name_string
);
2234 hx509_err(context
, 1, ret
, "hx509_ca_tbs_add_san_hardwareModuleName_string");
2237 for (i
= 0; ret
== 0 && i
< opt
->policy_strings
.num_strings
; i
++) {
2238 char *oidstr
, *uri
, *dt
;
2240 if ((oidstr
= strdup(opt
->policy_strings
.strings
[i
])) == NULL
)
2241 hx509_err(context
, 1, ENOMEM
, "out of memory");
2242 uri
= strchr(oidstr
, ':');
2245 dt
= strchr(uri
? uri
: "", ' ');
2249 parse_oid(oidstr
, NULL
, &oid
);
2250 ret
= hx509_ca_tbs_add_pol(context
, tbs
, &oid
, uri
, dt
);
2255 for (i
= 0; ret
== 0 && i
< opt
->policy_mapping_strings
.num_strings
; i
++) {
2256 char *issuer_oidstr
, *subject_oidstr
;
2257 heim_oid issuer_oid
, subject_oid
;
2259 if ((issuer_oidstr
=
2260 strdup(opt
->policy_mapping_strings
.strings
[i
])) == NULL
)
2261 hx509_err(context
, 1, ENOMEM
, "out of memory");
2262 subject_oidstr
= strchr(issuer_oidstr
, ':');
2263 if (subject_oidstr
== NULL
)
2264 subject_oidstr
= issuer_oidstr
;
2266 *(subject_oidstr
++) = '\0';
2268 parse_oid(issuer_oidstr
, NULL
, &issuer_oid
);
2269 parse_oid(subject_oidstr
, NULL
, &subject_oid
);
2270 ret
= hx509_ca_tbs_add_pol_mapping(context
, tbs
, &issuer_oid
,
2273 hx509_err(context
, 1, ret
, "failed to add policy mapping");
2274 der_free_oid(&issuer_oid
);
2275 der_free_oid(&subject_oid
);
2276 free(issuer_oidstr
);
2279 if (opt
->issue_ca_flag
) {
2280 ret
= hx509_ca_tbs_set_ca(context
, tbs
, opt
->path_length_integer
);
2282 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_ca");
2284 if (opt
->issue_proxy_flag
) {
2285 ret
= hx509_ca_tbs_set_proxy(context
, tbs
, opt
->path_length_integer
);
2287 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_proxy");
2289 if (opt
->domain_controller_flag
) {
2290 hx509_ca_tbs_set_domaincontroller(context
, tbs
);
2292 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_domaincontroller");
2296 ret
= hx509_ca_tbs_set_notAfter_lifetime(context
, tbs
, delta
);
2298 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_notAfter_lifetime");
2300 if (opt
->pkinit_max_life_string
) {
2301 time_t t
= parse_time(opt
->pkinit_max_life_string
, "s");
2303 ret
= hx509_ca_tbs_set_pkinit_max_life(context
, tbs
, t
);
2305 hx509_err(context
, 1, ret
, "hx509_ca_tbs_set_pkinit_max_life");
2308 if (opt
->self_signed_flag
) {
2309 ret
= hx509_ca_sign_self(context
, tbs
, private_key
, &cert
);
2311 hx509_err(context
, 1, ret
, "hx509_ca_sign_self");
2313 ret
= hx509_ca_sign(context
, tbs
, signer
, &cert
);
2315 hx509_err(context
, 1, ret
, "hx509_ca_sign");
2319 ret
= _hx509_cert_assign_key(cert
, cert_key
);
2321 hx509_err(context
, 1, ret
, "_hx509_cert_assign_key");
2326 char *sn
= fix_store_name(context
, opt
->certificate_string
, "FILE");
2328 ret
= hx509_certs_init(context
, sn
, HX509_CERTS_CREATE
, NULL
, &certs
);
2330 hx509_err(context
, 1, ret
, "hx509_certs_init");
2332 ret
= hx509_certs_add(context
, certs
, cert
);
2334 hx509_err(context
, 1, ret
, "hx509_certs_add");
2336 ret
= hx509_certs_store(context
, certs
, 0, NULL
);
2338 hx509_err(context
, 1, ret
, "hx509_certs_store");
2340 hx509_certs_free(&certs
);
2345 hx509_name_free(&subject
);
2347 hx509_cert_free(signer
);
2348 hx509_cert_free(cert
);
2349 free_SubjectPublicKeyInfo(&spki
);
2351 if (private_key
!= cert_key
)
2352 hx509_private_key_free(&private_key
);
2353 hx509_private_key_free(&cert_key
);
2355 hx509_ca_tbs_free(&tbs
);
2360 static int HX509_LIB_CALL
2361 test_one_cert(hx509_context hxcontext
, void *ctx
, hx509_cert cert
)
2363 heim_octet_string sd
, c
;
2364 hx509_verify_ctx vctx
= ctx
;
2365 hx509_certs signer
= NULL
;
2369 if (_hx509_cert_private_key(cert
) == NULL
)
2372 ret
= hx509_cms_create_signed_1(context
, 0, NULL
, NULL
, 0,
2373 NULL
, cert
, NULL
, NULL
, NULL
, &sd
);
2375 errx(1, "hx509_cms_create_signed_1");
2377 ret
= hx509_cms_verify_signed(context
, vctx
, 0, sd
.data
, sd
.length
,
2378 NULL
, NULL
, &type
, &c
, &signer
);
2381 hx509_err(context
, 1, ret
, "hx509_cms_verify_signed");
2383 printf("create-signature verify-sigature done\n");
2391 test_crypto(struct test_crypto_options
*opt
, int argc
, char ** argv
)
2393 hx509_verify_ctx vctx
;
2398 hx509_lock_init(context
, &lock
);
2399 lock_strings(lock
, &opt
->pass_strings
);
2401 ret
= hx509_certs_init(context
, "MEMORY:test-crypto", 0, NULL
, &certs
);
2402 if (ret
) hx509_err(context
, 1, ret
, "hx509_certs_init: MEMORY");
2404 for (i
= 0; i
< argc
; i
++) {
2405 char *sn
= fix_store_name(context
, argv
[i
], "FILE");
2406 ret
= hx509_certs_append(context
, certs
, lock
, sn
);
2408 hx509_err(context
, 1, ret
, "hx509_certs_append %s", sn
);
2412 ret
= hx509_verify_init_ctx(context
, &vctx
);
2414 hx509_err(context
, 1, ret
, "hx509_verify_init_ctx");
2416 hx509_verify_attach_anchors(vctx
, certs
);
2418 ret
= hx509_certs_iter_f(context
, certs
, test_one_cert
, vctx
);
2420 hx509_err(context
, 1, ret
, "hx509_cert_iter");
2422 hx509_certs_free(&certs
);
2428 statistic_print(struct statistic_print_options
*opt
, int argc
, char **argv
)
2432 if (stat_file_string
== NULL
)
2433 errx(1, "no stat file");
2435 if (opt
->type_integer
)
2436 type
= opt
->type_integer
;
2438 hx509_query_unparse_stats(context
, type
, stdout
);
2447 crl_sign(struct crl_sign_options
*opt
, int argc
, char **argv
)
2450 heim_octet_string os
;
2451 hx509_cert signer
= NULL
;
2455 hx509_lock_init(context
, &lock
);
2456 lock_strings(lock
, &opt
->pass_strings
);
2458 ret
= hx509_crl_alloc(context
, &crl
);
2460 errx(1, "crl alloc");
2462 if (opt
->signer_string
== NULL
)
2463 errx(1, "signer missing");
2466 hx509_certs certs
= NULL
;
2468 char *sn
= fix_store_name(context
, opt
->signer_string
, "FILE");
2470 ret
= hx509_certs_init(context
, sn
, 0, NULL
, &certs
);
2472 hx509_err(context
, 1, ret
, "hx509_certs_init: %s", sn
);
2474 ret
= hx509_query_alloc(context
, &q
);
2476 hx509_err(context
, 1, ret
, "hx509_query_alloc: %d", ret
);
2478 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
2480 ret
= hx509_certs_find(context
, certs
, q
, &signer
);
2481 hx509_query_free(context
, q
);
2482 hx509_certs_free(&certs
);
2484 hx509_err(context
, 1, ret
, "no signer certificate found");
2488 if (opt
->lifetime_string
) {
2491 delta
= parse_time(opt
->lifetime_string
, "day");
2493 errx(1, "Invalid lifetime: %s", opt
->lifetime_string
);
2495 hx509_crl_lifetime(context
, crl
, delta
);
2499 hx509_certs revoked
= NULL
;
2502 ret
= hx509_certs_init(context
, "MEMORY:revoked-certs", 0,
2505 hx509_err(context
, 1, ret
,
2506 "hx509_certs_init: MEMORY cert");
2508 for (i
= 0; i
< argc
; i
++) {
2509 char *sn
= fix_store_name(context
, argv
[i
], "FILE");
2511 ret
= hx509_certs_append(context
, revoked
, lock
, sn
);
2513 hx509_err(context
, 1, ret
, "hx509_certs_append: %s", sn
);
2516 hx509_crl_add_revoked_certs(context
, crl
, revoked
);
2517 hx509_certs_free(&revoked
);
2520 hx509_crl_sign(context
, signer
, crl
, &os
);
2522 if (opt
->crl_file_string
)
2523 rk_dumpdata(opt
->crl_file_string
, os
.data
, os
.length
);
2527 hx509_crl_free(context
, &crl
);
2528 hx509_cert_free(signer
);
2529 hx509_lock_free(lock
);
2535 hxtool_list_oids(void *opt
, int argc
, char **argv
)
2537 const heim_oid
*oid
;
2540 while (der_match_heim_oid_by_name("", &cursor
, &oid
) == 0) {
2543 if ((errno
= der_print_heim_oid_sym(oid
, '.', &s
)) > 0)
2544 err(1, "der_print_heim_oid_sym");
2552 acert1_sans_utf8_other(struct acert_options
*opt
,
2553 struct getarg_strings
*wanted
,
2560 if (!wanted
->num_strings
)
2562 for (k
= 0; k
< wanted
->num_strings
; k
++) {
2563 len
= strlen(wanted
->strings
[k
]);
2564 if (len
== san
->length
&&
2565 strncmp(san
->data
, wanted
->strings
[k
], len
) == 0) {
2566 if (opt
->verbose_flag
)
2567 fprintf(stderr
, "Matched OtherName SAN %s (%s)\n",
2568 wanted
->strings
[k
], type
);
2573 if (opt
->verbose_flag
)
2574 fprintf(stderr
, "Did not match OtherName SAN %s (%s)\n",
2575 wanted
->strings
[k
], type
);
2580 acert1_sans_other(struct acert_options
*opt
,
2587 const char *type_str
= NULL
;
2591 (void) der_print_heim_oid_sym(type_id
, '.', &s
);
2592 type_str
= s
? s
: "<unknown>";
2593 if (der_heim_oid_cmp(type_id
, &asn1_oid_id_pkix_on_xmppAddr
) == 0) {
2594 ret
= acert1_sans_utf8_other(opt
, &opt
->has_xmpp_san_strings
,
2595 s
? s
: "xmpp", value
, count
);
2599 if (der_heim_oid_cmp(type_id
, &asn1_oid_id_pkinit_san
) != 0) {
2600 if (opt
->verbose_flag
)
2601 fprintf(stderr
, "Ignoring OtherName SAN of type %s\n", type_str
);
2607 type_str
= s
= NULL
;
2609 if (opt
->has_pkinit_san_strings
.num_strings
== 0)
2612 for (k
= 0; k
< opt
->has_pkinit_san_strings
.num_strings
; k
++) {
2613 const char *s2
= opt
->has_pkinit_san_strings
.strings
[k
];
2615 if ((ret
= _hx509_make_pkinit_san(context
, s2
, &pkinit
)))
2617 match
= (pkinit
.length
== value
->length
&&
2618 memcmp(pkinit
.data
, value
->data
, pkinit
.length
) == 0);
2621 if (opt
->verbose_flag
)
2622 fprintf(stderr
, "Matched PKINIT SAN %s\n", s2
);
2627 if (opt
->verbose_flag
)
2628 fprintf(stderr
, "Unexpected PKINIT SAN\n");
2633 acert1_sans(struct acert_options
*opt
,
2638 heim_printable_string hps
;
2641 size_t unwanted
= 0;
2644 memset(&gns
, 0, sizeof(gns
));
2645 decode_GeneralNames(e
->extnValue
.data
, e
->extnValue
.length
, &gns
, &sz
);
2646 for (i
= 0; (ret
== -1 || ret
== 0) && i
< gns
.len
; i
++) {
2647 GeneralName
*gn
= &gns
.val
[i
];
2651 if (gn
->element
== choice_GeneralName_rfc822Name
) {
2652 for (k
= 0; k
< opt
->has_email_san_strings
.num_strings
; k
++) {
2653 s
= opt
->has_email_san_strings
.strings
[k
];
2654 hps
.data
= rk_UNCONST(s
);
2655 hps
.length
= strlen(s
);
2656 if (der_printable_string_cmp(&gn
->u
.rfc822Name
, &hps
) == 0) {
2657 if (opt
->verbose_flag
)
2658 fprintf(stderr
, "Matched e-mail address SAN %s\n", s
);
2663 if (k
&& k
== opt
->has_email_san_strings
.num_strings
) {
2664 if (opt
->verbose_flag
)
2665 fprintf(stderr
, "Unexpected e-mail address SAN %.*s\n",
2666 (int)gn
->u
.rfc822Name
.length
,
2667 (const char *)gn
->u
.rfc822Name
.data
);
2670 } else if (gn
->element
== choice_GeneralName_dNSName
) {
2671 for (k
= 0; k
< opt
->has_dnsname_san_strings
.num_strings
; k
++) {
2672 s
= opt
->has_dnsname_san_strings
.strings
[k
];
2673 hps
.data
= rk_UNCONST(s
);
2674 hps
.length
= strlen(s
);
2675 if (der_printable_string_cmp(&gn
->u
.dNSName
, &hps
) == 0) {
2676 if (opt
->verbose_flag
)
2677 fprintf(stderr
, "Matched dNSName SAN %s\n", s
);
2682 if (k
&& k
== opt
->has_dnsname_san_strings
.num_strings
) {
2683 if (opt
->verbose_flag
)
2684 fprintf(stderr
, "Unexpected e-mail address SAN %.*s\n",
2685 (int)gn
->u
.dNSName
.length
,
2686 (const char *)gn
->u
.dNSName
.data
);
2689 } else if (gn
->element
== choice_GeneralName_registeredID
) {
2690 for (k
= 0; k
< opt
->has_registeredID_san_strings
.num_strings
; k
++) {
2693 s
= opt
->has_registeredID_san_strings
.strings
[k
];
2694 memset(&oid
, 0, sizeof(oid
));
2695 parse_oid(s
, NULL
, &oid
);
2696 if (der_heim_oid_cmp(&gn
->u
.registeredID
, &oid
) == 0) {
2698 if (opt
->verbose_flag
)
2699 fprintf(stderr
, "Matched registeredID SAN %s\n", s
);
2705 if (k
&& k
== opt
->has_dnsname_san_strings
.num_strings
) {
2706 if (opt
->verbose_flag
)
2707 fprintf(stderr
, "Unexpected registeredID SAN\n");
2710 } else if (gn
->element
== choice_GeneralName_otherName
) {
2711 ret
= acert1_sans_other(opt
, &gn
->u
.otherName
.type_id
,
2712 &gn
->u
.otherName
.value
, count
);
2713 } else if (opt
->verbose_flag
) {
2714 fprintf(stderr
, "Unexpected unsupported SAN\n");
2718 free_GeneralNames(&gns
);
2719 if (ret
== 0 && unwanted
&& opt
->exact_flag
)
2725 acert1_ekus(struct acert_options
*opt
,
2732 size_t unwanted
= 0;
2735 memset(&eku
, 0, sizeof(eku
));
2736 decode_ExtKeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, &eku
, &sz
);
2737 for (i
= 0; (ret
== -1 || ret
== 0) && i
< eku
.len
; i
++) {
2739 for (k
= 0; k
< opt
->has_eku_strings
.num_strings
; k
++) {
2740 const char *s
= opt
->has_eku_strings
.strings
[k
];
2743 memset(&oid
, 0, sizeof(oid
));
2744 parse_oid(s
, NULL
, &oid
);
2745 if (der_heim_oid_cmp(&eku
.val
[i
], &oid
) == 0) {
2747 if (opt
->verbose_flag
)
2748 fprintf(stderr
, "Matched EKU OID %s\n", s
);
2754 if (k
&& k
== opt
->has_eku_strings
.num_strings
) {
2757 (void) der_print_heim_oid_sym(&eku
.val
[i
], '.', &oids
);
2758 if (opt
->verbose_flag
)
2759 fprintf(stderr
, "Unexpected EKU OID %s\n",
2760 oids
? oids
: "<could-not-format-OID>");
2764 free_ExtKeyUsage(&eku
);
2765 if (ret
== 0 && unwanted
&& opt
->exact_flag
)
2771 acert1_kus(struct acert_options
*opt
,
2776 const struct units
*u
= asn1_KeyUsage_units();
2779 size_t unwanted
= 0;
2780 size_t wanted
= opt
->has_ku_strings
.num_strings
;
2783 memset(&ku
, 0, sizeof(ku
));
2784 decode_KeyUsage(e
->extnValue
.data
, e
->extnValue
.length
, &ku
, &sz
);
2785 ku_num
= KeyUsage2int(ku
);
2787 /* Validate requested key usage values */
2788 for (k
= 0; k
< wanted
; k
++) {
2789 const char *s
= opt
->has_ku_strings
.strings
[k
];
2791 for (i
= 0; u
[i
].name
; i
++)
2792 if (strcmp(s
, u
[i
].name
) == 0)
2795 if (u
[i
].name
== NULL
)
2796 warnx("Warning: requested key usage %s unknown", s
);
2799 for (i
= 0; u
[i
].name
; i
++) {
2800 if ((u
[i
].mult
& ku_num
))
2802 for (k
= 0; k
< wanted
; k
++) {
2803 const char *s
= opt
->has_ku_strings
.strings
[k
];
2805 if (!(u
[i
].mult
& ku_num
) || strcmp(s
, u
[i
].name
) != 0)
2808 if (opt
->verbose_flag
)
2809 fprintf(stderr
, "Matched key usage %s\n", s
);
2813 if ((u
[i
].mult
& ku_num
) && k
== wanted
) {
2814 if (opt
->verbose_flag
)
2815 fprintf(stderr
, "Unexpected key usage %s\n", u
[i
].name
);
2820 return (unwanted
&& opt
->exact_flag
) ? -1 : 0;
2824 ptime(const char *s
)
2830 if ((rest
= strptime(s
, "%Y-%m-%dT%H:%M:%S", &at_tm
)) != NULL
&&
2832 return mktime(&at_tm
);
2833 if ((rest
= strptime(s
, "%Y%m%d%H%M%S", &at_tm
)) != NULL
&& rest
[0] == '\0')
2834 return mktime(&at_tm
);
2835 if ((at_s
= parse_time(s
, "s")) != -1)
2836 return time(NULL
) + at_s
;
2837 errx(1, "Could not parse time spec %s", s
);
2841 acert1_validity(struct acert_options
*opt
, hx509_cert cert
)
2843 time_t not_before_eq
= 0;
2844 time_t not_before_lt
= 0;
2845 time_t not_before_gt
= 0;
2846 time_t not_after_eq
= 0;
2847 time_t not_after_lt
= 0;
2848 time_t not_after_gt
= 0;
2851 if (opt
->valid_now_flag
) {
2852 time_t now
= time(NULL
);
2854 if (hx509_cert_get_notBefore(cert
) > now
) {
2855 if (opt
->verbose_flag
)
2856 fprintf(stderr
, "Certificate not valid yet\n");
2859 if (hx509_cert_get_notAfter(cert
) < now
) {
2860 if (opt
->verbose_flag
)
2861 fprintf(stderr
, "Certificate currently expired\n");
2865 if (opt
->valid_at_string
) {
2866 time_t at
= ptime(opt
->valid_at_string
);
2868 if (hx509_cert_get_notBefore(cert
) > at
) {
2869 if (opt
->verbose_flag
)
2870 fprintf(stderr
, "Certificate not valid yet at %s\n",
2871 opt
->valid_at_string
);
2874 if (hx509_cert_get_notAfter(cert
) < at
) {
2875 if (opt
->verbose_flag
)
2876 fprintf(stderr
, "Certificate expired before %s\n",
2877 opt
->valid_at_string
);
2882 if (opt
->not_before_eq_string
)
2883 not_before_eq
= ptime(opt
->not_before_eq_string
);
2884 if (opt
->not_before_lt_string
)
2885 not_before_lt
= ptime(opt
->not_before_lt_string
);
2886 if (opt
->not_before_gt_string
)
2887 not_before_gt
= ptime(opt
->not_before_gt_string
);
2888 if (opt
->not_after_eq_string
)
2889 not_after_eq
= ptime(opt
->not_after_eq_string
);
2890 if (opt
->not_after_lt_string
)
2891 not_after_lt
= ptime(opt
->not_after_lt_string
);
2892 if (opt
->not_after_gt_string
)
2893 not_after_gt
= ptime(opt
->not_after_gt_string
);
2895 if ((not_before_eq
&& hx509_cert_get_notBefore(cert
) != not_before_eq
) ||
2896 (not_before_lt
&& hx509_cert_get_notBefore(cert
) >= not_before_lt
) ||
2897 (not_before_gt
&& hx509_cert_get_notBefore(cert
) <= not_before_gt
)) {
2898 if (opt
->verbose_flag
)
2899 fprintf(stderr
, "Certificate notBefore not as requested\n");
2902 if ((not_after_eq
&& hx509_cert_get_notAfter(cert
) != not_after_eq
) ||
2903 (not_after_lt
&& hx509_cert_get_notAfter(cert
) >= not_after_lt
) ||
2904 (not_after_gt
&& hx509_cert_get_notAfter(cert
) <= not_after_gt
)) {
2905 if (opt
->verbose_flag
)
2906 fprintf(stderr
, "Certificate notAfter not as requested\n");
2910 if (opt
->has_private_key_flag
&& !hx509_cert_have_private_key(cert
)) {
2911 if (opt
->verbose_flag
)
2912 fprintf(stderr
, "Certificate does not have a private key\n");
2916 if (opt
->lacks_private_key_flag
&& hx509_cert_have_private_key(cert
)) {
2917 if (opt
->verbose_flag
)
2918 fprintf(stderr
, "Certificate does not have a private key\n");
2926 acert1(struct acert_options
*opt
, size_t cert_num
, hx509_cert cert
, int *matched
)
2928 const heim_oid
*misc_exts
[] = {
2929 &asn1_oid_id_x509_ce_authorityKeyIdentifier
,
2930 &asn1_oid_id_x509_ce_subjectKeyIdentifier
,
2931 &asn1_oid_id_x509_ce_basicConstraints
,
2932 &asn1_oid_id_x509_ce_nameConstraints
,
2933 &asn1_oid_id_x509_ce_certificatePolicies
,
2934 &asn1_oid_id_x509_ce_policyMappings
,
2935 &asn1_oid_id_x509_ce_issuerAltName
,
2936 &asn1_oid_id_x509_ce_subjectDirectoryAttributes
,
2937 &asn1_oid_id_x509_ce_policyConstraints
,
2938 &asn1_oid_id_x509_ce_cRLDistributionPoints
,
2939 &asn1_oid_id_x509_ce_deltaCRLIndicator
,
2940 &asn1_oid_id_x509_ce_issuingDistributionPoint
,
2941 &asn1_oid_id_x509_ce_inhibitAnyPolicy
,
2942 &asn1_oid_id_x509_ce_cRLNumber
,
2943 &asn1_oid_id_x509_ce_freshestCRL
,
2946 const Certificate
*c
;
2947 const Extensions
*e
;
2949 size_t matched_elements
= 0;
2950 size_t wanted
, sans_wanted
, ekus_wanted
, kus_wanted
;
2951 size_t found
, sans_found
, ekus_found
, kus_found
;
2955 if ((c
= _hx509_get_cert(cert
)) == NULL
)
2956 errx(1, "Could not get Certificate");
2957 e
= c
->tbsCertificate
.extensions
;
2959 ret
= _hx509_cert_get_keyusage(context
, cert
, &ku
);
2960 if (ret
&& ret
!= HX509_KU_CERT_MISSING
)
2961 hx509_err(context
, 1, ret
, "Could not get key usage of certificate");
2962 if (ret
== HX509_KU_CERT_MISSING
&& opt
->ca_flag
)
2963 return 0; /* want CA cert; this isn't it */
2964 if (ret
== 0 && opt
->ca_flag
&& !ku
.keyCertSign
)
2965 return 0; /* want CA cert; this isn't it */
2966 if (ret
== 0 && opt
->end_entity_flag
&& ku
.keyCertSign
)
2967 return 0; /* want EE cert; this isn't it */
2969 if (opt
->cert_num_integer
!= -1 && cert_num
<= INT_MAX
&&
2970 opt
->cert_num_integer
!= (int)cert_num
)
2972 if (opt
->cert_num_integer
== -1 || opt
->cert_num_integer
== (int)cert_num
)
2975 if (_hx509_cert_get_version(c
) < 3) {
2976 warnx("Certificate with version %d < 3 ignored",
2977 _hx509_cert_get_version(c
));
2981 sans_wanted
= opt
->has_email_san_strings
.num_strings
2982 + opt
->has_xmpp_san_strings
.num_strings
2983 + opt
->has_ms_upn_san_strings
.num_strings
2984 + opt
->has_dnsname_san_strings
.num_strings
2985 + opt
->has_pkinit_san_strings
.num_strings
2986 + opt
->has_registeredID_san_strings
.num_strings
;
2987 ekus_wanted
= opt
->has_eku_strings
.num_strings
;
2988 kus_wanted
= opt
->has_ku_strings
.num_strings
;
2989 wanted
= sans_wanted
+ ekus_wanted
+ kus_wanted
;
2990 found
= sans_found
= ekus_found
= kus_found
= 0;
2995 return acert1_validity(opt
, cert
);
2998 for (i
= 0; i
< e
->len
; i
++) {
2999 if (der_heim_oid_cmp(&e
->val
[i
].extnID
,
3000 &asn1_oid_id_x509_ce_subjectAltName
) == 0) {
3001 ret
= acert1_sans(opt
, &e
->val
[i
], &matched_elements
, &sans_found
);
3002 if (ret
== -1 && sans_wanted
== 0 &&
3003 (!opt
->exact_flag
|| sans_found
== 0))
3005 } else if (der_heim_oid_cmp(&e
->val
[i
].extnID
,
3006 &asn1_oid_id_x509_ce_extKeyUsage
) == 0) {
3007 ret
= acert1_ekus(opt
, &e
->val
[i
], &matched_elements
, &ekus_found
);
3008 if (ret
== -1 && ekus_wanted
== 0 &&
3009 (!opt
->exact_flag
|| ekus_found
== 0))
3011 } else if (der_heim_oid_cmp(&e
->val
[i
].extnID
,
3012 &asn1_oid_id_x509_ce_keyUsage
) == 0) {
3013 ret
= acert1_kus(opt
, &e
->val
[i
], &matched_elements
, &kus_found
);
3014 if (ret
== -1 && kus_wanted
== 0 &&
3015 (!opt
->exact_flag
|| kus_found
== 0))
3020 for (k
= 0; misc_exts
[k
]; k
++) {
3021 if (der_heim_oid_cmp(&e
->val
[i
].extnID
, misc_exts
[k
]) == 0)
3027 (void) der_print_heim_oid(&e
->val
[i
].extnID
, '.', &oids
);
3028 warnx("Matching certificate has unexpected certificate "
3029 "extension %s", oids
? oids
: "<could not display OID>");
3033 if (ret
&& ret
!= -1)
3034 hx509_err(context
, 1, ret
, "Error checking matching certificate");
3038 if (matched_elements
!= wanted
)
3040 found
= sans_found
+ ekus_found
+ kus_found
;
3041 if (matched_elements
!= found
&& opt
->exact_flag
)
3045 return acert1_validity(opt
, cert
);
3049 acert(struct acert_options
*opt
, int argc
, char **argv
)
3051 hx509_cursor cursor
= NULL
;
3052 hx509_query
*q
= NULL
;
3053 hx509_certs certs
= NULL
;
3054 hx509_cert cert
= NULL
;
3055 char *sn
= fix_store_name(context
, argv
[0], "FILE");
3060 if (opt
->not_after_eq_string
&&
3061 (opt
->not_after_lt_string
|| opt
->not_after_gt_string
))
3062 errx(1, "--not-after-eq should not be given with --not-after-lt/gt");
3063 if (opt
->not_before_eq_string
&&
3064 (opt
->not_before_lt_string
|| opt
->not_before_gt_string
))
3065 errx(1, "--not-before-eq should not be given with --not-before-lt/gt");
3067 if ((ret
= hx509_certs_init(context
, sn
, 0, NULL
, &certs
)))
3068 hx509_err(context
, 1, ret
, "Could not load certificates from %s", sn
);
3070 if (opt
->expr_string
) {
3071 if ((ret
= hx509_query_alloc(context
, &q
)) ||
3072 (ret
= hx509_query_match_expr(context
, q
, opt
->expr_string
)))
3073 hx509_err(context
, 1, ret
, "Could not initialize query");
3074 if ((ret
= hx509_certs_find(context
, certs
, q
, &cert
)) || !cert
)
3075 hx509_err(context
, 1, ret
, "No matching certificate");
3076 ret
= acert1(opt
, -1, cert
, &matched
);
3079 ret
= hx509_certs_start_seq(context
, certs
, &cursor
);
3081 (ret
= hx509_certs_next_cert(context
, certs
,
3082 cursor
, &cert
)) == 0 &&
3084 ret
= acert1(opt
, n
++, cert
, &matched
);
3089 (void) hx509_certs_end_seq(context
, certs
, cursor
);
3091 if (!matched
&& ret
)
3092 hx509_err(context
, 1, ret
, "Could not find certificate");
3094 errx(1, "Could not find certificate");
3096 errx(1, "Matching certificate did not meet requirements");
3098 hx509_err(context
, 1, ret
, "Matching certificate did not meet "
3109 help(void *opt
, int argc
, char **argv
)
3111 sl_slc_help(commands
, argc
, argv
);
3116 main(int argc
, char **argv
)
3118 int ret
, optidx
= 0;
3120 setprogname (argv
[0]);
3122 if(getarg(args
, num_args
, argc
, argv
, &optidx
))
3127 print_version(NULL
);
3136 ret
= hx509_context_init(&context
);
3138 errx(1, "hx509_context_init failed with %d", ret
);
3140 if (stat_file_string
)
3141 hx509_query_statistic_file(context
, stat_file_string
);
3143 ret
= sl_command(commands
, argc
, argv
);
3145 warnx ("unrecognized command: %s", argv
[0]);
3147 hx509_context_free(&context
);