s4:heimdal: import lorikeet-heimdal-200911122202 (commit 9291fd2d101f3eecec550178634f...
[Samba/ekacnet.git] / source4 / heimdal / lib / hx509 / cert.c
blobebf02a99e34ced6df2ada3690c4e71ffdfd65c93
1 /*
2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
31 * SUCH DAMAGE.
34 #include "hx_locl.h"
35 #include "crypto-headers.h"
36 #include <rtbl.h>
38 /**
39 * @page page_cert The basic certificate
41 * The basic hx509 cerificate object in hx509 is hx509_cert. The
42 * hx509_cert object is representing one X509/PKIX certificate and
43 * associated attributes; like private key, friendly name, etc.
45 * A hx509_cert object is usully found via the keyset interfaces (@ref
46 * page_keyset), but its also possible to create a certificate
47 * directly from a parsed object with hx509_cert_init() and
48 * hx509_cert_init_data().
50 * See the library functions here: @ref hx509_cert
53 struct hx509_verify_ctx_data {
54 hx509_certs trust_anchors;
55 int flags;
56 #define HX509_VERIFY_CTX_F_TIME_SET 1
57 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
58 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
59 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
60 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
61 #define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32
62 time_t time_now;
63 unsigned int max_depth;
64 #define HX509_VERIFY_MAX_DEPTH 30
65 hx509_revoke_ctx revoke_ctx;
68 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
69 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
70 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
72 struct _hx509_cert_attrs {
73 size_t len;
74 hx509_cert_attribute *val;
77 struct hx509_cert_data {
78 unsigned int ref;
79 char *friendlyname;
80 Certificate *data;
81 hx509_private_key private_key;
82 struct _hx509_cert_attrs attrs;
83 hx509_name basename;
84 _hx509_cert_release_func release;
85 void *ctx;
88 typedef struct hx509_name_constraints {
89 NameConstraints *val;
90 size_t len;
91 } hx509_name_constraints;
93 #define GeneralSubtrees_SET(g,var) \
94 (g)->len = (var)->len, (g)->val = (var)->val;
96 /**
97 * Creates a hx509 context that most functions in the library
98 * uses. The context is only allowed to be used by one thread at each
99 * moment. Free the context with hx509_context_free().
101 * @param context Returns a pointer to new hx509 context.
103 * @return Returns an hx509 error code.
105 * @ingroup hx509
109 hx509_context_init(hx509_context *context)
111 *context = calloc(1, sizeof(**context));
112 if (*context == NULL)
113 return ENOMEM;
115 _hx509_ks_null_register(*context);
116 _hx509_ks_mem_register(*context);
117 _hx509_ks_file_register(*context);
118 _hx509_ks_pkcs12_register(*context);
119 _hx509_ks_pkcs11_register(*context);
120 _hx509_ks_dir_register(*context);
121 _hx509_ks_keychain_register(*context);
123 ENGINE_add_conf_module();
124 OpenSSL_add_all_algorithms();
126 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
128 initialize_hx_error_table_r(&(*context)->et_list);
129 initialize_asn1_error_table_r(&(*context)->et_list);
131 #ifdef HX509_DEFAULT_ANCHORS
132 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
133 NULL, &(*context)->default_trust_anchors);
134 #endif
136 return 0;
140 * Selects if the hx509_revoke_verify() function is going to require
141 * the existans of a revokation method (OCSP, CRL) or not. Note that
142 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
143 * call hx509_revoke_verify().
145 * @param context hx509 context to change the flag for.
146 * @param flag zero, revokation method required, non zero missing
147 * revokation method ok
149 * @ingroup hx509_verify
152 void
153 hx509_context_set_missing_revoke(hx509_context context, int flag)
155 if (flag)
156 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
157 else
158 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
162 * Free the context allocated by hx509_context_init().
164 * @param context context to be freed.
166 * @ingroup hx509
169 void
170 hx509_context_free(hx509_context *context)
172 hx509_clear_error_string(*context);
173 if ((*context)->ks_ops) {
174 free((*context)->ks_ops);
175 (*context)->ks_ops = NULL;
177 (*context)->ks_num_ops = 0;
178 free_error_table ((*context)->et_list);
179 if ((*context)->querystat)
180 free((*context)->querystat);
181 memset(*context, 0, sizeof(**context));
182 free(*context);
183 *context = NULL;
190 Certificate *
191 _hx509_get_cert(hx509_cert cert)
193 return cert->data;
201 _hx509_cert_get_version(const Certificate *t)
203 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
207 * Allocate and init an hx509 certificate object from the decoded
208 * certificate `c´.
210 * @param context A hx509 context.
211 * @param c
212 * @param cert
214 * @return Returns an hx509 error code.
216 * @ingroup hx509_cert
220 hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
222 int ret;
224 *cert = malloc(sizeof(**cert));
225 if (*cert == NULL)
226 return ENOMEM;
227 (*cert)->ref = 1;
228 (*cert)->friendlyname = NULL;
229 (*cert)->attrs.len = 0;
230 (*cert)->attrs.val = NULL;
231 (*cert)->private_key = NULL;
232 (*cert)->basename = NULL;
233 (*cert)->release = NULL;
234 (*cert)->ctx = NULL;
236 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
237 if ((*cert)->data == NULL) {
238 free(*cert);
239 return ENOMEM;
241 ret = copy_Certificate(c, (*cert)->data);
242 if (ret) {
243 free((*cert)->data);
244 free(*cert);
245 *cert = NULL;
247 return ret;
251 * Just like hx509_cert_init(), but instead of a decode certificate
252 * takes an pointer and length to a memory region that contains a
253 * DER/BER encoded certificate.
255 * If the memory region doesn't contain just the certificate and
256 * nothing more the function will fail with
257 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
259 * @param context A hx509 context.
260 * @param ptr pointer to memory region containing encoded certificate.
261 * @param len length of memory region.
262 * @param cert a return pointer to a hx509 certificate object, will
263 * contain NULL on error.
265 * @return An hx509 error code, see hx509_get_error_string().
267 * @ingroup hx509_cert
271 hx509_cert_init_data(hx509_context context,
272 const void *ptr,
273 size_t len,
274 hx509_cert *cert)
276 Certificate t;
277 size_t size;
278 int ret;
280 ret = decode_Certificate(ptr, len, &t, &size);
281 if (ret) {
282 hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
283 return ret;
285 if (size != len) {
286 free_Certificate(&t);
287 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
288 "Extra data after certificate");
289 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
292 ret = hx509_cert_init(context, &t, cert);
293 free_Certificate(&t);
294 return ret;
297 void
298 _hx509_cert_set_release(hx509_cert cert,
299 _hx509_cert_release_func release,
300 void *ctx)
302 cert->release = release;
303 cert->ctx = ctx;
307 /* Doesn't make a copy of `private_key'. */
310 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
312 if (cert->private_key)
313 _hx509_private_key_free(&cert->private_key);
314 cert->private_key = _hx509_private_key_ref(private_key);
315 return 0;
319 * Free reference to the hx509 certificate object, if the refcounter
320 * reaches 0, the object if freed. Its allowed to pass in NULL.
322 * @param cert the cert to free.
324 * @ingroup hx509_cert
327 void
328 hx509_cert_free(hx509_cert cert)
330 int i;
332 if (cert == NULL)
333 return;
335 if (cert->ref <= 0)
336 _hx509_abort("cert refcount <= 0 on free");
337 if (--cert->ref > 0)
338 return;
340 if (cert->release)
341 (cert->release)(cert, cert->ctx);
343 if (cert->private_key)
344 _hx509_private_key_free(&cert->private_key);
346 free_Certificate(cert->data);
347 free(cert->data);
349 for (i = 0; i < cert->attrs.len; i++) {
350 der_free_octet_string(&cert->attrs.val[i]->data);
351 der_free_oid(&cert->attrs.val[i]->oid);
352 free(cert->attrs.val[i]);
354 free(cert->attrs.val);
355 free(cert->friendlyname);
356 if (cert->basename)
357 hx509_name_free(&cert->basename);
358 memset(cert, 0, sizeof(cert));
359 free(cert);
363 * Add a reference to a hx509 certificate object.
365 * @param cert a pointer to an hx509 certificate object.
367 * @return the same object as is passed in.
369 * @ingroup hx509_cert
372 hx509_cert
373 hx509_cert_ref(hx509_cert cert)
375 if (cert == NULL)
376 return NULL;
377 if (cert->ref <= 0)
378 _hx509_abort("cert refcount <= 0");
379 cert->ref++;
380 if (cert->ref == 0)
381 _hx509_abort("cert refcount == 0");
382 return cert;
386 * Allocate an verification context that is used fo control the
387 * verification process.
389 * @param context A hx509 context.
390 * @param ctx returns a pointer to a hx509_verify_ctx object.
392 * @return An hx509 error code, see hx509_get_error_string().
394 * @ingroup hx509_verify
398 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
400 hx509_verify_ctx c;
402 c = calloc(1, sizeof(*c));
403 if (c == NULL)
404 return ENOMEM;
406 c->max_depth = HX509_VERIFY_MAX_DEPTH;
408 *ctx = c;
410 return 0;
414 * Free an hx509 verification context.
416 * @param ctx the context to be freed.
418 * @ingroup hx509_verify
421 void
422 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
424 if (ctx) {
425 hx509_certs_free(&ctx->trust_anchors);
426 hx509_revoke_free(&ctx->revoke_ctx);
427 memset(ctx, 0, sizeof(*ctx));
429 free(ctx);
433 * Set the trust anchors in the verification context, makes an
434 * reference to the keyset, so the consumer can free the keyset
435 * independent of the destruction of the verification context (ctx).
436 * If there already is a keyset attached, it's released.
438 * @param ctx a verification context
439 * @param set a keyset containing the trust anchors.
441 * @ingroup hx509_verify
444 void
445 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
447 if (ctx->trust_anchors)
448 hx509_certs_free(&ctx->trust_anchors);
449 ctx->trust_anchors = hx509_certs_ref(set);
453 * Attach an revocation context to the verfication context, , makes an
454 * reference to the revoke context, so the consumer can free the
455 * revoke context independent of the destruction of the verification
456 * context. If there is no revoke context, the verification process is
457 * NOT going to check any verification status.
459 * @param ctx a verification context.
460 * @param revoke_ctx a revoke context.
462 * @ingroup hx509_verify
465 void
466 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
468 if (ctx->revoke_ctx)
469 hx509_revoke_free(&ctx->revoke_ctx);
470 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
474 * Set the clock time the the verification process is going to
475 * use. Used to check certificate in the past and future time. If not
476 * set the current time will be used.
478 * @param ctx a verification context.
479 * @param t the time the verifiation is using.
482 * @ingroup hx509_verify
485 void
486 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
488 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
489 ctx->time_now = t;
492 time_t
493 _hx509_verify_get_time(hx509_verify_ctx ctx)
495 return ctx->time_now;
499 * Set the maximum depth of the certificate chain that the path
500 * builder is going to try.
502 * @param ctx a verification context
503 * @param max_depth maxium depth of the certificate chain, include
504 * trust anchor.
506 * @ingroup hx509_verify
509 void
510 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
512 ctx->max_depth = max_depth;
516 * Allow or deny the use of proxy certificates
518 * @param ctx a verification context
519 * @param boolean if non zero, allow proxy certificates.
521 * @ingroup hx509_verify
524 void
525 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
527 if (boolean)
528 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
529 else
530 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
534 * Select strict RFC3280 verification of certificiates. This means
535 * checking key usage on CA certificates, this will make version 1
536 * certificiates unuseable.
538 * @param ctx a verification context
539 * @param boolean if non zero, use strict verification.
541 * @ingroup hx509_verify
544 void
545 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
547 if (boolean)
548 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
549 else
550 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
554 * Allow using the operating system builtin trust anchors if no other
555 * trust anchors are configured.
557 * @param ctx a verification context
558 * @param boolean if non zero, useing the operating systems builtin
559 * trust anchors.
562 * @return An hx509 error code, see hx509_get_error_string().
564 * @ingroup hx509_cert
567 void
568 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
570 if (boolean)
571 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
572 else
573 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
576 void
577 hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
578 int boolean)
580 if (boolean)
581 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
582 else
583 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
586 static const Extension *
587 find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
589 const TBSCertificate *c = &cert->tbsCertificate;
591 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
592 return NULL;
594 for (;*idx < c->extensions->len; (*idx)++) {
595 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
596 return &c->extensions->val[(*idx)++];
598 return NULL;
601 static int
602 find_extension_auth_key_id(const Certificate *subject,
603 AuthorityKeyIdentifier *ai)
605 const Extension *e;
606 size_t size;
607 int i = 0;
609 memset(ai, 0, sizeof(*ai));
611 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
612 if (e == NULL)
613 return HX509_EXTENSION_NOT_FOUND;
615 return decode_AuthorityKeyIdentifier(e->extnValue.data,
616 e->extnValue.length,
617 ai, &size);
621 _hx509_find_extension_subject_key_id(const Certificate *issuer,
622 SubjectKeyIdentifier *si)
624 const Extension *e;
625 size_t size;
626 int i = 0;
628 memset(si, 0, sizeof(*si));
630 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
631 if (e == NULL)
632 return HX509_EXTENSION_NOT_FOUND;
634 return decode_SubjectKeyIdentifier(e->extnValue.data,
635 e->extnValue.length,
636 si, &size);
639 static int
640 find_extension_name_constraints(const Certificate *subject,
641 NameConstraints *nc)
643 const Extension *e;
644 size_t size;
645 int i = 0;
647 memset(nc, 0, sizeof(*nc));
649 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
650 if (e == NULL)
651 return HX509_EXTENSION_NOT_FOUND;
653 return decode_NameConstraints(e->extnValue.data,
654 e->extnValue.length,
655 nc, &size);
658 static int
659 find_extension_subject_alt_name(const Certificate *cert, int *i,
660 GeneralNames *sa)
662 const Extension *e;
663 size_t size;
665 memset(sa, 0, sizeof(*sa));
667 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
668 if (e == NULL)
669 return HX509_EXTENSION_NOT_FOUND;
671 return decode_GeneralNames(e->extnValue.data,
672 e->extnValue.length,
673 sa, &size);
676 static int
677 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
679 const Extension *e;
680 size_t size;
681 int i = 0;
683 memset(eku, 0, sizeof(*eku));
685 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
686 if (e == NULL)
687 return HX509_EXTENSION_NOT_FOUND;
689 return decode_ExtKeyUsage(e->extnValue.data,
690 e->extnValue.length,
691 eku, &size);
694 static int
695 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
697 void *p;
698 int ret;
700 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
701 if (p == NULL)
702 return ENOMEM;
703 list->val = p;
704 ret = der_copy_octet_string(entry, &list->val[list->len]);
705 if (ret)
706 return ret;
707 list->len++;
708 return 0;
712 * Free a list of octet strings returned by another hx509 library
713 * function.
715 * @param list list to be freed.
717 * @ingroup hx509_misc
720 void
721 hx509_free_octet_string_list(hx509_octet_string_list *list)
723 int i;
724 for (i = 0; i < list->len; i++)
725 der_free_octet_string(&list->val[i]);
726 free(list->val);
727 list->val = NULL;
728 list->len = 0;
732 * Return a list of subjectAltNames specified by oid in the
733 * certificate. On error the
735 * The returned list of octet string should be freed with
736 * hx509_free_octet_string_list().
738 * @param context A hx509 context.
739 * @param cert a hx509 certificate object.
740 * @param oid an oid to for SubjectAltName.
741 * @param list list of matching SubjectAltName.
743 * @return An hx509 error code, see hx509_get_error_string().
745 * @ingroup hx509_cert
749 hx509_cert_find_subjectAltName_otherName(hx509_context context,
750 hx509_cert cert,
751 const heim_oid *oid,
752 hx509_octet_string_list *list)
754 GeneralNames sa;
755 int ret, i, j;
757 list->val = NULL;
758 list->len = 0;
760 i = 0;
761 while (1) {
762 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
763 i++;
764 if (ret == HX509_EXTENSION_NOT_FOUND) {
765 return 0;
766 } else if (ret != 0) {
767 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
768 hx509_free_octet_string_list(list);
769 return ret;
772 for (j = 0; j < sa.len; j++) {
773 if (sa.val[j].element == choice_GeneralName_otherName &&
774 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
776 ret = add_to_list(list, &sa.val[j].u.otherName.value);
777 if (ret) {
778 hx509_set_error_string(context, 0, ret,
779 "Error adding an exra SAN to "
780 "return list");
781 hx509_free_octet_string_list(list);
782 free_GeneralNames(&sa);
783 return ret;
787 free_GeneralNames(&sa);
792 static int
793 check_key_usage(hx509_context context, const Certificate *cert,
794 unsigned flags, int req_present)
796 const Extension *e;
797 KeyUsage ku;
798 size_t size;
799 int ret, i = 0;
800 unsigned ku_flags;
802 if (_hx509_cert_get_version(cert) < 3)
803 return 0;
805 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
806 if (e == NULL) {
807 if (req_present) {
808 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
809 "Required extension key "
810 "usage missing from certifiate");
811 return HX509_KU_CERT_MISSING;
813 return 0;
816 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
817 if (ret)
818 return ret;
819 ku_flags = KeyUsage2int(ku);
820 if ((ku_flags & flags) != flags) {
821 unsigned missing = (~ku_flags) & flags;
822 char buf[256], *name;
824 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
825 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
826 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
827 "Key usage %s required but missing "
828 "from certifiate %s", buf, name);
829 free(name);
830 return HX509_KU_CERT_MISSING;
832 return 0;
836 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
837 * an error code. If 'req_present' the existance is required of the
838 * KeyUsage extension.
842 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
843 unsigned flags, int req_present)
845 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
848 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
850 static int
851 check_basic_constraints(hx509_context context, const Certificate *cert,
852 enum certtype type, int depth)
854 BasicConstraints bc;
855 const Extension *e;
856 size_t size;
857 int ret, i = 0;
859 if (_hx509_cert_get_version(cert) < 3)
860 return 0;
862 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
863 if (e == NULL) {
864 switch(type) {
865 case PROXY_CERT:
866 case EE_CERT:
867 return 0;
868 case CA_CERT: {
869 char *name;
870 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
871 assert(ret == 0);
872 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
873 "basicConstraints missing from "
874 "CA certifiacte %s", name);
875 free(name);
876 return HX509_EXTENSION_NOT_FOUND;
881 ret = decode_BasicConstraints(e->extnValue.data,
882 e->extnValue.length, &bc,
883 &size);
884 if (ret)
885 return ret;
886 switch(type) {
887 case PROXY_CERT:
888 if (bc.cA != NULL && *bc.cA)
889 ret = HX509_PARENT_IS_CA;
890 break;
891 case EE_CERT:
892 ret = 0;
893 break;
894 case CA_CERT:
895 if (bc.cA == NULL || !*bc.cA)
896 ret = HX509_PARENT_NOT_CA;
897 else if (bc.pathLenConstraint)
898 if (depth - 1 > *bc.pathLenConstraint)
899 ret = HX509_CA_PATH_TOO_DEEP;
900 break;
902 free_BasicConstraints(&bc);
903 return ret;
907 _hx509_cert_is_parent_cmp(const Certificate *subject,
908 const Certificate *issuer,
909 int allow_self_signed)
911 int diff;
912 AuthorityKeyIdentifier ai;
913 SubjectKeyIdentifier si;
914 int ret_ai, ret_si, ret;
916 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
917 &subject->tbsCertificate.issuer,
918 &diff);
919 if (ret)
920 return ret;
921 if (diff)
922 return diff;
924 memset(&ai, 0, sizeof(ai));
925 memset(&si, 0, sizeof(si));
928 * Try to find AuthorityKeyIdentifier, if it's not present in the
929 * subject certificate nor the parent.
932 ret_ai = find_extension_auth_key_id(subject, &ai);
933 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
934 return 1;
935 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
936 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
937 return -1;
939 if (ret_si && ret_ai)
940 goto out;
941 if (ret_ai)
942 goto out;
943 if (ret_si) {
944 if (allow_self_signed) {
945 diff = 0;
946 goto out;
947 } else if (ai.keyIdentifier) {
948 diff = -1;
949 goto out;
953 if (ai.keyIdentifier == NULL) {
954 Name name;
956 if (ai.authorityCertIssuer == NULL)
957 return -1;
958 if (ai.authorityCertSerialNumber == NULL)
959 return -1;
961 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
962 &issuer->tbsCertificate.serialNumber);
963 if (diff)
964 return diff;
965 if (ai.authorityCertIssuer->len != 1)
966 return -1;
967 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
968 return -1;
970 name.element =
971 ai.authorityCertIssuer->val[0].u.directoryName.element;
972 name.u.rdnSequence =
973 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
975 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
976 &name,
977 &diff);
978 if (ret)
979 return ret;
980 if (diff)
981 return diff;
982 diff = 0;
983 } else
984 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
985 if (diff)
986 goto out;
988 out:
989 free_AuthorityKeyIdentifier(&ai);
990 free_SubjectKeyIdentifier(&si);
991 return diff;
994 static int
995 certificate_is_anchor(hx509_context context,
996 hx509_certs trust_anchors,
997 const hx509_cert cert)
999 hx509_query q;
1000 hx509_cert c;
1001 int ret;
1003 if (trust_anchors == NULL)
1004 return 0;
1006 _hx509_query_clear(&q);
1008 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1009 q.certificate = _hx509_get_cert(cert);
1011 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1012 if (ret == 0)
1013 hx509_cert_free(c);
1014 return ret == 0;
1017 static int
1018 certificate_is_self_signed(hx509_context context,
1019 const Certificate *cert,
1020 int *self_signed)
1022 int ret, diff;
1023 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1024 &cert->tbsCertificate.issuer, &diff);
1025 *self_signed = (diff == 0);
1026 if (ret)
1027 hx509_set_error_string(context, 0, ret,
1028 "Failed to check if self signed");
1029 return ret;
1033 * The subjectName is "null" when it's empty set of relative DBs.
1036 static int
1037 subject_null_p(const Certificate *c)
1039 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1043 static int
1044 find_parent(hx509_context context,
1045 time_t time_now,
1046 hx509_certs trust_anchors,
1047 hx509_path *path,
1048 hx509_certs pool,
1049 hx509_cert current,
1050 hx509_cert *parent)
1052 AuthorityKeyIdentifier ai;
1053 hx509_query q;
1054 int ret;
1056 *parent = NULL;
1057 memset(&ai, 0, sizeof(ai));
1059 _hx509_query_clear(&q);
1061 if (!subject_null_p(current->data)) {
1062 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1063 q.subject = _hx509_get_cert(current);
1064 } else {
1065 ret = find_extension_auth_key_id(current->data, &ai);
1066 if (ret) {
1067 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1068 "Subjectless certificate missing AuthKeyID");
1069 return HX509_CERTIFICATE_MALFORMED;
1072 if (ai.keyIdentifier == NULL) {
1073 free_AuthorityKeyIdentifier(&ai);
1074 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1075 "Subjectless certificate missing keyIdentifier "
1076 "inside AuthKeyID");
1077 return HX509_CERTIFICATE_MALFORMED;
1080 q.subject_id = ai.keyIdentifier;
1081 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1084 q.path = path;
1085 q.match |= HX509_QUERY_NO_MATCH_PATH;
1087 if (pool) {
1088 q.timenow = time_now;
1089 q.match |= HX509_QUERY_MATCH_TIME;
1091 ret = hx509_certs_find(context, pool, &q, parent);
1092 if (ret == 0) {
1093 free_AuthorityKeyIdentifier(&ai);
1094 return 0;
1096 q.match &= ~HX509_QUERY_MATCH_TIME;
1099 if (trust_anchors) {
1100 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1101 if (ret == 0) {
1102 free_AuthorityKeyIdentifier(&ai);
1103 return ret;
1106 free_AuthorityKeyIdentifier(&ai);
1109 hx509_name name;
1110 char *str;
1112 ret = hx509_cert_get_subject(current, &name);
1113 if (ret) {
1114 hx509_clear_error_string(context);
1115 return HX509_ISSUER_NOT_FOUND;
1117 ret = hx509_name_to_string(name, &str);
1118 hx509_name_free(&name);
1119 if (ret) {
1120 hx509_clear_error_string(context);
1121 return HX509_ISSUER_NOT_FOUND;
1124 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1125 "Failed to find issuer for "
1126 "certificate with subject: '%s'", str);
1127 free(str);
1129 return HX509_ISSUER_NOT_FOUND;
1136 static int
1137 is_proxy_cert(hx509_context context,
1138 const Certificate *cert,
1139 ProxyCertInfo *rinfo)
1141 ProxyCertInfo info;
1142 const Extension *e;
1143 size_t size;
1144 int ret, i = 0;
1146 if (rinfo)
1147 memset(rinfo, 0, sizeof(*rinfo));
1149 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1150 if (e == NULL) {
1151 hx509_clear_error_string(context);
1152 return HX509_EXTENSION_NOT_FOUND;
1155 ret = decode_ProxyCertInfo(e->extnValue.data,
1156 e->extnValue.length,
1157 &info,
1158 &size);
1159 if (ret) {
1160 hx509_clear_error_string(context);
1161 return ret;
1163 if (size != e->extnValue.length) {
1164 free_ProxyCertInfo(&info);
1165 hx509_clear_error_string(context);
1166 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1168 if (rinfo == NULL)
1169 free_ProxyCertInfo(&info);
1170 else
1171 *rinfo = info;
1173 return 0;
1177 * Path operations are like MEMORY based keyset, but with exposed
1178 * internal so we can do easy searches.
1182 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1184 hx509_cert *val;
1185 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1186 if (val == NULL) {
1187 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1188 return ENOMEM;
1191 path->val = val;
1192 path->val[path->len] = hx509_cert_ref(cert);
1193 path->len++;
1195 return 0;
1198 void
1199 _hx509_path_free(hx509_path *path)
1201 unsigned i;
1203 for (i = 0; i < path->len; i++)
1204 hx509_cert_free(path->val[i]);
1205 free(path->val);
1206 path->val = NULL;
1207 path->len = 0;
1211 * Find path by looking up issuer for the top certificate and continue
1212 * until an anchor certificate is found or max limit is found. A
1213 * certificate never included twice in the path.
1215 * If the trust anchors are not given, calculate optimistic path, just
1216 * follow the chain upward until we no longer find a parent or we hit
1217 * the max path limit. In this case, a failure will always be returned
1218 * depending on what error condition is hit first.
1220 * The path includes a path from the top certificate to the anchor
1221 * certificate.
1223 * The caller needs to free `path´ both on successful built path and
1224 * failure.
1228 _hx509_calculate_path(hx509_context context,
1229 int flags,
1230 time_t time_now,
1231 hx509_certs anchors,
1232 unsigned int max_depth,
1233 hx509_cert cert,
1234 hx509_certs pool,
1235 hx509_path *path)
1237 hx509_cert parent, current;
1238 int ret;
1240 if (max_depth == 0)
1241 max_depth = HX509_VERIFY_MAX_DEPTH;
1243 ret = _hx509_path_append(context, path, cert);
1244 if (ret)
1245 return ret;
1247 current = hx509_cert_ref(cert);
1249 while (!certificate_is_anchor(context, anchors, current)) {
1251 ret = find_parent(context, time_now, anchors, path,
1252 pool, current, &parent);
1253 hx509_cert_free(current);
1254 if (ret)
1255 return ret;
1257 ret = _hx509_path_append(context, path, parent);
1258 if (ret)
1259 return ret;
1260 current = parent;
1262 if (path->len > max_depth) {
1263 hx509_cert_free(current);
1264 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1265 "Path too long while bulding "
1266 "certificate chain");
1267 return HX509_PATH_TOO_LONG;
1271 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1272 path->len > 0 &&
1273 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1275 hx509_cert_free(path->val[path->len - 1]);
1276 path->len--;
1279 hx509_cert_free(current);
1280 return 0;
1284 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1285 const AlgorithmIdentifier *q)
1287 int diff;
1288 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1289 if (diff)
1290 return diff;
1291 if (p->parameters) {
1292 if (q->parameters)
1293 return heim_any_cmp(p->parameters,
1294 q->parameters);
1295 else
1296 return 1;
1297 } else {
1298 if (q->parameters)
1299 return -1;
1300 else
1301 return 0;
1306 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1308 int diff;
1309 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1310 if (diff)
1311 return diff;
1312 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1313 &q->signatureAlgorithm);
1314 if (diff)
1315 return diff;
1316 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1317 &q->tbsCertificate._save);
1318 return diff;
1322 * Compare to hx509 certificate object, useful for sorting.
1324 * @param p a hx509 certificate object.
1325 * @param q a hx509 certificate object.
1327 * @return 0 the objects are the same, returns > 0 is p is "larger"
1328 * then q, < 0 if p is "smaller" then q.
1330 * @ingroup hx509_cert
1334 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1336 return _hx509_Certificate_cmp(p->data, q->data);
1340 * Return the name of the issuer of the hx509 certificate.
1342 * @param p a hx509 certificate object.
1343 * @param name a pointer to a hx509 name, should be freed by
1344 * hx509_name_free().
1346 * @return An hx509 error code, see hx509_get_error_string().
1348 * @ingroup hx509_cert
1352 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1354 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1358 * Return the name of the subject of the hx509 certificate.
1360 * @param p a hx509 certificate object.
1361 * @param name a pointer to a hx509 name, should be freed by
1362 * hx509_name_free(). See also hx509_cert_get_base_subject().
1364 * @return An hx509 error code, see hx509_get_error_string().
1366 * @ingroup hx509_cert
1370 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1372 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1376 * Return the name of the base subject of the hx509 certificate. If
1377 * the certiicate is a verified proxy certificate, the this function
1378 * return the base certificate (root of the proxy chain). If the proxy
1379 * certificate is not verified with the base certificate
1380 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1382 * @param context a hx509 context.
1383 * @param c a hx509 certificate object.
1384 * @param name a pointer to a hx509 name, should be freed by
1385 * hx509_name_free(). See also hx509_cert_get_subject().
1387 * @return An hx509 error code, see hx509_get_error_string().
1389 * @ingroup hx509_cert
1393 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1394 hx509_name *name)
1396 if (c->basename)
1397 return hx509_name_copy(context, c->basename, name);
1398 if (is_proxy_cert(context, c->data, NULL) == 0) {
1399 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1400 hx509_set_error_string(context, 0, ret,
1401 "Proxy certificate have not been "
1402 "canonicalize yet, no base name");
1403 return ret;
1405 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1409 * Get serial number of the certificate.
1411 * @param p a hx509 certificate object.
1412 * @param i serial number, should be freed ith der_free_heim_integer().
1414 * @return An hx509 error code, see hx509_get_error_string().
1416 * @ingroup hx509_cert
1420 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1422 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1426 * Get notBefore time of the certificate.
1428 * @param p a hx509 certificate object.
1430 * @return return not before time
1432 * @ingroup hx509_cert
1435 time_t
1436 hx509_cert_get_notBefore(hx509_cert p)
1438 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1442 * Get notAfter time of the certificate.
1444 * @param p a hx509 certificate object.
1446 * @return return not after time.
1448 * @ingroup hx509_cert
1451 time_t
1452 hx509_cert_get_notAfter(hx509_cert p)
1454 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1458 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1460 * @param context a hx509 context.
1461 * @param p a hx509 certificate object.
1462 * @param spki SubjectPublicKeyInfo, should be freed with
1463 * free_SubjectPublicKeyInfo().
1465 * @return An hx509 error code, see hx509_get_error_string().
1467 * @ingroup hx509_cert
1471 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1473 int ret;
1475 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1476 if (ret)
1477 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1478 return ret;
1482 * Get the AlgorithmIdentifier from the hx509 certificate.
1484 * @param context a hx509 context.
1485 * @param p a hx509 certificate object.
1486 * @param alg AlgorithmIdentifier, should be freed with
1487 * free_AlgorithmIdentifier(). The algorithmidentifier is
1488 * typicly rsaEncryption, or id-ecPublicKey, or some other
1489 * public key mechanism.
1491 * @return An hx509 error code, see hx509_get_error_string().
1493 * @ingroup hx509_cert
1497 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1498 hx509_cert p,
1499 AlgorithmIdentifier *alg)
1501 int ret;
1503 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1504 if (ret)
1505 hx509_set_error_string(context, 0, ret,
1506 "Failed to copy SPKI AlgorithmIdentifier");
1507 return ret;
1511 hx509_private_key
1512 _hx509_cert_private_key(hx509_cert p)
1514 return p->private_key;
1518 hx509_cert_have_private_key(hx509_cert p)
1520 return p->private_key ? 1 : 0;
1525 _hx509_cert_private_key_exportable(hx509_cert p)
1527 if (p->private_key == NULL)
1528 return 0;
1529 return _hx509_private_key_exportable(p->private_key);
1533 _hx509_cert_private_decrypt(hx509_context context,
1534 const heim_octet_string *ciphertext,
1535 const heim_oid *encryption_oid,
1536 hx509_cert p,
1537 heim_octet_string *cleartext)
1539 cleartext->data = NULL;
1540 cleartext->length = 0;
1542 if (p->private_key == NULL) {
1543 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1544 "Private key missing");
1545 return HX509_PRIVATE_KEY_MISSING;
1548 return _hx509_private_key_private_decrypt(context,
1549 ciphertext,
1550 encryption_oid,
1551 p->private_key,
1552 cleartext);
1556 _hx509_cert_public_encrypt(hx509_context context,
1557 const heim_octet_string *cleartext,
1558 const hx509_cert p,
1559 heim_oid *encryption_oid,
1560 heim_octet_string *ciphertext)
1562 return _hx509_public_encrypt(context,
1563 cleartext, p->data,
1564 encryption_oid, ciphertext);
1571 time_t
1572 _hx509_Time2time_t(const Time *t)
1574 switch(t->element) {
1575 case choice_Time_utcTime:
1576 return t->u.utcTime;
1577 case choice_Time_generalTime:
1578 return t->u.generalTime;
1580 return 0;
1587 static int
1588 init_name_constraints(hx509_name_constraints *nc)
1590 memset(nc, 0, sizeof(*nc));
1591 return 0;
1594 static int
1595 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1596 hx509_name_constraints *nc)
1598 NameConstraints tnc;
1599 int ret;
1601 ret = find_extension_name_constraints(c, &tnc);
1602 if (ret == HX509_EXTENSION_NOT_FOUND)
1603 return 0;
1604 else if (ret) {
1605 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1606 return ret;
1607 } else if (not_ca) {
1608 ret = HX509_VERIFY_CONSTRAINTS;
1609 hx509_set_error_string(context, 0, ret, "Not a CA and "
1610 "have NameConstraints");
1611 } else {
1612 NameConstraints *val;
1613 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1614 if (val == NULL) {
1615 hx509_clear_error_string(context);
1616 ret = ENOMEM;
1617 goto out;
1619 nc->val = val;
1620 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1621 if (ret) {
1622 hx509_clear_error_string(context);
1623 goto out;
1625 nc->len += 1;
1627 out:
1628 free_NameConstraints(&tnc);
1629 return ret;
1632 static int
1633 match_RDN(const RelativeDistinguishedName *c,
1634 const RelativeDistinguishedName *n)
1636 int i;
1638 if (c->len != n->len)
1639 return HX509_NAME_CONSTRAINT_ERROR;
1641 for (i = 0; i < n->len; i++) {
1642 int diff, ret;
1644 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1645 return HX509_NAME_CONSTRAINT_ERROR;
1646 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1647 if (ret)
1648 return ret;
1649 if (diff != 0)
1650 return HX509_NAME_CONSTRAINT_ERROR;
1652 return 0;
1655 static int
1656 match_X501Name(const Name *c, const Name *n)
1658 int i, ret;
1660 if (c->element != choice_Name_rdnSequence
1661 || n->element != choice_Name_rdnSequence)
1662 return 0;
1663 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1664 return HX509_NAME_CONSTRAINT_ERROR;
1665 for (i = 0; i < c->u.rdnSequence.len; i++) {
1666 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1667 if (ret)
1668 return ret;
1670 return 0;
1674 static int
1675 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1678 * Name constraints only apply to the same name type, see RFC3280,
1679 * 4.2.1.11.
1681 assert(c->element == n->element);
1683 switch(c->element) {
1684 case choice_GeneralName_otherName:
1685 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1686 &n->u.otherName.type_id) != 0)
1687 return HX509_NAME_CONSTRAINT_ERROR;
1688 if (heim_any_cmp(&c->u.otherName.value,
1689 &n->u.otherName.value) != 0)
1690 return HX509_NAME_CONSTRAINT_ERROR;
1691 *match = 1;
1692 return 0;
1693 case choice_GeneralName_rfc822Name: {
1694 const char *s;
1695 size_t len1, len2;
1696 s = strchr(c->u.rfc822Name, '@');
1697 if (s) {
1698 if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1699 return HX509_NAME_CONSTRAINT_ERROR;
1700 } else {
1701 s = strchr(n->u.rfc822Name, '@');
1702 if (s == NULL)
1703 return HX509_NAME_CONSTRAINT_ERROR;
1704 len1 = strlen(c->u.rfc822Name);
1705 len2 = strlen(s + 1);
1706 if (len1 > len2)
1707 return HX509_NAME_CONSTRAINT_ERROR;
1708 if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1709 return HX509_NAME_CONSTRAINT_ERROR;
1710 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1711 return HX509_NAME_CONSTRAINT_ERROR;
1713 *match = 1;
1714 return 0;
1716 case choice_GeneralName_dNSName: {
1717 size_t lenc, lenn;
1719 lenc = strlen(c->u.dNSName);
1720 lenn = strlen(n->u.dNSName);
1721 if (lenc > lenn)
1722 return HX509_NAME_CONSTRAINT_ERROR;
1723 if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1724 return HX509_NAME_CONSTRAINT_ERROR;
1725 if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1726 return HX509_NAME_CONSTRAINT_ERROR;
1727 *match = 1;
1728 return 0;
1730 case choice_GeneralName_directoryName: {
1731 Name c_name, n_name;
1732 int ret;
1734 c_name._save.data = NULL;
1735 c_name._save.length = 0;
1736 c_name.element = c->u.directoryName.element;
1737 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1739 n_name._save.data = NULL;
1740 n_name._save.length = 0;
1741 n_name.element = n->u.directoryName.element;
1742 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1744 ret = match_X501Name(&c_name, &n_name);
1745 if (ret == 0)
1746 *match = 1;
1747 return ret;
1749 case choice_GeneralName_uniformResourceIdentifier:
1750 case choice_GeneralName_iPAddress:
1751 case choice_GeneralName_registeredID:
1752 default:
1753 return HX509_NAME_CONSTRAINT_ERROR;
1757 static int
1758 match_alt_name(const GeneralName *n, const Certificate *c,
1759 int *same, int *match)
1761 GeneralNames sa;
1762 int ret, i, j;
1764 i = 0;
1765 do {
1766 ret = find_extension_subject_alt_name(c, &i, &sa);
1767 if (ret == HX509_EXTENSION_NOT_FOUND) {
1768 ret = 0;
1769 break;
1770 } else if (ret != 0)
1771 break;
1773 for (j = 0; j < sa.len; j++) {
1774 if (n->element == sa.val[j].element) {
1775 *same = 1;
1776 ret = match_general_name(n, &sa.val[j], match);
1779 free_GeneralNames(&sa);
1780 } while (1);
1781 return ret;
1785 static int
1786 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1788 int name, alt_name, same;
1789 unsigned int i;
1790 int ret = 0;
1792 name = alt_name = same = *match = 0;
1793 for (i = 0; i < t->len; i++) {
1794 if (t->val[i].minimum && t->val[i].maximum)
1795 return HX509_RANGE;
1798 * If the constraint apply to directoryNames, test is with
1799 * subjectName of the certificate if the certificate have a
1800 * non-null (empty) subjectName.
1803 if (t->val[i].base.element == choice_GeneralName_directoryName
1804 && !subject_null_p(c))
1806 GeneralName certname;
1808 memset(&certname, 0, sizeof(certname));
1809 certname.element = choice_GeneralName_directoryName;
1810 certname.u.directoryName.element =
1811 c->tbsCertificate.subject.element;
1812 certname.u.directoryName.u.rdnSequence =
1813 c->tbsCertificate.subject.u.rdnSequence;
1815 ret = match_general_name(&t->val[i].base, &certname, &name);
1818 /* Handle subjectAltNames, this is icky since they
1819 * restrictions only apply if the subjectAltName is of the
1820 * same type. So if there have been a match of type, require
1821 * altname to be set.
1823 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1825 if (name && (!same || alt_name))
1826 *match = 1;
1827 return ret;
1830 static int
1831 check_name_constraints(hx509_context context,
1832 const hx509_name_constraints *nc,
1833 const Certificate *c)
1835 int match, ret;
1836 int i;
1838 for (i = 0 ; i < nc->len; i++) {
1839 GeneralSubtrees gs;
1841 if (nc->val[i].permittedSubtrees) {
1842 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1843 ret = match_tree(&gs, c, &match);
1844 if (ret) {
1845 hx509_clear_error_string(context);
1846 return ret;
1848 /* allow null subjectNames, they wont matches anything */
1849 if (match == 0 && !subject_null_p(c)) {
1850 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1851 "Error verify constraints, "
1852 "certificate didn't match any "
1853 "permitted subtree");
1854 return HX509_VERIFY_CONSTRAINTS;
1857 if (nc->val[i].excludedSubtrees) {
1858 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1859 ret = match_tree(&gs, c, &match);
1860 if (ret) {
1861 hx509_clear_error_string(context);
1862 return ret;
1864 if (match) {
1865 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1866 "Error verify constraints, "
1867 "certificate included in excluded "
1868 "subtree");
1869 return HX509_VERIFY_CONSTRAINTS;
1873 return 0;
1876 static void
1877 free_name_constraints(hx509_name_constraints *nc)
1879 int i;
1881 for (i = 0 ; i < nc->len; i++)
1882 free_NameConstraints(&nc->val[i]);
1883 free(nc->val);
1887 * Build and verify the path for the certificate to the trust anchor
1888 * specified in the verify context. The path is constructed from the
1889 * certificate, the pool and the trust anchors.
1891 * @param context A hx509 context.
1892 * @param ctx A hx509 verification context.
1893 * @param cert the certificate to build the path from.
1894 * @param pool A keyset of certificates to build the chain from.
1896 * @return An hx509 error code, see hx509_get_error_string().
1898 * @ingroup hx509_verify
1902 hx509_verify_path(hx509_context context,
1903 hx509_verify_ctx ctx,
1904 hx509_cert cert,
1905 hx509_certs pool)
1907 hx509_name_constraints nc;
1908 hx509_path path;
1909 int ret, i, proxy_cert_depth, selfsigned_depth, diff;
1910 enum certtype type;
1911 Name proxy_issuer;
1912 hx509_certs anchors = NULL;
1914 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1916 ret = init_name_constraints(&nc);
1917 if (ret)
1918 return ret;
1920 path.val = NULL;
1921 path.len = 0;
1923 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1924 ctx->time_now = time(NULL);
1929 if (ctx->trust_anchors)
1930 anchors = hx509_certs_ref(ctx->trust_anchors);
1931 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1932 anchors = hx509_certs_ref(context->default_trust_anchors);
1933 else {
1934 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1935 if (ret)
1936 goto out;
1940 * Calculate the path from the certificate user presented to the
1941 * to an anchor.
1943 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1944 anchors, ctx->max_depth,
1945 cert, pool, &path);
1946 if (ret)
1947 goto out;
1950 * Check CA and proxy certificate chain from the top of the
1951 * certificate chain. Also check certificate is valid with respect
1952 * to the current time.
1956 proxy_cert_depth = 0;
1957 selfsigned_depth = 0;
1959 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1960 type = PROXY_CERT;
1961 else
1962 type = EE_CERT;
1964 for (i = 0; i < path.len; i++) {
1965 Certificate *c;
1966 time_t t;
1968 c = _hx509_get_cert(path.val[i]);
1971 * Lets do some basic check on issuer like
1972 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1973 * on what type of certificate this is.
1976 switch (type) {
1977 case CA_CERT:
1979 /* XXX make constants for keyusage */
1980 ret = check_key_usage(context, c, 1 << 5,
1981 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1982 if (ret) {
1983 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1984 "Key usage missing from CA certificate");
1985 goto out;
1988 /* self signed cert doesn't add to path length */
1989 if (i + 1 != path.len) {
1990 int selfsigned;
1992 ret = certificate_is_self_signed(context, c, &selfsigned);
1993 if (ret)
1994 goto out;
1995 if (selfsigned)
1996 selfsigned_depth++;
1999 break;
2000 case PROXY_CERT: {
2001 ProxyCertInfo info;
2003 if (is_proxy_cert(context, c, &info) == 0) {
2004 int j;
2006 if (info.pCPathLenConstraint != NULL &&
2007 *info.pCPathLenConstraint < i)
2009 free_ProxyCertInfo(&info);
2010 ret = HX509_PATH_TOO_LONG;
2011 hx509_set_error_string(context, 0, ret,
2012 "Proxy certificate chain "
2013 "longer then allowed");
2014 goto out;
2016 /* XXX MUST check info.proxyPolicy */
2017 free_ProxyCertInfo(&info);
2019 j = 0;
2020 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2021 ret = HX509_PROXY_CERT_INVALID;
2022 hx509_set_error_string(context, 0, ret,
2023 "Proxy certificate have explicity "
2024 "forbidden subjectAltName");
2025 goto out;
2028 j = 0;
2029 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2030 ret = HX509_PROXY_CERT_INVALID;
2031 hx509_set_error_string(context, 0, ret,
2032 "Proxy certificate have explicity "
2033 "forbidden issuerAltName");
2034 goto out;
2038 * The subject name of the proxy certificate should be
2039 * CN=XXX,<proxy issuer>, prune of CN and check if its
2040 * the same over the whole chain of proxy certs and
2041 * then check with the EE cert when we get to it.
2044 if (proxy_cert_depth) {
2045 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2046 if (ret) {
2047 hx509_set_error_string(context, 0, ret, "Out of memory");
2048 goto out;
2050 if (diff) {
2051 ret = HX509_PROXY_CERT_NAME_WRONG;
2052 hx509_set_error_string(context, 0, ret,
2053 "Base proxy name not right");
2054 goto out;
2058 free_Name(&proxy_issuer);
2060 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2061 if (ret) {
2062 hx509_clear_error_string(context);
2063 goto out;
2066 j = proxy_issuer.u.rdnSequence.len;
2067 if (proxy_issuer.u.rdnSequence.len < 2
2068 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2069 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2070 &asn1_oid_id_at_commonName))
2072 ret = HX509_PROXY_CERT_NAME_WRONG;
2073 hx509_set_error_string(context, 0, ret,
2074 "Proxy name too short or "
2075 "does not have Common name "
2076 "at the top");
2077 goto out;
2080 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2081 proxy_issuer.u.rdnSequence.len -= 1;
2083 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2084 if (ret) {
2085 hx509_set_error_string(context, 0, ret, "Out of memory");
2086 goto out;
2088 if (diff != 0) {
2089 ret = HX509_PROXY_CERT_NAME_WRONG;
2090 hx509_set_error_string(context, 0, ret,
2091 "Proxy issuer name not as expected");
2092 goto out;
2095 break;
2096 } else {
2098 * Now we are done with the proxy certificates, this
2099 * cert was an EE cert and we we will fall though to
2100 * EE checking below.
2102 type = EE_CERT;
2103 /* FALLTHOUGH */
2106 case EE_CERT:
2108 * If there where any proxy certificates in the chain
2109 * (proxy_cert_depth > 0), check that the proxy issuer
2110 * matched proxy certificates "base" subject.
2112 if (proxy_cert_depth) {
2114 ret = _hx509_name_cmp(&proxy_issuer,
2115 &c->tbsCertificate.subject, &diff);
2116 if (ret) {
2117 hx509_set_error_string(context, 0, ret, "out of memory");
2118 goto out;
2120 if (diff) {
2121 ret = HX509_PROXY_CERT_NAME_WRONG;
2122 hx509_clear_error_string(context);
2123 goto out;
2125 if (cert->basename)
2126 hx509_name_free(&cert->basename);
2128 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2129 if (ret) {
2130 hx509_clear_error_string(context);
2131 goto out;
2135 break;
2138 ret = check_basic_constraints(context, c, type,
2139 i - proxy_cert_depth - selfsigned_depth);
2140 if (ret)
2141 goto out;
2144 * Don't check the trust anchors expiration time since they
2145 * are transported out of band, from RFC3820.
2147 if (i + 1 != path.len || CHECK_TA(ctx)) {
2149 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2150 if (t > ctx->time_now) {
2151 ret = HX509_CERT_USED_BEFORE_TIME;
2152 hx509_clear_error_string(context);
2153 goto out;
2155 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2156 if (t < ctx->time_now) {
2157 ret = HX509_CERT_USED_AFTER_TIME;
2158 hx509_clear_error_string(context);
2159 goto out;
2163 if (type == EE_CERT)
2164 type = CA_CERT;
2165 else if (type == PROXY_CERT)
2166 proxy_cert_depth++;
2170 * Verify constraints, do this backward so path constraints are
2171 * checked in the right order.
2174 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2175 Certificate *c;
2176 int selfsigned;
2178 c = _hx509_get_cert(path.val[i]);
2180 ret = certificate_is_self_signed(context, c, &selfsigned);
2181 if (ret)
2182 goto out;
2184 /* verify name constraints, not for selfsigned and anchor */
2185 if (!selfsigned || i + 1 != path.len) {
2186 ret = check_name_constraints(context, &nc, c);
2187 if (ret) {
2188 goto out;
2191 ret = add_name_constraints(context, c, i == 0, &nc);
2192 if (ret)
2193 goto out;
2195 /* XXX verify all other silly constraints */
2200 * Verify that no certificates has been revoked.
2203 if (ctx->revoke_ctx) {
2204 hx509_certs certs;
2206 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2207 NULL, &certs);
2208 if (ret)
2209 goto out;
2211 for (i = 0; i < path.len; i++) {
2212 ret = hx509_certs_add(context, certs, path.val[i]);
2213 if (ret) {
2214 hx509_certs_free(&certs);
2215 goto out;
2218 ret = hx509_certs_merge(context, certs, pool);
2219 if (ret) {
2220 hx509_certs_free(&certs);
2221 goto out;
2224 for (i = 0; i < path.len - 1; i++) {
2225 int parent = (i < path.len - 1) ? i + 1 : i;
2227 ret = hx509_revoke_verify(context,
2228 ctx->revoke_ctx,
2229 certs,
2230 ctx->time_now,
2231 path.val[i],
2232 path.val[parent]);
2233 if (ret) {
2234 hx509_certs_free(&certs);
2235 goto out;
2238 hx509_certs_free(&certs);
2242 * Verify signatures, do this backward so public key working
2243 * parameter is passed up from the anchor up though the chain.
2246 for (i = path.len - 1; i >= 0; i--) {
2247 hx509_cert signer;
2248 Certificate *c;
2250 c = _hx509_get_cert(path.val[i]);
2252 /* is last in chain (trust anchor) */
2253 if (i + 1 == path.len) {
2254 int selfsigned;
2256 signer = path.val[i];
2258 ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2259 if (ret)
2260 goto out;
2262 /* if trust anchor is not self signed, don't check sig */
2263 if (!selfsigned)
2264 continue;
2265 } else {
2266 /* take next certificate in chain */
2267 signer = path.val[i + 1];
2270 /* verify signatureValue */
2271 ret = _hx509_verify_signature_bitstring(context,
2272 signer,
2273 &c->signatureAlgorithm,
2274 &c->tbsCertificate._save,
2275 &c->signatureValue);
2276 if (ret) {
2277 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2278 "Failed to verify signature of certificate");
2279 goto out;
2282 * Verify that the sigature algorithm "best-before" date is
2283 * before the creation date of the certificate, do this for
2284 * trust anchors too, since any trust anchor that is created
2285 * after a algorithm is known to be bad deserved to be invalid.
2287 * Skip the leaf certificate for now...
2290 if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2291 time_t notBefore =
2292 _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2293 ret = _hx509_signature_best_before(context,
2294 &c->signatureAlgorithm,
2295 notBefore);
2296 if (ret)
2297 goto out;
2301 out:
2302 hx509_certs_free(&anchors);
2303 free_Name(&proxy_issuer);
2304 free_name_constraints(&nc);
2305 _hx509_path_free(&path);
2307 return ret;
2311 * Verify a signature made using the private key of an certificate.
2313 * @param context A hx509 context.
2314 * @param signer the certificate that made the signature.
2315 * @param alg algorthm that was used to sign the data.
2316 * @param data the data that was signed.
2317 * @param sig the sigature to verify.
2319 * @return An hx509 error code, see hx509_get_error_string().
2321 * @ingroup hx509_crypto
2325 hx509_verify_signature(hx509_context context,
2326 const hx509_cert signer,
2327 const AlgorithmIdentifier *alg,
2328 const heim_octet_string *data,
2329 const heim_octet_string *sig)
2331 return _hx509_verify_signature(context, signer, alg, data, sig);
2335 _hx509_verify_signature_bitstring(hx509_context context,
2336 const hx509_cert signer,
2337 const AlgorithmIdentifier *alg,
2338 const heim_octet_string *data,
2339 const heim_bit_string *sig)
2341 heim_octet_string os;
2343 if (sig->length & 7) {
2344 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2345 "signature not multiple of 8 bits");
2346 return HX509_CRYPTO_SIG_INVALID_FORMAT;
2349 os.data = sig->data;
2350 os.length = sig->length / 8;
2352 return _hx509_verify_signature(context, signer, alg, data, &os);
2358 * Verify that the certificate is allowed to be used for the hostname
2359 * and address.
2361 * @param context A hx509 context.
2362 * @param cert the certificate to match with
2363 * @param flags Flags to modify the behavior:
2364 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2365 * @param type type of hostname:
2366 * - HX509_HN_HOSTNAME for plain hostname.
2367 * - HX509_HN_DNSSRV for DNS SRV names.
2368 * @param hostname the hostname to check
2369 * @param sa address of the host
2370 * @param sa_size length of address
2372 * @return An hx509 error code, see hx509_get_error_string().
2374 * @ingroup hx509_cert
2378 hx509_verify_hostname(hx509_context context,
2379 const hx509_cert cert,
2380 int flags,
2381 hx509_hostname_type type,
2382 const char *hostname,
2383 const struct sockaddr *sa,
2384 /* XXX krb5_socklen_t */ int sa_size)
2386 GeneralNames san;
2387 const Name *name;
2388 int ret, i, j;
2390 if (sa && sa_size <= 0)
2391 return EINVAL;
2393 memset(&san, 0, sizeof(san));
2395 i = 0;
2396 do {
2397 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2398 if (ret == HX509_EXTENSION_NOT_FOUND)
2399 break;
2400 else if (ret != 0)
2401 return HX509_PARSING_NAME_FAILED;
2403 for (j = 0; j < san.len; j++) {
2404 switch (san.val[j].element) {
2405 case choice_GeneralName_dNSName:
2406 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2407 free_GeneralNames(&san);
2408 return 0;
2410 break;
2411 default:
2412 break;
2415 free_GeneralNames(&san);
2416 } while (1);
2418 name = &cert->data->tbsCertificate.subject;
2420 /* Find first CN= in the name, and try to match the hostname on that */
2421 for (ret = 0, i = name->u.rdnSequence.len - 1; ret == 0 && i >= 0; i--) {
2422 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2423 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2425 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2426 DirectoryString *ds = &n->value;
2427 switch (ds->element) {
2428 case choice_DirectoryString_printableString:
2429 if (strcasecmp(ds->u.printableString, hostname) == 0)
2430 return 0;
2431 break;
2432 case choice_DirectoryString_ia5String:
2433 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2434 return 0;
2435 break;
2436 case choice_DirectoryString_utf8String:
2437 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2438 return 0;
2439 default:
2440 break;
2442 ret = HX509_NAME_CONSTRAINT_ERROR;
2447 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2448 ret = HX509_NAME_CONSTRAINT_ERROR;
2450 return ret;
2454 _hx509_set_cert_attribute(hx509_context context,
2455 hx509_cert cert,
2456 const heim_oid *oid,
2457 const heim_octet_string *attr)
2459 hx509_cert_attribute a;
2460 void *d;
2462 if (hx509_cert_get_attribute(cert, oid) != NULL)
2463 return 0;
2465 d = realloc(cert->attrs.val,
2466 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2467 if (d == NULL) {
2468 hx509_clear_error_string(context);
2469 return ENOMEM;
2471 cert->attrs.val = d;
2473 a = malloc(sizeof(*a));
2474 if (a == NULL)
2475 return ENOMEM;
2477 der_copy_octet_string(attr, &a->data);
2478 der_copy_oid(oid, &a->oid);
2480 cert->attrs.val[cert->attrs.len] = a;
2481 cert->attrs.len++;
2483 return 0;
2487 * Get an external attribute for the certificate, examples are
2488 * friendly name and id.
2490 * @param cert hx509 certificate object to search
2491 * @param oid an oid to search for.
2493 * @return an hx509_cert_attribute, only valid as long as the
2494 * certificate is referenced.
2496 * @ingroup hx509_cert
2499 hx509_cert_attribute
2500 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2502 int i;
2503 for (i = 0; i < cert->attrs.len; i++)
2504 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2505 return cert->attrs.val[i];
2506 return NULL;
2510 * Set the friendly name on the certificate.
2512 * @param cert The certificate to set the friendly name on
2513 * @param name Friendly name.
2515 * @return An hx509 error code, see hx509_get_error_string().
2517 * @ingroup hx509_cert
2521 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2523 if (cert->friendlyname)
2524 free(cert->friendlyname);
2525 cert->friendlyname = strdup(name);
2526 if (cert->friendlyname == NULL)
2527 return ENOMEM;
2528 return 0;
2532 * Get friendly name of the certificate.
2534 * @param cert cert to get the friendly name from.
2536 * @return an friendly name or NULL if there is. The friendly name is
2537 * only valid as long as the certificate is referenced.
2539 * @ingroup hx509_cert
2542 const char *
2543 hx509_cert_get_friendly_name(hx509_cert cert)
2545 hx509_cert_attribute a;
2546 PKCS9_friendlyName n;
2547 size_t sz;
2548 int ret, i;
2550 if (cert->friendlyname)
2551 return cert->friendlyname;
2553 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2554 if (a == NULL) {
2555 hx509_name name;
2557 ret = hx509_cert_get_subject(cert, &name);
2558 if (ret)
2559 return NULL;
2560 ret = hx509_name_to_string(name, &cert->friendlyname);
2561 hx509_name_free(&name);
2562 if (ret)
2563 return NULL;
2564 return cert->friendlyname;
2567 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2568 if (ret)
2569 return NULL;
2571 if (n.len != 1) {
2572 free_PKCS9_friendlyName(&n);
2573 return NULL;
2576 cert->friendlyname = malloc(n.val[0].length + 1);
2577 if (cert->friendlyname == NULL) {
2578 free_PKCS9_friendlyName(&n);
2579 return NULL;
2582 for (i = 0; i < n.val[0].length; i++) {
2583 if (n.val[0].data[i] <= 0xff)
2584 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2585 else
2586 cert->friendlyname[i] = 'X';
2588 cert->friendlyname[i] = '\0';
2589 free_PKCS9_friendlyName(&n);
2591 return cert->friendlyname;
2594 void
2595 _hx509_query_clear(hx509_query *q)
2597 memset(q, 0, sizeof(*q));
2601 * Allocate an query controller. Free using hx509_query_free().
2603 * @param context A hx509 context.
2604 * @param q return pointer to a hx509_query.
2606 * @return An hx509 error code, see hx509_get_error_string().
2608 * @ingroup hx509_cert
2612 hx509_query_alloc(hx509_context context, hx509_query **q)
2614 *q = calloc(1, sizeof(**q));
2615 if (*q == NULL)
2616 return ENOMEM;
2617 return 0;
2622 * Set match options for the hx509 query controller.
2624 * @param q query controller.
2625 * @param option options to control the query controller.
2627 * @return An hx509 error code, see hx509_get_error_string().
2629 * @ingroup hx509_cert
2632 void
2633 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2635 switch(option) {
2636 case HX509_QUERY_OPTION_PRIVATE_KEY:
2637 q->match |= HX509_QUERY_PRIVATE_KEY;
2638 break;
2639 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2640 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2641 break;
2642 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2643 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2644 break;
2645 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2646 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2647 break;
2648 case HX509_QUERY_OPTION_END:
2649 default:
2650 break;
2655 * Set the issuer and serial number of match in the query
2656 * controller. The function make copies of the isser and serial number.
2658 * @param q a hx509 query controller
2659 * @param issuer issuer to search for
2660 * @param serialNumber the serialNumber of the issuer.
2662 * @return An hx509 error code, see hx509_get_error_string().
2664 * @ingroup hx509_cert
2668 hx509_query_match_issuer_serial(hx509_query *q,
2669 const Name *issuer,
2670 const heim_integer *serialNumber)
2672 int ret;
2673 if (q->serial) {
2674 der_free_heim_integer(q->serial);
2675 free(q->serial);
2677 q->serial = malloc(sizeof(*q->serial));
2678 if (q->serial == NULL)
2679 return ENOMEM;
2680 ret = der_copy_heim_integer(serialNumber, q->serial);
2681 if (ret) {
2682 free(q->serial);
2683 q->serial = NULL;
2684 return ret;
2686 if (q->issuer_name) {
2687 free_Name(q->issuer_name);
2688 free(q->issuer_name);
2690 q->issuer_name = malloc(sizeof(*q->issuer_name));
2691 if (q->issuer_name == NULL)
2692 return ENOMEM;
2693 ret = copy_Name(issuer, q->issuer_name);
2694 if (ret) {
2695 free(q->issuer_name);
2696 q->issuer_name = NULL;
2697 return ret;
2699 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2700 return 0;
2704 * Set the query controller to match on a friendly name
2706 * @param q a hx509 query controller.
2707 * @param name a friendly name to match on
2709 * @return An hx509 error code, see hx509_get_error_string().
2711 * @ingroup hx509_cert
2715 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2717 if (q->friendlyname)
2718 free(q->friendlyname);
2719 q->friendlyname = strdup(name);
2720 if (q->friendlyname == NULL)
2721 return ENOMEM;
2722 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2723 return 0;
2727 * Set the query controller to require an one specific EKU (extended
2728 * key usage). Any previous EKU matching is overwitten. If NULL is
2729 * passed in as the eku, the EKU requirement is reset.
2731 * @param q a hx509 query controller.
2732 * @param eku an EKU to match on.
2734 * @return An hx509 error code, see hx509_get_error_string().
2736 * @ingroup hx509_cert
2740 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2742 int ret;
2744 if (eku == NULL) {
2745 if (q->eku) {
2746 der_free_oid(q->eku);
2747 free(q->eku);
2748 q->eku = NULL;
2750 q->match &= ~HX509_QUERY_MATCH_EKU;
2751 } else {
2752 if (q->eku) {
2753 der_free_oid(q->eku);
2754 } else {
2755 q->eku = calloc(1, sizeof(*q->eku));
2756 if (q->eku == NULL)
2757 return ENOMEM;
2759 ret = der_copy_oid(eku, q->eku);
2760 if (ret) {
2761 free(q->eku);
2762 q->eku = NULL;
2763 return ret;
2765 q->match |= HX509_QUERY_MATCH_EKU;
2767 return 0;
2771 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2773 if (q->expr) {
2774 _hx509_expr_free(q->expr);
2775 q->expr = NULL;
2778 if (expr == NULL) {
2779 q->match &= ~HX509_QUERY_MATCH_EXPR;
2780 } else {
2781 q->expr = _hx509_expr_parse(expr);
2782 if (q->expr)
2783 q->match |= HX509_QUERY_MATCH_EXPR;
2786 return 0;
2790 * Set the query controller to match using a specific match function.
2792 * @param q a hx509 query controller.
2793 * @param func function to use for matching, if the argument is NULL,
2794 * the match function is removed.
2795 * @param ctx context passed to the function.
2797 * @return An hx509 error code, see hx509_get_error_string().
2799 * @ingroup hx509_cert
2803 hx509_query_match_cmp_func(hx509_query *q,
2804 int (*func)(hx509_context, hx509_cert, void *),
2805 void *ctx)
2807 if (func)
2808 q->match |= HX509_QUERY_MATCH_FUNCTION;
2809 else
2810 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2811 q->cmp_func = func;
2812 q->cmp_func_ctx = ctx;
2813 return 0;
2817 * Free the query controller.
2819 * @param context A hx509 context.
2820 * @param q a pointer to the query controller.
2822 * @ingroup hx509_cert
2825 void
2826 hx509_query_free(hx509_context context, hx509_query *q)
2828 if (q == NULL)
2829 return;
2831 if (q->serial) {
2832 der_free_heim_integer(q->serial);
2833 free(q->serial);
2835 if (q->issuer_name) {
2836 free_Name(q->issuer_name);
2837 free(q->issuer_name);
2839 if (q->eku) {
2840 der_free_oid(q->eku);
2841 free(q->eku);
2843 if (q->friendlyname)
2844 free(q->friendlyname);
2845 if (q->expr)
2846 _hx509_expr_free(q->expr);
2848 memset(q, 0, sizeof(*q));
2849 free(q);
2853 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2855 Certificate *c = _hx509_get_cert(cert);
2856 int ret, diff;
2858 _hx509_query_statistic(context, 1, q);
2860 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2861 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2862 return 0;
2864 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2865 _hx509_Certificate_cmp(q->certificate, c) != 0)
2866 return 0;
2868 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2869 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2870 return 0;
2872 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2873 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2874 if (ret || diff)
2875 return 0;
2878 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2879 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2880 if (ret || diff)
2881 return 0;
2884 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2885 SubjectKeyIdentifier si;
2887 ret = _hx509_find_extension_subject_key_id(c, &si);
2888 if (ret == 0) {
2889 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2890 ret = 1;
2891 free_SubjectKeyIdentifier(&si);
2893 if (ret)
2894 return 0;
2896 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2897 return 0;
2898 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2899 _hx509_cert_private_key(cert) == NULL)
2900 return 0;
2903 unsigned ku = 0;
2904 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2905 ku |= (1 << 0);
2906 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2907 ku |= (1 << 1);
2908 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2909 ku |= (1 << 2);
2910 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2911 ku |= (1 << 3);
2912 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2913 ku |= (1 << 4);
2914 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2915 ku |= (1 << 5);
2916 if (q->match & HX509_QUERY_KU_CRLSIGN)
2917 ku |= (1 << 6);
2918 if (ku && check_key_usage(context, c, ku, TRUE))
2919 return 0;
2921 if ((q->match & HX509_QUERY_ANCHOR))
2922 return 0;
2924 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2925 hx509_cert_attribute a;
2927 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
2928 if (a == NULL)
2929 return 0;
2930 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2931 return 0;
2934 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2935 size_t i;
2937 for (i = 0; i < q->path->len; i++)
2938 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2939 return 0;
2941 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2942 const char *name = hx509_cert_get_friendly_name(cert);
2943 if (name == NULL)
2944 return 0;
2945 if (strcasecmp(q->friendlyname, name) != 0)
2946 return 0;
2948 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2949 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
2950 if (ret != 0)
2951 return 0;
2954 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2955 heim_octet_string os;
2957 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2958 os.length =
2959 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2961 ret = _hx509_verify_signature(context,
2962 NULL,
2963 hx509_signature_sha1(),
2964 &os,
2965 q->keyhash_sha1);
2966 if (ret != 0)
2967 return 0;
2970 if (q->match & HX509_QUERY_MATCH_TIME) {
2971 time_t t;
2972 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2973 if (t > q->timenow)
2974 return 0;
2975 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2976 if (t < q->timenow)
2977 return 0;
2980 /* If an EKU is required, check the cert for it. */
2981 if ((q->match & HX509_QUERY_MATCH_EKU) &&
2982 hx509_cert_check_eku(context, cert, q->eku, 0))
2983 return 0;
2985 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
2986 hx509_env env = NULL;
2988 ret = _hx509_cert_to_env(context, cert, &env);
2989 if (ret)
2990 return 0;
2992 ret = _hx509_expr_eval(context, env, q->expr);
2993 hx509_env_free(&env);
2994 if (ret == 0)
2995 return 0;
2998 if (q->match & ~HX509_QUERY_MASK)
2999 return 0;
3001 return 1;
3005 * Set a statistic file for the query statistics.
3007 * @param context A hx509 context.
3008 * @param fn statistics file name
3010 * @ingroup hx509_cert
3013 void
3014 hx509_query_statistic_file(hx509_context context, const char *fn)
3016 if (context->querystat)
3017 free(context->querystat);
3018 context->querystat = strdup(fn);
3021 void
3022 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3024 FILE *f;
3025 if (context->querystat == NULL)
3026 return;
3027 f = fopen(context->querystat, "a");
3028 if (f == NULL)
3029 return;
3030 rk_cloexec_file(f);
3031 fprintf(f, "%d %d\n", type, q->match);
3032 fclose(f);
3035 static const char *statname[] = {
3036 "find issuer cert",
3037 "match serialnumber",
3038 "match issuer name",
3039 "match subject name",
3040 "match subject key id",
3041 "match issuer id",
3042 "private key",
3043 "ku encipherment",
3044 "ku digitalsignature",
3045 "ku keycertsign",
3046 "ku crlsign",
3047 "ku nonrepudiation",
3048 "ku keyagreement",
3049 "ku dataencipherment",
3050 "anchor",
3051 "match certificate",
3052 "match local key id",
3053 "no match path",
3054 "match friendly name",
3055 "match function",
3056 "match key hash sha1",
3057 "match time"
3060 struct stat_el {
3061 unsigned long stats;
3062 unsigned int index;
3066 static int
3067 stat_sort(const void *a, const void *b)
3069 const struct stat_el *ae = a;
3070 const struct stat_el *be = b;
3071 return be->stats - ae->stats;
3075 * Unparse the statistics file and print the result on a FILE descriptor.
3077 * @param context A hx509 context.
3078 * @param printtype tyep to print
3079 * @param out the FILE to write the data on.
3081 * @ingroup hx509_cert
3084 void
3085 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3087 rtbl_t t;
3088 FILE *f;
3089 int type, mask, i, num;
3090 unsigned long multiqueries = 0, totalqueries = 0;
3091 struct stat_el stats[32];
3093 if (context->querystat == NULL)
3094 return;
3095 f = fopen(context->querystat, "r");
3096 if (f == NULL) {
3097 fprintf(out, "No statistic file %s: %s.\n",
3098 context->querystat, strerror(errno));
3099 return;
3101 rk_cloexec_file(f);
3103 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3104 stats[i].index = i;
3105 stats[i].stats = 0;
3108 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3109 if (type != printtype)
3110 continue;
3111 num = i = 0;
3112 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3113 if (mask & 1) {
3114 stats[i].stats++;
3115 num++;
3117 mask = mask >>1 ;
3118 i++;
3120 if (num > 1)
3121 multiqueries++;
3122 totalqueries++;
3124 fclose(f);
3126 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3128 t = rtbl_create();
3129 if (t == NULL)
3130 errx(1, "out of memory");
3132 rtbl_set_separator (t, " ");
3134 rtbl_add_column_by_id (t, 0, "Name", 0);
3135 rtbl_add_column_by_id (t, 1, "Counter", 0);
3138 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3139 char str[10];
3141 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3142 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3143 else {
3144 snprintf(str, sizeof(str), "%d", stats[i].index);
3145 rtbl_add_column_entry_by_id (t, 0, str);
3147 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3148 rtbl_add_column_entry_by_id (t, 1, str);
3151 rtbl_format(t, out);
3152 rtbl_destroy(t);
3154 fprintf(out, "\nQueries: multi %lu total %lu\n",
3155 multiqueries, totalqueries);
3159 * Check the extended key usage on the hx509 certificate.
3161 * @param context A hx509 context.
3162 * @param cert A hx509 context.
3163 * @param eku the EKU to check for
3164 * @param allow_any_eku if the any EKU is set, allow that to be a
3165 * substitute.
3167 * @return An hx509 error code, see hx509_get_error_string().
3169 * @ingroup hx509_cert
3173 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3174 const heim_oid *eku, int allow_any_eku)
3176 ExtKeyUsage e;
3177 int ret, i;
3179 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3180 if (ret) {
3181 hx509_clear_error_string(context);
3182 return ret;
3185 for (i = 0; i < e.len; i++) {
3186 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3187 free_ExtKeyUsage(&e);
3188 return 0;
3190 if (allow_any_eku) {
3191 #if 0
3192 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3193 free_ExtKeyUsage(&e);
3194 return 0;
3196 #endif
3199 free_ExtKeyUsage(&e);
3200 hx509_clear_error_string(context);
3201 return HX509_CERTIFICATE_MISSING_EKU;
3205 _hx509_cert_get_keyusage(hx509_context context,
3206 hx509_cert c,
3207 KeyUsage *ku)
3209 Certificate *cert;
3210 const Extension *e;
3211 size_t size;
3212 int ret, i = 0;
3214 memset(ku, 0, sizeof(*ku));
3216 cert = _hx509_get_cert(c);
3218 if (_hx509_cert_get_version(cert) < 3)
3219 return 0;
3221 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3222 if (e == NULL)
3223 return HX509_KU_CERT_MISSING;
3225 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3226 if (ret)
3227 return ret;
3228 return 0;
3232 _hx509_cert_get_eku(hx509_context context,
3233 hx509_cert cert,
3234 ExtKeyUsage *e)
3236 int ret;
3238 memset(e, 0, sizeof(*e));
3240 ret = find_extension_eku(_hx509_get_cert(cert), e);
3241 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3242 hx509_clear_error_string(context);
3243 return ret;
3245 return 0;
3249 * Encodes the hx509 certificate as a DER encode binary.
3251 * @param context A hx509 context.
3252 * @param c the certificate to encode.
3253 * @param os the encode certificate, set to NULL, 0 on case of
3254 * error. Free the returned structure with hx509_xfree().
3256 * @return An hx509 error code, see hx509_get_error_string().
3258 * @ingroup hx509_cert
3262 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3264 size_t size;
3265 int ret;
3267 os->data = NULL;
3268 os->length = 0;
3270 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3271 _hx509_get_cert(c), &size, ret);
3272 if (ret) {
3273 os->data = NULL;
3274 os->length = 0;
3275 return ret;
3277 if (os->length != size)
3278 _hx509_abort("internal ASN.1 encoder error");
3280 return ret;
3284 * Last to avoid lost __attribute__s due to #undef.
3287 #undef __attribute__
3288 #define __attribute__(X)
3290 void
3291 _hx509_abort(const char *fmt, ...)
3292 __attribute__ ((noreturn, format (printf, 1, 2)))
3294 va_list ap;
3295 va_start(ap, fmt);
3296 vprintf(fmt, ap);
3297 va_end(ap);
3298 printf("\n");
3299 fflush(stdout);
3300 abort();
3304 * Free a data element allocated in the library.
3306 * @param ptr data to be freed.
3308 * @ingroup hx509_misc
3311 void
3312 hx509_xfree(void *ptr)
3314 free(ptr);
3322 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3324 ExtKeyUsage eku;
3325 hx509_name name;
3326 char *buf;
3327 int ret;
3328 hx509_env envcert = NULL;
3330 *env = NULL;
3332 /* version */
3333 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3334 ret = hx509_env_add(context, &envcert, "version", buf);
3335 free(buf);
3336 if (ret)
3337 goto out;
3339 /* subject */
3340 ret = hx509_cert_get_subject(cert, &name);
3341 if (ret)
3342 goto out;
3344 ret = hx509_name_to_string(name, &buf);
3345 if (ret) {
3346 hx509_name_free(&name);
3347 goto out;
3350 ret = hx509_env_add(context, &envcert, "subject", buf);
3351 hx509_name_free(&name);
3352 if (ret)
3353 goto out;
3355 /* issuer */
3356 ret = hx509_cert_get_issuer(cert, &name);
3357 if (ret)
3358 goto out;
3360 ret = hx509_name_to_string(name, &buf);
3361 hx509_name_free(&name);
3362 if (ret)
3363 goto out;
3365 ret = hx509_env_add(context, &envcert, "issuer", buf);
3366 hx509_xfree(buf);
3367 if (ret)
3368 goto out;
3370 /* eku */
3372 ret = _hx509_cert_get_eku(context, cert, &eku);
3373 if (ret == HX509_EXTENSION_NOT_FOUND)
3375 else if (ret != 0)
3376 goto out;
3377 else {
3378 int i;
3379 hx509_env enveku = NULL;
3381 for (i = 0; i < eku.len; i++) {
3383 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3384 if (ret) {
3385 free_ExtKeyUsage(&eku);
3386 hx509_env_free(&enveku);
3387 goto out;
3389 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3390 free(buf);
3391 if (ret) {
3392 free_ExtKeyUsage(&eku);
3393 hx509_env_free(&enveku);
3394 goto out;
3397 free_ExtKeyUsage(&eku);
3399 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3400 if (ret) {
3401 hx509_env_free(&enveku);
3402 goto out;
3407 Certificate *c = _hx509_get_cert(cert);
3408 heim_octet_string os, sig;
3409 hx509_env envhash = NULL;
3411 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3412 os.length =
3413 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3415 ret = _hx509_create_signature(context,
3416 NULL,
3417 hx509_signature_sha1(),
3418 &os,
3419 NULL,
3420 &sig);
3421 if (ret != 0)
3422 goto out;
3424 ret = hex_encode(sig.data, sig.length, &buf);
3425 der_free_octet_string(&sig);
3426 if (ret < 0) {
3427 ret = ENOMEM;
3428 hx509_set_error_string(context, 0, ret,
3429 "Out of memory");
3430 goto out;
3433 ret = hx509_env_add(context, &envhash, "sha1", buf);
3434 free(buf);
3435 if (ret)
3436 goto out;
3438 ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3439 if (ret) {
3440 hx509_env_free(&envhash);
3441 goto out;
3445 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3446 if (ret)
3447 goto out;
3449 return 0;
3451 out:
3452 hx509_env_free(&envcert);
3453 return ret;
3457 * Print a simple representation of a certificate
3459 * @param context A hx509 context, can be NULL
3460 * @param cert certificate to print
3461 * @param out the stdio output stream, if NULL, stdout is used
3463 * @return An hx509 error code
3465 * @ingroup hx509_cert
3469 hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3471 hx509_name name;
3472 char *str;
3473 int ret;
3475 if (out == NULL)
3476 out = stderr;
3478 ret = hx509_cert_get_issuer(cert, &name);
3479 if (ret)
3480 return ret;
3481 hx509_name_to_string(name, &str);
3482 hx509_name_free(&name);
3483 fprintf(out, " issuer: \"%s\"\n", str);
3484 free(str);
3486 ret = hx509_cert_get_subject(cert, &name);
3487 if (ret)
3488 return ret;
3489 hx509_name_to_string(name, &str);
3490 hx509_name_free(&name);
3491 fprintf(out, " subject: \"%s\"\n", str);
3492 free(str);
3495 heim_integer serialNumber;
3497 ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3498 if (ret)
3499 return ret;
3500 ret = der_print_hex_heim_integer(&serialNumber, &str);
3501 if (ret)
3502 return ret;
3503 der_free_heim_integer(&serialNumber);
3504 fprintf(out, " serial: %s\n", str);
3505 free(str);
3508 printf(" keyusage: ");
3509 ret = hx509_cert_keyusage_print(context, cert, &str);
3510 if (ret == 0) {
3511 fprintf(out, "%s\n", str);
3512 free(str);
3513 } else
3514 fprintf(out, "no");
3516 return 0;