more documentation
[heimdal.git] / lib / hx509 / cert.c
blobdb7adf001f15f90c22157482b6a3a7112a4f0dd3
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 RCSID("$Id$");
36 #include "crypto-headers.h"
37 #include <rtbl.h>
39 /**
40 * @page page_cert The basic certificate
42 * The basic hx509 cerificate object in hx509 is hx509_cert. The
43 * hx509_cert object is representing one X509/PKIX certificate and
44 * associated attributes; like private key, friendly name, etc.
46 * A hx509_cert object is usully found via the keyset interfaces (@ref
47 * page_keyset), but its also possible to create a certificate
48 * directly from a parsed object with hx509_cert_init() and
49 * hx509_cert_init_data().
51 * See the library functions here: @ref hx509_cert
54 struct hx509_verify_ctx_data {
55 hx509_certs trust_anchors;
56 int flags;
57 #define HX509_VERIFY_CTX_F_TIME_SET 1
58 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
59 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
60 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
61 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
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 (OSCP, 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;
200 #if 0
201 void
202 _hx509_print_cert_subject(hx509_cert cert)
204 char *subject_name;
205 hx509_name name;
206 int ret;
208 ret = hx509_cert_get_subject(cert, &name);
209 if (ret)
210 abort();
212 ret = hx509_name_to_string(name, &subject_name);
213 hx509_name_free(&name);
214 if (ret)
215 abort();
217 printf("name: %s\n", subject_name);
219 free(subject_name);
221 #endif
228 _hx509_cert_get_version(const Certificate *t)
230 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
234 * Allocate and init an hx509 certificate object from the decoded
235 * certificate `c´.
237 * @param context A hx509 context.
238 * @param c
239 * @param cert
241 * @return Returns an hx509 error code.
243 * @ingroup hx509_cert
247 hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
249 int ret;
251 *cert = malloc(sizeof(**cert));
252 if (*cert == NULL)
253 return ENOMEM;
254 (*cert)->ref = 1;
255 (*cert)->friendlyname = NULL;
256 (*cert)->attrs.len = 0;
257 (*cert)->attrs.val = NULL;
258 (*cert)->private_key = NULL;
259 (*cert)->basename = NULL;
260 (*cert)->release = NULL;
261 (*cert)->ctx = NULL;
263 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
264 if ((*cert)->data == NULL) {
265 free(*cert);
266 return ENOMEM;
268 ret = copy_Certificate(c, (*cert)->data);
269 if (ret) {
270 free((*cert)->data);
271 free(*cert);
272 *cert = NULL;
274 return ret;
278 * Just like hx509_cert_init(), but instead of a decode certificate
279 * takes an pointer and length to a memory region that contains a
280 * DER/BER encoded certificate.
282 * If the memory region doesn't contain just the certificate and
283 * nothing more the function will fail with
284 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
286 * @param context A hx509 context.
287 * @param ptr pointer to memory region containing encoded certificate.
288 * @param len length of memory region.
289 * @param cert a return pointer to a hx509 certificate object, will
290 * contain NULL on error.
292 * @return An hx509 error code, see hx509_get_error_string().
294 * @ingroup hx509_cert
298 hx509_cert_init_data(hx509_context context,
299 const void *ptr,
300 size_t len,
301 hx509_cert *cert)
303 Certificate t;
304 size_t size;
305 int ret;
307 ret = decode_Certificate(ptr, len, &t, &size);
308 if (ret) {
309 hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
310 return ret;
312 if (size != len) {
313 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
314 "Extra data after certificate");
315 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
318 ret = hx509_cert_init(context, &t, cert);
319 free_Certificate(&t);
320 return ret;
323 void
324 _hx509_cert_set_release(hx509_cert cert,
325 _hx509_cert_release_func release,
326 void *ctx)
328 cert->release = release;
329 cert->ctx = ctx;
333 /* Doesn't make a copy of `private_key'. */
336 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
338 if (cert->private_key)
339 _hx509_private_key_free(&cert->private_key);
340 cert->private_key = _hx509_private_key_ref(private_key);
341 return 0;
345 * Free reference to the hx509 certificate object, if the refcounter
346 * reaches 0, the object if freed. Its allowed to pass in NULL.
348 * @param cert the cert to free.
350 * @ingroup hx509_cert
353 void
354 hx509_cert_free(hx509_cert cert)
356 int i;
358 if (cert == NULL)
359 return;
361 if (cert->ref <= 0)
362 _hx509_abort("cert refcount <= 0 on free");
363 if (--cert->ref > 0)
364 return;
366 if (cert->release)
367 (cert->release)(cert, cert->ctx);
369 if (cert->private_key)
370 _hx509_private_key_free(&cert->private_key);
372 free_Certificate(cert->data);
373 free(cert->data);
375 for (i = 0; i < cert->attrs.len; i++) {
376 der_free_octet_string(&cert->attrs.val[i]->data);
377 der_free_oid(&cert->attrs.val[i]->oid);
378 free(cert->attrs.val[i]);
380 free(cert->attrs.val);
381 free(cert->friendlyname);
382 if (cert->basename)
383 hx509_name_free(&cert->basename);
384 memset(cert, 0, sizeof(cert));
385 free(cert);
389 * Add a reference to a hx509 certificate object.
391 * @param cert a pointer to an hx509 certificate object.
393 * @return the same object as is passed in.
395 * @ingroup hx509_cert
398 hx509_cert
399 hx509_cert_ref(hx509_cert cert)
401 if (cert == NULL)
402 return NULL;
403 if (cert->ref <= 0)
404 _hx509_abort("cert refcount <= 0");
405 cert->ref++;
406 if (cert->ref == 0)
407 _hx509_abort("cert refcount == 0");
408 return cert;
412 * Allocate an verification context that is used fo control the
413 * verification process.
415 * @param context A hx509 context.
416 * @param ctx returns a pointer to a hx509_verify_ctx object.
418 * @return An hx509 error code, see hx509_get_error_string().
420 * @ingroup hx509_verify
424 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
426 hx509_verify_ctx c;
428 c = calloc(1, sizeof(*c));
429 if (c == NULL)
430 return ENOMEM;
432 c->max_depth = HX509_VERIFY_MAX_DEPTH;
434 *ctx = c;
436 return 0;
440 * Free an hx509 verification context.
442 * @param ctx the context to be freed.
444 * @ingroup hx509_verify
447 void
448 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
450 if (ctx) {
451 hx509_certs_free(&ctx->trust_anchors);
452 hx509_revoke_free(&ctx->revoke_ctx);
453 memset(ctx, 0, sizeof(*ctx));
455 free(ctx);
459 * Set the trust anchors in the verification context, makes an
460 * reference to the keyset, so the consumer can free the keyset
461 * independent of the destruction of the verification context (ctx).
463 * @param ctx a verification context
464 * @param set a keyset containing the trust anchors.
466 * @ingroup hx509_verify
469 void
470 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
472 ctx->trust_anchors = _hx509_certs_ref(set);
476 * Attach an revocation context to the verfication context, , makes an
477 * reference to the revoke context, so the consumer can free the
478 * revoke context independent of the destruction of the verification
479 * context. If there is no revoke context, the verification process is
480 * NOT going to check any verification status.
482 * @param ctx a verification context.
483 * @param revoke_ctx a revoke context.
485 * @ingroup hx509_verify
488 void
489 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
491 if (ctx->revoke_ctx)
492 hx509_revoke_free(&ctx->revoke_ctx);
493 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
497 * Set the clock time the the verification process is going to
498 * use. Used to check certificate in the past and future time. If not
499 * set the current time will be used.
501 * @param ctx a verification context.
502 * @param t the time the verifiation is using.
505 * @ingroup hx509_verify
508 void
509 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
511 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
512 ctx->time_now = t;
516 * Set the maximum depth of the certificate chain that the path
517 * builder is going to try.
519 * @param ctx a verification context
520 * @param max_depth maxium depth of the certificate chain, include
521 * trust anchor.
523 * @ingroup hx509_verify
526 void
527 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
529 ctx->max_depth = max_depth;
533 * Allow or deny the use of proxy certificates
535 * @param ctx a verification context
536 * @param boolean if non zero, allow proxy certificates.
538 * @ingroup hx509_verify
541 void
542 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
544 if (boolean)
545 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
546 else
547 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
551 * Select strict RFC3280 verification of certificiates. This means
552 * checking key usage on CA certificates, this will make version 1
553 * certificiates unuseable.
555 * @param ctx a verification context
556 * @param boolean if non zero, use strict verification.
558 * @ingroup hx509_verify
561 void
562 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
564 if (boolean)
565 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
566 else
567 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
571 * Allow using the operating system builtin trust anchors if no other
572 * trust anchors are configured.
574 * @param ctx a verification context
575 * @param boolean if non zero, useing the operating systems builtin
576 * trust anchors.
579 * @return An hx509 error code, see hx509_get_error_string().
581 * @ingroup hx509_cert
584 void
585 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
587 if (boolean)
588 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
589 else
590 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
593 static const Extension *
594 find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
596 const TBSCertificate *c = &cert->tbsCertificate;
598 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
599 return NULL;
601 for (;*idx < c->extensions->len; (*idx)++) {
602 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
603 return &c->extensions->val[(*idx)++];
605 return NULL;
608 static int
609 find_extension_auth_key_id(const Certificate *subject,
610 AuthorityKeyIdentifier *ai)
612 const Extension *e;
613 size_t size;
614 int i = 0;
616 memset(ai, 0, sizeof(*ai));
618 e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i);
619 if (e == NULL)
620 return HX509_EXTENSION_NOT_FOUND;
622 return decode_AuthorityKeyIdentifier(e->extnValue.data,
623 e->extnValue.length,
624 ai, &size);
628 _hx509_find_extension_subject_key_id(const Certificate *issuer,
629 SubjectKeyIdentifier *si)
631 const Extension *e;
632 size_t size;
633 int i = 0;
635 memset(si, 0, sizeof(*si));
637 e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i);
638 if (e == NULL)
639 return HX509_EXTENSION_NOT_FOUND;
641 return decode_SubjectKeyIdentifier(e->extnValue.data,
642 e->extnValue.length,
643 si, &size);
646 static int
647 find_extension_name_constraints(const Certificate *subject,
648 NameConstraints *nc)
650 const Extension *e;
651 size_t size;
652 int i = 0;
654 memset(nc, 0, sizeof(*nc));
656 e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i);
657 if (e == NULL)
658 return HX509_EXTENSION_NOT_FOUND;
660 return decode_NameConstraints(e->extnValue.data,
661 e->extnValue.length,
662 nc, &size);
665 static int
666 find_extension_subject_alt_name(const Certificate *cert, int *i,
667 GeneralNames *sa)
669 const Extension *e;
670 size_t size;
672 memset(sa, 0, sizeof(*sa));
674 e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i);
675 if (e == NULL)
676 return HX509_EXTENSION_NOT_FOUND;
678 return decode_GeneralNames(e->extnValue.data,
679 e->extnValue.length,
680 sa, &size);
683 static int
684 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
686 const Extension *e;
687 size_t size;
688 int i = 0;
690 memset(eku, 0, sizeof(*eku));
692 e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i);
693 if (e == NULL)
694 return HX509_EXTENSION_NOT_FOUND;
696 return decode_ExtKeyUsage(e->extnValue.data,
697 e->extnValue.length,
698 eku, &size);
701 static int
702 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
704 void *p;
705 int ret;
707 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
708 if (p == NULL)
709 return ENOMEM;
710 list->val = p;
711 ret = der_copy_octet_string(entry, &list->val[list->len]);
712 if (ret)
713 return ret;
714 list->len++;
715 return 0;
719 * Free a list of octet strings returned by another hx509 library
720 * function.
722 * @param list list to be freed.
724 * @ingroup hx509_misc
727 void
728 hx509_free_octet_string_list(hx509_octet_string_list *list)
730 int i;
731 for (i = 0; i < list->len; i++)
732 der_free_octet_string(&list->val[i]);
733 free(list->val);
734 list->val = NULL;
735 list->len = 0;
739 * Return a list of subjectAltNames specified by oid in the
740 * certificate. On error the
742 * The returned list of octet string should be freed with
743 * hx509_free_octet_string_list().
745 * @param context A hx509 context.
746 * @param cert a hx509 certificate object.
747 * @param oid an oid to for SubjectAltName.
748 * @param list list of matching SubjectAltName.
750 * @return An hx509 error code, see hx509_get_error_string().
752 * @ingroup hx509_cert
756 hx509_cert_find_subjectAltName_otherName(hx509_context context,
757 hx509_cert cert,
758 const heim_oid *oid,
759 hx509_octet_string_list *list)
761 GeneralNames sa;
762 int ret, i, j;
764 list->val = NULL;
765 list->len = 0;
767 i = 0;
768 while (1) {
769 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
770 i++;
771 if (ret == HX509_EXTENSION_NOT_FOUND) {
772 ret = 0;
773 break;
774 } else if (ret != 0) {
775 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
776 hx509_free_octet_string_list(list);
777 return ret;
780 for (j = 0; j < sa.len; j++) {
781 if (sa.val[j].element == choice_GeneralName_otherName &&
782 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
784 ret = add_to_list(list, &sa.val[j].u.otherName.value);
785 if (ret) {
786 hx509_set_error_string(context, 0, ret,
787 "Error adding an exra SAN to "
788 "return list");
789 hx509_free_octet_string_list(list);
790 free_GeneralNames(&sa);
791 return ret;
795 free_GeneralNames(&sa);
797 return 0;
801 static int
802 check_key_usage(hx509_context context, const Certificate *cert,
803 unsigned flags, int req_present)
805 const Extension *e;
806 KeyUsage ku;
807 size_t size;
808 int ret, i = 0;
809 unsigned ku_flags;
811 if (_hx509_cert_get_version(cert) < 3)
812 return 0;
814 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
815 if (e == NULL) {
816 if (req_present) {
817 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
818 "Required extension key "
819 "usage missing from certifiate");
820 return HX509_KU_CERT_MISSING;
822 return 0;
825 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
826 if (ret)
827 return ret;
828 ku_flags = KeyUsage2int(ku);
829 if ((ku_flags & flags) != flags) {
830 unsigned missing = (~ku_flags) & flags;
831 char buf[256], *name;
833 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
834 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
835 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
836 "Key usage %s required but missing "
837 "from certifiate %s", buf, name);
838 free(name);
839 return HX509_KU_CERT_MISSING;
841 return 0;
845 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
846 * an error code. If 'req_present' the existance is required of the
847 * KeyUsage extension.
851 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
852 unsigned flags, int req_present)
854 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
857 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
859 static int
860 check_basic_constraints(hx509_context context, const Certificate *cert,
861 enum certtype type, int depth)
863 BasicConstraints bc;
864 const Extension *e;
865 size_t size;
866 int ret, i = 0;
868 if (_hx509_cert_get_version(cert) < 3)
869 return 0;
871 e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i);
872 if (e == NULL) {
873 switch(type) {
874 case PROXY_CERT:
875 case EE_CERT:
876 return 0;
877 case CA_CERT: {
878 char *name;
879 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
880 assert(ret == 0);
881 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
882 "basicConstraints missing from "
883 "CA certifiacte %s", name);
884 free(name);
885 return HX509_EXTENSION_NOT_FOUND;
890 ret = decode_BasicConstraints(e->extnValue.data,
891 e->extnValue.length, &bc,
892 &size);
893 if (ret)
894 return ret;
895 switch(type) {
896 case PROXY_CERT:
897 if (bc.cA != NULL && *bc.cA)
898 ret = HX509_PARENT_IS_CA;
899 break;
900 case EE_CERT:
901 ret = 0;
902 break;
903 case CA_CERT:
904 if (bc.cA == NULL || !*bc.cA)
905 ret = HX509_PARENT_NOT_CA;
906 else if (bc.pathLenConstraint)
907 if (depth - 1 > *bc.pathLenConstraint)
908 ret = HX509_CA_PATH_TOO_DEEP;
909 break;
911 free_BasicConstraints(&bc);
912 return ret;
916 _hx509_cert_is_parent_cmp(const Certificate *subject,
917 const Certificate *issuer,
918 int allow_self_signed)
920 int diff;
921 AuthorityKeyIdentifier ai;
922 SubjectKeyIdentifier si;
923 int ret_ai, ret_si;
925 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
926 &subject->tbsCertificate.issuer);
927 if (diff)
928 return diff;
930 memset(&ai, 0, sizeof(ai));
931 memset(&si, 0, sizeof(si));
934 * Try to find AuthorityKeyIdentifier, if it's not present in the
935 * subject certificate nor the parent.
938 ret_ai = find_extension_auth_key_id(subject, &ai);
939 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
940 return 1;
941 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
942 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
943 return -1;
945 if (ret_si && ret_ai)
946 goto out;
947 if (ret_ai)
948 goto out;
949 if (ret_si) {
950 if (allow_self_signed) {
951 diff = 0;
952 goto out;
953 } else if (ai.keyIdentifier) {
954 diff = -1;
955 goto out;
959 if (ai.keyIdentifier == NULL) {
960 Name name;
962 if (ai.authorityCertIssuer == NULL)
963 return -1;
964 if (ai.authorityCertSerialNumber == NULL)
965 return -1;
967 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
968 &issuer->tbsCertificate.serialNumber);
969 if (diff)
970 return diff;
971 if (ai.authorityCertIssuer->len != 1)
972 return -1;
973 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
974 return -1;
976 name.element =
977 ai.authorityCertIssuer->val[0].u.directoryName.element;
978 name.u.rdnSequence =
979 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
981 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
982 &name);
983 if (diff)
984 return diff;
985 diff = 0;
986 } else
987 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
988 if (diff)
989 goto out;
991 out:
992 free_AuthorityKeyIdentifier(&ai);
993 free_SubjectKeyIdentifier(&si);
994 return diff;
997 static int
998 certificate_is_anchor(hx509_context context,
999 hx509_certs trust_anchors,
1000 const hx509_cert cert)
1002 hx509_query q;
1003 hx509_cert c;
1004 int ret;
1006 if (trust_anchors == NULL)
1007 return 0;
1009 _hx509_query_clear(&q);
1011 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1012 q.certificate = _hx509_get_cert(cert);
1014 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1015 if (ret == 0)
1016 hx509_cert_free(c);
1017 return ret == 0;
1020 static int
1021 certificate_is_self_signed(const Certificate *cert)
1023 return _hx509_name_cmp(&cert->tbsCertificate.subject,
1024 &cert->tbsCertificate.issuer) == 0;
1028 * The subjectName is "null" when it's empty set of relative DBs.
1031 static int
1032 subject_null_p(const Certificate *c)
1034 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1038 static int
1039 find_parent(hx509_context context,
1040 time_t time_now,
1041 hx509_certs trust_anchors,
1042 hx509_path *path,
1043 hx509_certs pool,
1044 hx509_cert current,
1045 hx509_cert *parent)
1047 AuthorityKeyIdentifier ai;
1048 hx509_query q;
1049 int ret;
1051 *parent = NULL;
1052 memset(&ai, 0, sizeof(ai));
1054 _hx509_query_clear(&q);
1056 if (!subject_null_p(current->data)) {
1057 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1058 q.subject = _hx509_get_cert(current);
1059 } else {
1060 ret = find_extension_auth_key_id(current->data, &ai);
1061 if (ret) {
1062 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1063 "Subjectless certificate missing AuthKeyID");
1064 return HX509_CERTIFICATE_MALFORMED;
1067 if (ai.keyIdentifier == NULL) {
1068 free_AuthorityKeyIdentifier(&ai);
1069 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1070 "Subjectless certificate missing keyIdentifier "
1071 "inside AuthKeyID");
1072 return HX509_CERTIFICATE_MALFORMED;
1075 q.subject_id = ai.keyIdentifier;
1076 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1079 q.path = path;
1080 q.match |= HX509_QUERY_NO_MATCH_PATH;
1082 if (pool) {
1083 q.timenow = time_now;
1084 q.match |= HX509_QUERY_MATCH_TIME;
1086 ret = hx509_certs_find(context, pool, &q, parent);
1087 if (ret == 0) {
1088 free_AuthorityKeyIdentifier(&ai);
1089 return 0;
1091 q.match &= ~HX509_QUERY_MATCH_TIME;
1094 if (trust_anchors) {
1095 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1096 if (ret == 0) {
1097 free_AuthorityKeyIdentifier(&ai);
1098 return ret;
1101 free_AuthorityKeyIdentifier(&ai);
1104 hx509_name name;
1105 char *str;
1107 ret = hx509_cert_get_subject(current, &name);
1108 if (ret) {
1109 hx509_clear_error_string(context);
1110 return HX509_ISSUER_NOT_FOUND;
1112 ret = hx509_name_to_string(name, &str);
1113 hx509_name_free(&name);
1114 if (ret) {
1115 hx509_clear_error_string(context);
1116 return HX509_ISSUER_NOT_FOUND;
1119 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1120 "Failed to find issuer for "
1121 "certificate with subject: '%s'", str);
1122 free(str);
1124 return HX509_ISSUER_NOT_FOUND;
1131 static int
1132 is_proxy_cert(hx509_context context,
1133 const Certificate *cert,
1134 ProxyCertInfo *rinfo)
1136 ProxyCertInfo info;
1137 const Extension *e;
1138 size_t size;
1139 int ret, i = 0;
1141 if (rinfo)
1142 memset(rinfo, 0, sizeof(*rinfo));
1144 e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i);
1145 if (e == NULL) {
1146 hx509_clear_error_string(context);
1147 return HX509_EXTENSION_NOT_FOUND;
1150 ret = decode_ProxyCertInfo(e->extnValue.data,
1151 e->extnValue.length,
1152 &info,
1153 &size);
1154 if (ret) {
1155 hx509_clear_error_string(context);
1156 return ret;
1158 if (size != e->extnValue.length) {
1159 free_ProxyCertInfo(&info);
1160 hx509_clear_error_string(context);
1161 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1163 if (rinfo == NULL)
1164 free_ProxyCertInfo(&info);
1165 else
1166 *rinfo = info;
1168 return 0;
1172 * Path operations are like MEMORY based keyset, but with exposed
1173 * internal so we can do easy searches.
1177 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1179 hx509_cert *val;
1180 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1181 if (val == NULL) {
1182 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1183 return ENOMEM;
1186 path->val = val;
1187 path->val[path->len] = hx509_cert_ref(cert);
1188 path->len++;
1190 return 0;
1193 void
1194 _hx509_path_free(hx509_path *path)
1196 unsigned i;
1198 for (i = 0; i < path->len; i++)
1199 hx509_cert_free(path->val[i]);
1200 free(path->val);
1201 path->val = NULL;
1202 path->len = 0;
1206 * Find path by looking up issuer for the top certificate and continue
1207 * until an anchor certificate is found or max limit is found. A
1208 * certificate never included twice in the path.
1210 * If the trust anchors are not given, calculate optimistic path, just
1211 * follow the chain upward until we no longer find a parent or we hit
1212 * the max path limit. In this case, a failure will always be returned
1213 * depending on what error condition is hit first.
1215 * The path includes a path from the top certificate to the anchor
1216 * certificate.
1218 * The caller needs to free `path´ both on successful built path and
1219 * failure.
1223 _hx509_calculate_path(hx509_context context,
1224 int flags,
1225 time_t time_now,
1226 hx509_certs anchors,
1227 unsigned int max_depth,
1228 hx509_cert cert,
1229 hx509_certs pool,
1230 hx509_path *path)
1232 hx509_cert parent, current;
1233 int ret;
1235 if (max_depth == 0)
1236 max_depth = HX509_VERIFY_MAX_DEPTH;
1238 ret = _hx509_path_append(context, path, cert);
1239 if (ret)
1240 return ret;
1242 current = hx509_cert_ref(cert);
1244 while (!certificate_is_anchor(context, anchors, current)) {
1246 ret = find_parent(context, time_now, anchors, path,
1247 pool, current, &parent);
1248 hx509_cert_free(current);
1249 if (ret)
1250 return ret;
1252 ret = _hx509_path_append(context, path, parent);
1253 if (ret)
1254 return ret;
1255 current = parent;
1257 if (path->len > max_depth) {
1258 hx509_cert_free(current);
1259 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1260 "Path too long while bulding "
1261 "certificate chain");
1262 return HX509_PATH_TOO_LONG;
1266 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1267 path->len > 0 &&
1268 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1270 hx509_cert_free(path->val[path->len - 1]);
1271 path->len--;
1274 hx509_cert_free(current);
1275 return 0;
1278 static int
1279 AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1280 const AlgorithmIdentifier *q)
1282 int diff;
1283 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1284 if (diff)
1285 return diff;
1286 if (p->parameters) {
1287 if (q->parameters)
1288 return heim_any_cmp(p->parameters,
1289 q->parameters);
1290 else
1291 return 1;
1292 } else {
1293 if (q->parameters)
1294 return -1;
1295 else
1296 return 0;
1301 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1303 int diff;
1304 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1305 if (diff)
1306 return diff;
1307 diff = AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1308 &q->signatureAlgorithm);
1309 if (diff)
1310 return diff;
1311 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1312 &q->tbsCertificate._save);
1313 return diff;
1317 * Compare to hx509 certificate object, useful for sorting.
1319 * @param p a hx509 certificate object.
1320 * @param q a hx509 certificate object.
1322 * @return 0 the objects are the same, returns > 0 is p is "larger"
1323 * then q, < 0 if p is "smaller" then q.
1325 * @ingroup hx509_cert
1329 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1331 return _hx509_Certificate_cmp(p->data, q->data);
1335 * Return the name of the issuer of the hx509 certificate.
1337 * @param p a hx509 certificate object.
1338 * @param name a pointer to a hx509 name, should be freed by
1339 * hx509_name_free().
1341 * @return An hx509 error code, see hx509_get_error_string().
1343 * @ingroup hx509_cert
1347 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1349 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1353 * Return the name of the subject of the hx509 certificate.
1355 * @param p a hx509 certificate object.
1356 * @param name a pointer to a hx509 name, should be freed by
1357 * hx509_name_free(). See also hx509_cert_get_base_subject().
1359 * @return An hx509 error code, see hx509_get_error_string().
1361 * @ingroup hx509_cert
1365 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1367 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1371 * Return the name of the base subject of the hx509 certificate. If
1372 * the certiicate is a verified proxy certificate, the this function
1373 * return the base certificate (root of the proxy chain). If the proxy
1374 * certificate is not verified with the base certificate
1375 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1377 * @param context a hx509 context.
1378 * @param c a hx509 certificate object.
1379 * @param name a pointer to a hx509 name, should be freed by
1380 * hx509_name_free(). See also hx509_cert_get_subject().
1382 * @return An hx509 error code, see hx509_get_error_string().
1384 * @ingroup hx509_cert
1388 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1389 hx509_name *name)
1391 if (c->basename)
1392 return hx509_name_copy(context, c->basename, name);
1393 if (is_proxy_cert(context, c->data, NULL) == 0) {
1394 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1395 hx509_set_error_string(context, 0, ret,
1396 "Proxy certificate have not been "
1397 "canonicalize yet, no base name");
1398 return ret;
1400 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1404 * Get serial number of the certificate.
1406 * @param p a hx509 certificate object.
1407 * @param i serial number, should be freed ith der_free_heim_integer().
1409 * @return An hx509 error code, see hx509_get_error_string().
1411 * @ingroup hx509_cert
1415 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1417 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1421 * Get notBefore time of the certificate.
1423 * @param p a hx509 certificate object.
1425 * @return return not before time
1427 * @ingroup hx509_cert
1430 time_t
1431 hx509_cert_get_notBefore(hx509_cert p)
1433 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1437 * Get notAfter time of the certificate.
1439 * @param p a hx509 certificate object.
1441 * @return return not after time.
1443 * @ingroup hx509_cert
1446 time_t
1447 hx509_cert_get_notAfter(hx509_cert p)
1449 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1453 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1455 * @param p a hx509 certificate object.
1456 * @param spki SubjectPublicKeyInfo, should be freed with
1457 * free_SubjectPublicKeyInfo().
1459 * @return An hx509 error code, see hx509_get_error_string().
1461 * @ingroup hx509_cert
1465 hx509_cert_get_SPKI(hx509_cert p, SubjectPublicKeyInfo *spki)
1467 return copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo,
1468 spki);
1471 hx509_private_key
1472 _hx509_cert_private_key(hx509_cert p)
1474 return p->private_key;
1478 _hx509_cert_private_key_exportable(hx509_cert p)
1480 if (p->private_key == NULL)
1481 return 0;
1482 return _hx509_private_key_exportable(p->private_key);
1486 _hx509_cert_private_decrypt(hx509_context context,
1487 const heim_octet_string *ciphertext,
1488 const heim_oid *encryption_oid,
1489 hx509_cert p,
1490 heim_octet_string *cleartext)
1492 cleartext->data = NULL;
1493 cleartext->length = 0;
1495 if (p->private_key == NULL) {
1496 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1497 "Private key missing");
1498 return HX509_PRIVATE_KEY_MISSING;
1501 return _hx509_private_key_private_decrypt(context,
1502 ciphertext,
1503 encryption_oid,
1504 p->private_key,
1505 cleartext);
1509 _hx509_cert_public_encrypt(hx509_context context,
1510 const heim_octet_string *cleartext,
1511 const hx509_cert p,
1512 heim_oid *encryption_oid,
1513 heim_octet_string *ciphertext)
1515 return _hx509_public_encrypt(context,
1516 cleartext, p->data,
1517 encryption_oid, ciphertext);
1524 time_t
1525 _hx509_Time2time_t(const Time *t)
1527 switch(t->element) {
1528 case choice_Time_utcTime:
1529 return t->u.utcTime;
1530 case choice_Time_generalTime:
1531 return t->u.generalTime;
1533 return 0;
1540 static int
1541 init_name_constraints(hx509_name_constraints *nc)
1543 memset(nc, 0, sizeof(*nc));
1544 return 0;
1547 static int
1548 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1549 hx509_name_constraints *nc)
1551 NameConstraints tnc;
1552 int ret;
1554 ret = find_extension_name_constraints(c, &tnc);
1555 if (ret == HX509_EXTENSION_NOT_FOUND)
1556 return 0;
1557 else if (ret) {
1558 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1559 return ret;
1560 } else if (not_ca) {
1561 ret = HX509_VERIFY_CONSTRAINTS;
1562 hx509_set_error_string(context, 0, ret, "Not a CA and "
1563 "have NameConstraints");
1564 } else {
1565 NameConstraints *val;
1566 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1567 if (val == NULL) {
1568 hx509_clear_error_string(context);
1569 ret = ENOMEM;
1570 goto out;
1572 nc->val = val;
1573 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1574 if (ret) {
1575 hx509_clear_error_string(context);
1576 goto out;
1578 nc->len += 1;
1580 out:
1581 free_NameConstraints(&tnc);
1582 return ret;
1585 static int
1586 match_RDN(const RelativeDistinguishedName *c,
1587 const RelativeDistinguishedName *n)
1589 int i;
1591 if (c->len != n->len)
1592 return HX509_NAME_CONSTRAINT_ERROR;
1594 for (i = 0; i < n->len; i++) {
1595 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1596 return HX509_NAME_CONSTRAINT_ERROR;
1597 if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0)
1598 return HX509_NAME_CONSTRAINT_ERROR;
1600 return 0;
1603 static int
1604 match_X501Name(const Name *c, const Name *n)
1606 int i, ret;
1608 if (c->element != choice_Name_rdnSequence
1609 || n->element != choice_Name_rdnSequence)
1610 return 0;
1611 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1612 return HX509_NAME_CONSTRAINT_ERROR;
1613 for (i = 0; i < c->u.rdnSequence.len; i++) {
1614 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1615 if (ret)
1616 return ret;
1618 return 0;
1622 static int
1623 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1626 * Name constraints only apply to the same name type, see RFC3280,
1627 * 4.2.1.11.
1629 assert(c->element == n->element);
1631 switch(c->element) {
1632 case choice_GeneralName_otherName:
1633 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1634 &n->u.otherName.type_id) != 0)
1635 return HX509_NAME_CONSTRAINT_ERROR;
1636 if (heim_any_cmp(&c->u.otherName.value,
1637 &n->u.otherName.value) != 0)
1638 return HX509_NAME_CONSTRAINT_ERROR;
1639 *match = 1;
1640 return 0;
1641 case choice_GeneralName_rfc822Name: {
1642 const char *s;
1643 size_t len1, len2;
1644 s = strchr(c->u.rfc822Name, '@');
1645 if (s) {
1646 if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1647 return HX509_NAME_CONSTRAINT_ERROR;
1648 } else {
1649 s = strchr(n->u.rfc822Name, '@');
1650 if (s == NULL)
1651 return HX509_NAME_CONSTRAINT_ERROR;
1652 len1 = strlen(c->u.rfc822Name);
1653 len2 = strlen(s + 1);
1654 if (len1 > len2)
1655 return HX509_NAME_CONSTRAINT_ERROR;
1656 if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1657 return HX509_NAME_CONSTRAINT_ERROR;
1658 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1659 return HX509_NAME_CONSTRAINT_ERROR;
1661 *match = 1;
1662 return 0;
1664 case choice_GeneralName_dNSName: {
1665 size_t lenc, lenn;
1667 lenc = strlen(c->u.dNSName);
1668 lenn = strlen(n->u.dNSName);
1669 if (lenc > lenn)
1670 return HX509_NAME_CONSTRAINT_ERROR;
1671 if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1672 return HX509_NAME_CONSTRAINT_ERROR;
1673 if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1674 return HX509_NAME_CONSTRAINT_ERROR;
1675 *match = 1;
1676 return 0;
1678 case choice_GeneralName_directoryName: {
1679 Name c_name, n_name;
1680 int ret;
1682 c_name._save.data = NULL;
1683 c_name._save.length = 0;
1684 c_name.element = c->u.directoryName.element;
1685 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1687 n_name._save.data = NULL;
1688 n_name._save.length = 0;
1689 n_name.element = n->u.directoryName.element;
1690 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1692 ret = match_X501Name(&c_name, &n_name);
1693 if (ret == 0)
1694 *match = 1;
1695 return ret;
1697 case choice_GeneralName_uniformResourceIdentifier:
1698 case choice_GeneralName_iPAddress:
1699 case choice_GeneralName_registeredID:
1700 default:
1701 return HX509_NAME_CONSTRAINT_ERROR;
1705 static int
1706 match_alt_name(const GeneralName *n, const Certificate *c,
1707 int *same, int *match)
1709 GeneralNames sa;
1710 int ret, i, j;
1712 i = 0;
1713 do {
1714 ret = find_extension_subject_alt_name(c, &i, &sa);
1715 if (ret == HX509_EXTENSION_NOT_FOUND) {
1716 ret = 0;
1717 break;
1718 } else if (ret != 0)
1719 break;
1721 for (j = 0; j < sa.len; j++) {
1722 if (n->element == sa.val[j].element) {
1723 *same = 1;
1724 ret = match_general_name(n, &sa.val[j], match);
1727 free_GeneralNames(&sa);
1728 } while (1);
1729 return ret;
1733 static int
1734 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1736 int name, alt_name, same;
1737 unsigned int i;
1738 int ret = 0;
1740 name = alt_name = same = *match = 0;
1741 for (i = 0; i < t->len; i++) {
1742 if (t->val[i].minimum && t->val[i].maximum)
1743 return HX509_RANGE;
1746 * If the constraint apply to directoryNames, test is with
1747 * subjectName of the certificate if the certificate have a
1748 * non-null (empty) subjectName.
1751 if (t->val[i].base.element == choice_GeneralName_directoryName
1752 && !subject_null_p(c))
1754 GeneralName certname;
1756 memset(&certname, 0, sizeof(certname));
1757 certname.element = choice_GeneralName_directoryName;
1758 certname.u.directoryName.element =
1759 c->tbsCertificate.subject.element;
1760 certname.u.directoryName.u.rdnSequence =
1761 c->tbsCertificate.subject.u.rdnSequence;
1763 ret = match_general_name(&t->val[i].base, &certname, &name);
1766 /* Handle subjectAltNames, this is icky since they
1767 * restrictions only apply if the subjectAltName is of the
1768 * same type. So if there have been a match of type, require
1769 * altname to be set.
1771 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1773 if (name && (!same || alt_name))
1774 *match = 1;
1775 return ret;
1778 static int
1779 check_name_constraints(hx509_context context,
1780 const hx509_name_constraints *nc,
1781 const Certificate *c)
1783 int match, ret;
1784 int i;
1786 for (i = 0 ; i < nc->len; i++) {
1787 GeneralSubtrees gs;
1789 if (nc->val[i].permittedSubtrees) {
1790 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1791 ret = match_tree(&gs, c, &match);
1792 if (ret) {
1793 hx509_clear_error_string(context);
1794 return ret;
1796 /* allow null subjectNames, they wont matches anything */
1797 if (match == 0 && !subject_null_p(c)) {
1798 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1799 "Error verify constraints, "
1800 "certificate didn't match any "
1801 "permitted subtree");
1802 return HX509_VERIFY_CONSTRAINTS;
1805 if (nc->val[i].excludedSubtrees) {
1806 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1807 ret = match_tree(&gs, c, &match);
1808 if (ret) {
1809 hx509_clear_error_string(context);
1810 return ret;
1812 if (match) {
1813 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1814 "Error verify constraints, "
1815 "certificate included in excluded "
1816 "subtree");
1817 return HX509_VERIFY_CONSTRAINTS;
1821 return 0;
1824 static void
1825 free_name_constraints(hx509_name_constraints *nc)
1827 int i;
1829 for (i = 0 ; i < nc->len; i++)
1830 free_NameConstraints(&nc->val[i]);
1831 free(nc->val);
1835 * Build and verify the path for the certificate to the trust anchor
1836 * specified in the verify context. The path is constructed from the
1837 * certificate, the pool and the trust anchors.
1839 * @param context A hx509 context.
1840 * @param ctx A hx509 verification context.
1841 * @param cert the certificate to build the path from.
1842 * @param pool A keyset of certificates to build the chain from.
1844 * @return An hx509 error code, see hx509_get_error_string().
1846 * @ingroup hx509_verify
1850 hx509_verify_path(hx509_context context,
1851 hx509_verify_ctx ctx,
1852 hx509_cert cert,
1853 hx509_certs pool)
1855 hx509_name_constraints nc;
1856 hx509_path path;
1857 #if 0
1858 const AlgorithmIdentifier *alg_id;
1859 #endif
1860 int ret, i, proxy_cert_depth, selfsigned_depth;
1861 enum certtype type;
1862 Name proxy_issuer;
1863 hx509_certs anchors = NULL;
1865 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1867 ret = init_name_constraints(&nc);
1868 if (ret)
1869 return ret;
1871 path.val = NULL;
1872 path.len = 0;
1874 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1875 ctx->time_now = time(NULL);
1880 if (ctx->trust_anchors)
1881 anchors = _hx509_certs_ref(ctx->trust_anchors);
1882 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1883 anchors = _hx509_certs_ref(context->default_trust_anchors);
1884 else {
1885 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1886 if (ret)
1887 goto out;
1891 * Calculate the path from the certificate user presented to the
1892 * to an anchor.
1894 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1895 anchors, ctx->max_depth,
1896 cert, pool, &path);
1897 if (ret)
1898 goto out;
1900 #if 0
1901 alg_id = path.val[path->len - 1]->data->tbsCertificate.signature;
1902 #endif
1905 * Check CA and proxy certificate chain from the top of the
1906 * certificate chain. Also check certificate is valid with respect
1907 * to the current time.
1911 proxy_cert_depth = 0;
1912 selfsigned_depth = 0;
1914 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1915 type = PROXY_CERT;
1916 else
1917 type = EE_CERT;
1919 for (i = 0; i < path.len; i++) {
1920 Certificate *c;
1921 time_t t;
1923 c = _hx509_get_cert(path.val[i]);
1926 * Lets do some basic check on issuer like
1927 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1928 * on what type of certificate this is.
1931 switch (type) {
1932 case CA_CERT:
1933 /* XXX make constants for keyusage */
1934 ret = check_key_usage(context, c, 1 << 5,
1935 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1936 if (ret) {
1937 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1938 "Key usage missing from CA certificate");
1939 goto out;
1942 if (i + 1 != path.len && certificate_is_self_signed(c))
1943 selfsigned_depth++;
1945 break;
1946 case PROXY_CERT: {
1947 ProxyCertInfo info;
1949 if (is_proxy_cert(context, c, &info) == 0) {
1950 int j;
1952 if (info.pCPathLenConstraint != NULL &&
1953 *info.pCPathLenConstraint < i)
1955 free_ProxyCertInfo(&info);
1956 ret = HX509_PATH_TOO_LONG;
1957 hx509_set_error_string(context, 0, ret,
1958 "Proxy certificate chain "
1959 "longer then allowed");
1960 goto out;
1962 /* XXX MUST check info.proxyPolicy */
1963 free_ProxyCertInfo(&info);
1965 j = 0;
1966 if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
1967 ret = HX509_PROXY_CERT_INVALID;
1968 hx509_set_error_string(context, 0, ret,
1969 "Proxy certificate have explicity "
1970 "forbidden subjectAltName");
1971 goto out;
1974 j = 0;
1975 if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
1976 ret = HX509_PROXY_CERT_INVALID;
1977 hx509_set_error_string(context, 0, ret,
1978 "Proxy certificate have explicity "
1979 "forbidden issuerAltName");
1980 goto out;
1984 * The subject name of the proxy certificate should be
1985 * CN=XXX,<proxy issuer>, prune of CN and check if its
1986 * the same over the whole chain of proxy certs and
1987 * then check with the EE cert when we get to it.
1990 if (proxy_cert_depth) {
1991 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject);
1992 if (ret) {
1993 ret = HX509_PROXY_CERT_NAME_WRONG;
1994 hx509_set_error_string(context, 0, ret,
1995 "Base proxy name not right");
1996 goto out;
2000 free_Name(&proxy_issuer);
2002 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2003 if (ret) {
2004 hx509_clear_error_string(context);
2005 goto out;
2008 j = proxy_issuer.u.rdnSequence.len;
2009 if (proxy_issuer.u.rdnSequence.len < 2
2010 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2011 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2012 oid_id_at_commonName()))
2014 ret = HX509_PROXY_CERT_NAME_WRONG;
2015 hx509_set_error_string(context, 0, ret,
2016 "Proxy name too short or "
2017 "does not have Common name "
2018 "at the top");
2019 goto out;
2022 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2023 proxy_issuer.u.rdnSequence.len -= 1;
2025 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer);
2026 if (ret != 0) {
2027 ret = HX509_PROXY_CERT_NAME_WRONG;
2028 hx509_set_error_string(context, 0, ret,
2029 "Proxy issuer name not as expected");
2030 goto out;
2033 break;
2034 } else {
2036 * Now we are done with the proxy certificates, this
2037 * cert was an EE cert and we we will fall though to
2038 * EE checking below.
2040 type = EE_CERT;
2041 /* FALLTHOUGH */
2044 case EE_CERT:
2046 * If there where any proxy certificates in the chain
2047 * (proxy_cert_depth > 0), check that the proxy issuer
2048 * matched proxy certificates "base" subject.
2050 if (proxy_cert_depth) {
2052 ret = _hx509_name_cmp(&proxy_issuer,
2053 &c->tbsCertificate.subject);
2054 if (ret) {
2055 ret = HX509_PROXY_CERT_NAME_WRONG;
2056 hx509_clear_error_string(context);
2057 goto out;
2059 if (cert->basename)
2060 hx509_name_free(&cert->basename);
2062 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2063 if (ret) {
2064 hx509_clear_error_string(context);
2065 goto out;
2069 break;
2072 ret = check_basic_constraints(context, c, type,
2073 i - proxy_cert_depth - selfsigned_depth);
2074 if (ret)
2075 goto out;
2078 * Don't check the trust anchors expiration time since they
2079 * are transported out of band, from RFC3820.
2081 if (i + 1 != path.len || CHECK_TA(ctx)) {
2083 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2084 if (t > ctx->time_now) {
2085 ret = HX509_CERT_USED_BEFORE_TIME;
2086 hx509_clear_error_string(context);
2087 goto out;
2089 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2090 if (t < ctx->time_now) {
2091 ret = HX509_CERT_USED_AFTER_TIME;
2092 hx509_clear_error_string(context);
2093 goto out;
2097 if (type == EE_CERT)
2098 type = CA_CERT;
2099 else if (type == PROXY_CERT)
2100 proxy_cert_depth++;
2104 * Verify constraints, do this backward so path constraints are
2105 * checked in the right order.
2108 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2109 Certificate *c;
2111 c = _hx509_get_cert(path.val[i]);
2113 /* verify name constraints, not for selfsigned and anchor */
2114 if (!certificate_is_self_signed(c) || i + 1 != path.len) {
2115 ret = check_name_constraints(context, &nc, c);
2116 if (ret) {
2117 goto out;
2120 ret = add_name_constraints(context, c, i == 0, &nc);
2121 if (ret)
2122 goto out;
2124 /* XXX verify all other silly constraints */
2129 * Verify that no certificates has been revoked.
2132 if (ctx->revoke_ctx) {
2133 hx509_certs certs;
2135 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2136 NULL, &certs);
2137 if (ret)
2138 goto out;
2140 for (i = 0; i < path.len; i++) {
2141 ret = hx509_certs_add(context, certs, path.val[i]);
2142 if (ret) {
2143 hx509_certs_free(&certs);
2144 goto out;
2147 ret = hx509_certs_merge(context, certs, pool);
2148 if (ret) {
2149 hx509_certs_free(&certs);
2150 goto out;
2153 for (i = 0; i < path.len - 1; i++) {
2154 int parent = (i < path.len - 1) ? i + 1 : i;
2156 ret = hx509_revoke_verify(context,
2157 ctx->revoke_ctx,
2158 certs,
2159 ctx->time_now,
2160 path.val[i],
2161 path.val[parent]);
2162 if (ret) {
2163 hx509_certs_free(&certs);
2164 goto out;
2167 hx509_certs_free(&certs);
2170 #if 0
2171 for (i = path.len - 1; i >= 0; i--) {
2172 _hx509_print_cert_subject(path.val[i]);
2174 #endif
2177 * Verify signatures, do this backward so public key working
2178 * parameter is passed up from the anchor up though the chain.
2181 for (i = path.len - 1; i >= 0; i--) {
2182 Certificate *signer, *c;
2184 c = _hx509_get_cert(path.val[i]);
2186 /* is last in chain (trust anchor) */
2187 if (i + 1 == path.len) {
2188 signer = path.val[i]->data;
2190 /* if trust anchor is not self signed, don't check sig */
2191 if (!certificate_is_self_signed(signer))
2192 continue;
2193 } else {
2194 /* take next certificate in chain */
2195 signer = path.val[i + 1]->data;
2198 /* verify signatureValue */
2199 ret = _hx509_verify_signature_bitstring(context,
2200 signer,
2201 &c->signatureAlgorithm,
2202 &c->tbsCertificate._save,
2203 &c->signatureValue);
2204 if (ret) {
2205 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2206 "Failed to verify signature of certificate");
2207 goto out;
2211 out:
2212 hx509_certs_free(&anchors);
2213 free_Name(&proxy_issuer);
2214 free_name_constraints(&nc);
2215 _hx509_path_free(&path);
2217 return ret;
2221 * Verify a signature made using the private key of an certificate.
2223 * @param context A hx509 context.
2224 * @param signer the certificate that made the signature.
2225 * @param alg algorthm that was used to sign the data.
2226 * @param data the data that was signed.
2227 * @param sig the sigature to verify.
2229 * @return An hx509 error code, see hx509_get_error_string().
2231 * @ingroup hx509_crypto
2235 hx509_verify_signature(hx509_context context,
2236 const hx509_cert signer,
2237 const AlgorithmIdentifier *alg,
2238 const heim_octet_string *data,
2239 const heim_octet_string *sig)
2241 return _hx509_verify_signature(context, signer->data, alg, data, sig);
2246 * Verify that the certificate is allowed to be used for the hostname
2247 * and address.
2249 * @param context A hx509 context.
2250 * @param cert the certificate to match with
2251 * @param flags Flags to modify the behavior:
2252 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2253 * @param type type of hostname:
2254 * - HX509_HN_HOSTNAME for plain hostname.
2255 * - HX509_HN_DNSSRV for DNS SRV names.
2256 * @param hostname the hostname to check
2257 * @param sa address of the host
2258 * @param sa_size length of address
2260 * @return An hx509 error code, see hx509_get_error_string().
2262 * @ingroup hx509_cert
2266 hx509_verify_hostname(hx509_context context,
2267 const hx509_cert cert,
2268 int flags,
2269 hx509_hostname_type type,
2270 const char *hostname,
2271 const struct sockaddr *sa,
2272 /* XXX krb5_socklen_t */ int sa_size)
2274 GeneralNames san;
2275 int ret, i, j;
2277 if (sa && sa_size <= 0)
2278 return EINVAL;
2280 memset(&san, 0, sizeof(san));
2282 i = 0;
2283 do {
2284 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2285 if (ret == HX509_EXTENSION_NOT_FOUND) {
2286 ret = 0;
2287 break;
2288 } else if (ret != 0)
2289 break;
2291 for (j = 0; j < san.len; j++) {
2292 switch (san.val[j].element) {
2293 case choice_GeneralName_dNSName:
2294 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2295 free_GeneralNames(&san);
2296 return 0;
2298 break;
2299 default:
2300 break;
2303 free_GeneralNames(&san);
2304 } while (1);
2307 Name *name = &cert->data->tbsCertificate.subject;
2309 /* match if first component is a CN= */
2310 if (name->u.rdnSequence.len > 0
2311 && name->u.rdnSequence.val[0].len == 1
2312 && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
2313 oid_id_at_commonName()) == 0)
2315 DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
2317 switch (ds->element) {
2318 case choice_DirectoryString_printableString:
2319 if (strcasecmp(ds->u.printableString, hostname) == 0)
2320 return 0;
2321 break;
2322 case choice_DirectoryString_ia5String:
2323 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2324 return 0;
2325 break;
2326 case choice_DirectoryString_utf8String:
2327 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2328 return 0;
2329 default:
2330 break;
2335 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2336 ret = HX509_NAME_CONSTRAINT_ERROR;
2338 return ret;
2342 _hx509_set_cert_attribute(hx509_context context,
2343 hx509_cert cert,
2344 const heim_oid *oid,
2345 const heim_octet_string *attr)
2347 hx509_cert_attribute a;
2348 void *d;
2350 if (hx509_cert_get_attribute(cert, oid) != NULL)
2351 return 0;
2353 d = realloc(cert->attrs.val,
2354 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2355 if (d == NULL) {
2356 hx509_clear_error_string(context);
2357 return ENOMEM;
2359 cert->attrs.val = d;
2361 a = malloc(sizeof(*a));
2362 if (a == NULL)
2363 return ENOMEM;
2365 der_copy_octet_string(attr, &a->data);
2366 der_copy_oid(oid, &a->oid);
2368 cert->attrs.val[cert->attrs.len] = a;
2369 cert->attrs.len++;
2371 return 0;
2375 * Get an external attribute for the certificate, examples are
2376 * friendly name and id.
2378 * @param cert hx509 certificate object to search
2379 * @param oid an oid to search for.
2381 * @return an hx509_cert_attribute, only valid as long as the
2382 * certificate is referenced.
2384 * @ingroup hx509_cert
2387 hx509_cert_attribute
2388 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2390 int i;
2391 for (i = 0; i < cert->attrs.len; i++)
2392 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2393 return cert->attrs.val[i];
2394 return NULL;
2398 * Set the friendly name on the certificate.
2400 * @param cert The certificate to set the friendly name on
2401 * @param name Friendly name.
2403 * @return An hx509 error code, see hx509_get_error_string().
2405 * @ingroup hx509_cert
2409 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2411 if (cert->friendlyname)
2412 free(cert->friendlyname);
2413 cert->friendlyname = strdup(name);
2414 if (cert->friendlyname == NULL)
2415 return ENOMEM;
2416 return 0;
2420 * Get friendly name of the certificate.
2422 * @param cert cert to get the friendly name from.
2424 * @return an friendly name or NULL if there is. The friendly name is
2425 * only valid as long as the certificate is referenced.
2427 * @ingroup hx509_cert
2430 const char *
2431 hx509_cert_get_friendly_name(hx509_cert cert)
2433 hx509_cert_attribute a;
2434 PKCS9_friendlyName n;
2435 size_t sz;
2436 int ret, i;
2438 if (cert->friendlyname)
2439 return cert->friendlyname;
2441 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
2442 if (a == NULL) {
2443 /* XXX use subject name ? */
2444 return NULL;
2447 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2448 if (ret)
2449 return NULL;
2451 if (n.len != 1) {
2452 free_PKCS9_friendlyName(&n);
2453 return NULL;
2456 cert->friendlyname = malloc(n.val[0].length + 1);
2457 if (cert->friendlyname == NULL) {
2458 free_PKCS9_friendlyName(&n);
2459 return NULL;
2462 for (i = 0; i < n.val[0].length; i++) {
2463 if (n.val[0].data[i] <= 0xff)
2464 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2465 else
2466 cert->friendlyname[i] = 'X';
2468 cert->friendlyname[i] = '\0';
2469 free_PKCS9_friendlyName(&n);
2471 return cert->friendlyname;
2474 void
2475 _hx509_query_clear(hx509_query *q)
2477 memset(q, 0, sizeof(*q));
2481 * Allocate an query controller. Free using hx509_query_free().
2483 * @param context A hx509 context.
2484 * @param q return pointer to a hx509_query.
2486 * @return An hx509 error code, see hx509_get_error_string().
2488 * @ingroup hx509_cert
2492 hx509_query_alloc(hx509_context context, hx509_query **q)
2494 *q = calloc(1, sizeof(**q));
2495 if (*q == NULL)
2496 return ENOMEM;
2497 return 0;
2501 * Set match options for the hx509 query controller.
2503 * @param q query controller.
2504 * @param option options to control the query controller.
2506 * @return An hx509 error code, see hx509_get_error_string().
2508 * @ingroup hx509_cert
2511 void
2512 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2514 switch(option) {
2515 case HX509_QUERY_OPTION_PRIVATE_KEY:
2516 q->match |= HX509_QUERY_PRIVATE_KEY;
2517 break;
2518 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2519 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2520 break;
2521 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2522 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2523 break;
2524 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2525 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2526 break;
2527 case HX509_QUERY_OPTION_END:
2528 default:
2529 break;
2534 * Set the issuer and serial number of match in the query
2535 * controller. The function make copies of the isser and serial number.
2537 * @param q a hx509 query controller
2538 * @param issuer issuer to search for
2539 * @param serialNumber the serialNumber of the issuer.
2541 * @return An hx509 error code, see hx509_get_error_string().
2543 * @ingroup hx509_cert
2547 hx509_query_match_issuer_serial(hx509_query *q,
2548 const Name *issuer,
2549 const heim_integer *serialNumber)
2551 int ret;
2552 if (q->serial) {
2553 der_free_heim_integer(q->serial);
2554 free(q->serial);
2556 q->serial = malloc(sizeof(*q->serial));
2557 if (q->serial == NULL)
2558 return ENOMEM;
2559 ret = der_copy_heim_integer(serialNumber, q->serial);
2560 if (ret) {
2561 free(q->serial);
2562 q->serial = NULL;
2563 return ret;
2565 if (q->issuer_name) {
2566 free_Name(q->issuer_name);
2567 free(q->issuer_name);
2569 q->issuer_name = malloc(sizeof(*q->issuer_name));
2570 if (q->issuer_name == NULL)
2571 return ENOMEM;
2572 ret = copy_Name(issuer, q->issuer_name);
2573 if (ret) {
2574 free(q->issuer_name);
2575 q->issuer_name = NULL;
2576 return ret;
2578 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2579 return 0;
2583 * Set the query controller to match on a friendly name
2585 * @param q a hx509 query controller.
2586 * @param name a friendly name to match on
2588 * @return An hx509 error code, see hx509_get_error_string().
2590 * @ingroup hx509_cert
2594 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2596 if (q->friendlyname)
2597 free(q->friendlyname);
2598 q->friendlyname = strdup(name);
2599 if (q->friendlyname == NULL)
2600 return ENOMEM;
2601 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2602 return 0;
2606 * Set the query controller to match using a specific match function.
2608 * @param q a hx509 query controller.
2609 * @param func function to use for matching, if the argument is NULL,
2610 * the match function is removed.
2611 * @param ctx context passed to the function.
2613 * @return An hx509 error code, see hx509_get_error_string().
2615 * @ingroup hx509_cert
2619 hx509_query_match_cmp_func(hx509_query *q,
2620 int (*func)(void *, hx509_cert),
2621 void *ctx)
2623 if (func)
2624 q->match |= HX509_QUERY_MATCH_FUNCTION;
2625 else
2626 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2627 q->cmp_func = func;
2628 q->cmp_func_ctx = ctx;
2629 return 0;
2633 * Free the query controller.
2635 * @param context A hx509 context.
2636 * @param q a pointer to the query controller.
2638 * @ingroup hx509_cert
2641 void
2642 hx509_query_free(hx509_context context, hx509_query *q)
2644 if (q->serial) {
2645 der_free_heim_integer(q->serial);
2646 free(q->serial);
2647 q->serial = NULL;
2649 if (q->issuer_name) {
2650 free_Name(q->issuer_name);
2651 free(q->issuer_name);
2652 q->issuer_name = NULL;
2654 if (q) {
2655 free(q->friendlyname);
2656 memset(q, 0, sizeof(*q));
2658 free(q);
2662 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2664 Certificate *c = _hx509_get_cert(cert);
2666 _hx509_query_statistic(context, 1, q);
2668 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2669 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2670 return 0;
2672 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2673 _hx509_Certificate_cmp(q->certificate, c) != 0)
2674 return 0;
2676 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2677 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2678 return 0;
2680 if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
2681 && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
2682 return 0;
2684 if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
2685 && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
2686 return 0;
2688 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2689 SubjectKeyIdentifier si;
2690 int ret;
2692 ret = _hx509_find_extension_subject_key_id(c, &si);
2693 if (ret == 0) {
2694 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2695 ret = 1;
2696 free_SubjectKeyIdentifier(&si);
2698 if (ret)
2699 return 0;
2701 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2702 return 0;
2703 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2704 _hx509_cert_private_key(cert) == NULL)
2705 return 0;
2708 unsigned ku = 0;
2709 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2710 ku |= (1 << 0);
2711 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2712 ku |= (1 << 1);
2713 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2714 ku |= (1 << 2);
2715 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2716 ku |= (1 << 3);
2717 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2718 ku |= (1 << 4);
2719 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2720 ku |= (1 << 5);
2721 if (q->match & HX509_QUERY_KU_CRLSIGN)
2722 ku |= (1 << 6);
2723 if (ku && check_key_usage(context, c, ku, TRUE))
2724 return 0;
2726 if ((q->match & HX509_QUERY_ANCHOR))
2727 return 0;
2729 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2730 hx509_cert_attribute a;
2732 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2733 if (a == NULL)
2734 return 0;
2735 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2736 return 0;
2739 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2740 size_t i;
2742 for (i = 0; i < q->path->len; i++)
2743 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2744 return 0;
2746 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2747 const char *name = hx509_cert_get_friendly_name(cert);
2748 if (name == NULL)
2749 return 0;
2750 if (strcasecmp(q->friendlyname, name) != 0)
2751 return 0;
2753 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2754 int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2755 if (ret != 0)
2756 return 0;
2759 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2760 heim_octet_string os;
2761 int ret;
2763 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2764 os.length =
2765 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2767 ret = _hx509_verify_signature(context,
2768 NULL,
2769 hx509_signature_sha1(),
2770 &os,
2771 q->keyhash_sha1);
2772 if (ret != 0)
2773 return 0;
2776 if (q->match & HX509_QUERY_MATCH_TIME) {
2777 time_t t;
2778 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2779 if (t > q->timenow)
2780 return 0;
2781 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2782 if (t < q->timenow)
2783 return 0;
2786 if (q->match & ~HX509_QUERY_MASK)
2787 return 0;
2789 return 1;
2793 * Set a statistic file for the query statistics.
2795 * @param context A hx509 context.
2796 * @param fn statistics file name
2798 * @ingroup hx509_cert
2801 void
2802 hx509_query_statistic_file(hx509_context context, const char *fn)
2804 if (context->querystat)
2805 free(context->querystat);
2806 context->querystat = strdup(fn);
2809 void
2810 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2812 FILE *f;
2813 if (context->querystat == NULL)
2814 return;
2815 f = fopen(context->querystat, "a");
2816 if (f == NULL)
2817 return;
2818 fprintf(f, "%d %d\n", type, q->match);
2819 fclose(f);
2822 static const char *statname[] = {
2823 "find issuer cert",
2824 "match serialnumber",
2825 "match issuer name",
2826 "match subject name",
2827 "match subject key id",
2828 "match issuer id",
2829 "private key",
2830 "ku encipherment",
2831 "ku digitalsignature",
2832 "ku keycertsign",
2833 "ku crlsign",
2834 "ku nonrepudiation",
2835 "ku keyagreement",
2836 "ku dataencipherment",
2837 "anchor",
2838 "match certificate",
2839 "match local key id",
2840 "no match path",
2841 "match friendly name",
2842 "match function",
2843 "match key hash sha1",
2844 "match time"
2847 struct stat_el {
2848 unsigned long stats;
2849 unsigned int index;
2853 static int
2854 stat_sort(const void *a, const void *b)
2856 const struct stat_el *ae = a;
2857 const struct stat_el *be = b;
2858 return be->stats - ae->stats;
2862 * Unparse the statistics file and print the result on a FILE descriptor.
2864 * @param context A hx509 context.
2865 * @param printtype tyep to print
2866 * @param out the FILE to write the data on.
2868 * @ingroup hx509_cert
2871 void
2872 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
2874 rtbl_t t;
2875 FILE *f;
2876 int type, mask, i, num;
2877 unsigned long multiqueries = 0, totalqueries = 0;
2878 struct stat_el stats[32];
2880 if (context->querystat == NULL)
2881 return;
2882 f = fopen(context->querystat, "r");
2883 if (f == NULL) {
2884 fprintf(out, "No statistic file %s: %s.\n",
2885 context->querystat, strerror(errno));
2886 return;
2889 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2890 stats[i].index = i;
2891 stats[i].stats = 0;
2894 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
2895 if (type != printtype)
2896 continue;
2897 num = i = 0;
2898 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
2899 if (mask & 1) {
2900 stats[i].stats++;
2901 num++;
2903 mask = mask >>1 ;
2904 i++;
2906 if (num > 1)
2907 multiqueries++;
2908 totalqueries++;
2910 fclose(f);
2912 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
2914 t = rtbl_create();
2915 if (t == NULL)
2916 errx(1, "out of memory");
2918 rtbl_set_separator (t, " ");
2920 rtbl_add_column_by_id (t, 0, "Name", 0);
2921 rtbl_add_column_by_id (t, 1, "Counter", 0);
2924 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2925 char str[10];
2927 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
2928 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
2929 else {
2930 snprintf(str, sizeof(str), "%d", stats[i].index);
2931 rtbl_add_column_entry_by_id (t, 0, str);
2933 snprintf(str, sizeof(str), "%lu", stats[i].stats);
2934 rtbl_add_column_entry_by_id (t, 1, str);
2937 rtbl_format(t, out);
2938 rtbl_destroy(t);
2940 fprintf(out, "\nQueries: multi %lu total %lu\n",
2941 multiqueries, totalqueries);
2945 * Check the extended key usage on the hx509 certificate.
2947 * @param context A hx509 context.
2948 * @param cert A hx509 context.
2949 * @param eku the EKU to check for
2950 * @param allow_any_eku if the any EKU is set, allow that to be a
2951 * substitute.
2953 * @return An hx509 error code, see hx509_get_error_string().
2955 * @ingroup hx509_cert
2959 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
2960 const heim_oid *eku, int allow_any_eku)
2962 ExtKeyUsage e;
2963 int ret, i;
2965 ret = find_extension_eku(_hx509_get_cert(cert), &e);
2966 if (ret) {
2967 hx509_clear_error_string(context);
2968 return ret;
2971 for (i = 0; i < e.len; i++) {
2972 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
2973 free_ExtKeyUsage(&e);
2974 return 0;
2976 if (allow_any_eku) {
2977 #if 0
2978 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
2979 free_ExtKeyUsage(&e);
2980 return 0;
2982 #endif
2985 free_ExtKeyUsage(&e);
2986 hx509_clear_error_string(context);
2987 return HX509_CERTIFICATE_MISSING_EKU;
2991 _hx509_cert_get_keyusage(hx509_context context,
2992 hx509_cert c,
2993 KeyUsage *ku)
2995 Certificate *cert;
2996 const Extension *e;
2997 size_t size;
2998 int ret, i = 0;
3000 memset(ku, 0, sizeof(*ku));
3002 cert = _hx509_get_cert(c);
3004 if (_hx509_cert_get_version(cert) < 3)
3005 return 0;
3007 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
3008 if (e == NULL)
3009 return HX509_KU_CERT_MISSING;
3011 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3012 if (ret)
3013 return ret;
3014 return 0;
3018 _hx509_cert_get_eku(hx509_context context,
3019 hx509_cert cert,
3020 ExtKeyUsage *e)
3022 int ret;
3024 memset(e, 0, sizeof(*e));
3026 ret = find_extension_eku(_hx509_get_cert(cert), e);
3027 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3028 hx509_clear_error_string(context);
3029 return ret;
3031 return 0;
3035 * Encodes the hx509 certificate as a DER encode binary.
3037 * @param context A hx509 context.
3038 * @param c the certificate to encode.
3039 * @param os the encode certificate, set to NULL, 0 on case of error.
3041 * @return An hx509 error code, see hx509_get_error_string().
3043 * @ingroup hx509_cert
3047 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3049 size_t size;
3050 int ret;
3052 os->data = NULL;
3053 os->length = 0;
3055 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3056 _hx509_get_cert(c), &size, ret);
3057 if (ret) {
3058 os->data = NULL;
3059 os->length = 0;
3060 return ret;
3062 if (os->length != size)
3063 _hx509_abort("internal ASN.1 encoder error");
3065 return ret;
3069 * Last to avoid lost __attribute__s due to #undef.
3072 #undef __attribute__
3073 #define __attribute__(X)
3075 void
3076 _hx509_abort(const char *fmt, ...)
3077 __attribute__ ((noreturn, format (printf, 1, 2)))
3079 va_list ap;
3080 va_start(ap, fmt);
3081 vprintf(fmt, ap);
3082 va_end(ap);
3083 printf("\n");
3084 fflush(stdout);
3085 abort();