Move HX509_VHN_F_ALLOW_NO_MATCH to hx509.h
[heimdal.git] / lib / hx509 / cert.c
blobcf0d77a3865d7c54ac99b35c31d7ba26f55ba6b2
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 struct hx509_verify_ctx_data {
40 hx509_certs trust_anchors;
41 int flags;
42 #define HX509_VERIFY_CTX_F_TIME_SET 1
43 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
44 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
45 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
46 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
47 time_t time_now;
48 unsigned int max_depth;
49 #define HX509_VERIFY_MAX_DEPTH 30
50 hx509_revoke_ctx revoke_ctx;
53 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
54 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
55 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
57 struct _hx509_cert_attrs {
58 size_t len;
59 hx509_cert_attribute *val;
62 struct hx509_cert_data {
63 unsigned int ref;
64 char *friendlyname;
65 Certificate *data;
66 hx509_private_key private_key;
67 struct _hx509_cert_attrs attrs;
68 hx509_name basename;
69 _hx509_cert_release_func release;
70 void *ctx;
73 typedef struct hx509_name_constraints {
74 NameConstraints *val;
75 size_t len;
76 } hx509_name_constraints;
78 #define GeneralSubtrees_SET(g,var) \
79 (g)->len = (var)->len, (g)->val = (var)->val;
81 /**
82 * Creates a hx509 context that most functions in the library
83 * uses. The context is only allowed to be used by one thread at each
84 * moment. Free the context with hx509_context_free().
86 * @param context Returns a pointer to new hx509 context.
88 * @return Returns an hx509 error code.
90 * @ingroup hx509
93 int
94 hx509_context_init(hx509_context *context)
96 *context = calloc(1, sizeof(**context));
97 if (*context == NULL)
98 return ENOMEM;
100 _hx509_ks_null_register(*context);
101 _hx509_ks_mem_register(*context);
102 _hx509_ks_file_register(*context);
103 _hx509_ks_pkcs12_register(*context);
104 _hx509_ks_pkcs11_register(*context);
105 _hx509_ks_dir_register(*context);
106 _hx509_ks_keychain_register(*context);
108 ENGINE_add_conf_module();
109 OpenSSL_add_all_algorithms();
111 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
113 initialize_hx_error_table_r(&(*context)->et_list);
114 initialize_asn1_error_table_r(&(*context)->et_list);
116 #ifdef HX509_DEFAULT_ANCHORS
117 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
118 NULL, &(*context)->default_trust_anchors);
119 #endif
121 return 0;
125 * Selects if the hx509_revoke_verify() function is going to require
126 * the existans of a revokation method (OSCP, CRL) or not. Note that
127 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
128 * call hx509_revoke_verify().
130 * @param context hx509 context to change the flag for.
131 * @param flag zero, revokation method required, non zero missing
132 * revokation method ok
134 * @ingroup hx509_verify
137 void
138 hx509_context_set_missing_revoke(hx509_context context, int flag)
140 if (flag)
141 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
142 else
143 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
147 * Free the context allocated by hx509_context_init().
149 * @param context context to be freed.
151 * @ingroup hx509
154 void
155 hx509_context_free(hx509_context *context)
157 hx509_clear_error_string(*context);
158 if ((*context)->ks_ops) {
159 free((*context)->ks_ops);
160 (*context)->ks_ops = NULL;
162 (*context)->ks_num_ops = 0;
163 free_error_table ((*context)->et_list);
164 if ((*context)->querystat)
165 free((*context)->querystat);
166 memset(*context, 0, sizeof(**context));
167 free(*context);
168 *context = NULL;
175 Certificate *
176 _hx509_get_cert(hx509_cert cert)
178 return cert->data;
185 #if 0
186 void
187 _hx509_print_cert_subject(hx509_cert cert)
189 char *subject_name;
190 hx509_name name;
191 int ret;
193 ret = hx509_cert_get_subject(cert, &name);
194 if (ret)
195 abort();
197 ret = hx509_name_to_string(name, &subject_name);
198 hx509_name_free(&name);
199 if (ret)
200 abort();
202 printf("name: %s\n", subject_name);
204 free(subject_name);
206 #endif
213 _hx509_cert_get_version(const Certificate *t)
215 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
219 * Allocate and init an hx509 certificate object from the decoded
220 * certificate `c´.
222 * @param context A hx509 context.
223 * @param c
224 * @param cert
226 * @return Returns an hx509 error code.
228 * @ingroup hx509_cert
232 hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
234 int ret;
236 *cert = malloc(sizeof(**cert));
237 if (*cert == NULL)
238 return ENOMEM;
239 (*cert)->ref = 1;
240 (*cert)->friendlyname = NULL;
241 (*cert)->attrs.len = 0;
242 (*cert)->attrs.val = NULL;
243 (*cert)->private_key = NULL;
244 (*cert)->basename = NULL;
245 (*cert)->release = NULL;
246 (*cert)->ctx = NULL;
248 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
249 if ((*cert)->data == NULL) {
250 free(*cert);
251 return ENOMEM;
253 ret = copy_Certificate(c, (*cert)->data);
254 if (ret) {
255 free((*cert)->data);
256 free(*cert);
257 *cert = NULL;
259 return ret;
263 * Just like hx509_cert_init(), but instead of a decode certificate
264 * takes an pointer and length to a memory region that contains a
265 * DER/BER encoded certificate.
267 * If the memory region doesn't contain just the certificate and
268 * nothing more the function will fail with
269 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
271 * @param context A hx509 context.
272 * @param ptr pointer to memory region containing encoded certificate.
273 * @param len length of memory region.
274 * @param cert a return pointer to a hx509 certificate object, will
275 * contain NULL on error.
277 * @return An hx509 error code, see hx509_get_error_string().
279 * @ingroup hx509_cert
283 hx509_cert_init_data(hx509_context context,
284 const void *ptr,
285 size_t len,
286 hx509_cert *cert)
288 Certificate t;
289 size_t size;
290 int ret;
292 ret = decode_Certificate(ptr, len, &t, &size);
293 if (ret) {
294 hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
295 return ret;
297 if (size != len) {
298 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
299 "Extra data after certificate");
300 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
303 ret = hx509_cert_init(context, &t, cert);
304 free_Certificate(&t);
305 return ret;
308 void
309 _hx509_cert_set_release(hx509_cert cert,
310 _hx509_cert_release_func release,
311 void *ctx)
313 cert->release = release;
314 cert->ctx = ctx;
318 /* Doesn't make a copy of `private_key'. */
321 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
323 if (cert->private_key)
324 _hx509_private_key_free(&cert->private_key);
325 cert->private_key = _hx509_private_key_ref(private_key);
326 return 0;
330 * Free reference to the hx509 certificate object, if the refcounter
331 * reaches 0, the object if freed. Its allowed to pass in NULL.
333 * @param cert the cert to free.
335 * @ingroup hx509_cert
338 void
339 hx509_cert_free(hx509_cert cert)
341 int i;
343 if (cert == NULL)
344 return;
346 if (cert->ref <= 0)
347 _hx509_abort("cert refcount <= 0 on free");
348 if (--cert->ref > 0)
349 return;
351 if (cert->release)
352 (cert->release)(cert, cert->ctx);
354 if (cert->private_key)
355 _hx509_private_key_free(&cert->private_key);
357 free_Certificate(cert->data);
358 free(cert->data);
360 for (i = 0; i < cert->attrs.len; i++) {
361 der_free_octet_string(&cert->attrs.val[i]->data);
362 der_free_oid(&cert->attrs.val[i]->oid);
363 free(cert->attrs.val[i]);
365 free(cert->attrs.val);
366 free(cert->friendlyname);
367 if (cert->basename)
368 hx509_name_free(&cert->basename);
369 memset(cert, 0, sizeof(cert));
370 free(cert);
374 * Add a reference to a hx509 certificate object.
376 * @param cert a pointer to an hx509 certificate object.
378 * @return the same object as is passed in.
380 * @ingroup hx509_cert
383 hx509_cert
384 hx509_cert_ref(hx509_cert cert)
386 if (cert->ref <= 0)
387 _hx509_abort("cert refcount <= 0");
388 cert->ref++;
389 if (cert->ref == 0)
390 _hx509_abort("cert refcount == 0");
391 return cert;
395 * Allocate an verification context that is used fo control the
396 * verification process.
398 * @param context A hx509 context.
399 * @param ctx returns a pointer to a hx509_verify_ctx object.
401 * @return An hx509 error code, see hx509_get_error_string().
403 * @ingroup hx509_verify
407 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
409 hx509_verify_ctx c;
411 c = calloc(1, sizeof(*c));
412 if (c == NULL)
413 return ENOMEM;
415 c->max_depth = HX509_VERIFY_MAX_DEPTH;
417 *ctx = c;
419 return 0;
423 * Free an hx509 verification context.
425 * @param ctx the context to be freed.
427 * @ingroup hx509_verify
430 void
431 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
433 if (ctx) {
434 hx509_certs_free(&ctx->trust_anchors);
435 hx509_revoke_free(&ctx->revoke_ctx);
436 memset(ctx, 0, sizeof(*ctx));
438 free(ctx);
442 * Set the trust anchors in the verification context, makes an
443 * reference to the keyset, so the consumer can free the keyset
444 * independent of the destruction of the verification context (ctx).
446 * @param ctx a verification context
447 * @param set a keyset containing the trust anchors.
449 * @ingroup hx509_verify
452 void
453 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
455 ctx->trust_anchors = _hx509_certs_ref(set);
459 * Attach an revocation context to the verfication context, , makes an
460 * reference to the revoke context, so the consumer can free the
461 * revoke context independent of the destruction of the verification
462 * context. If there is no revoke context, the verification process is
463 * NOT going to check any verification status.
465 * @param ctx a verification context.
466 * @param revoke_ctx a revoke context.
468 * @ingroup hx509_verify
471 void
472 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
474 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
478 * Set the clock time the the verification process is going to
479 * use. Used to check certificate in the past and future time. If not
480 * set the current time will be used.
482 * @param ctx a verification context.
483 * @param t the time the verifiation is using.
486 * @ingroup hx509_verify
489 void
490 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
492 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
493 ctx->time_now = t;
497 * Set the maximum depth of the certificate chain that the path
498 * builder is going to try.
500 * @param ctx a verification context
501 * @param max_depth maxium depth of the certificate chain, include
502 * trust anchor.
504 * @ingroup hx509_verify
507 void
508 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
510 ctx->max_depth = max_depth;
514 * Allow or deny the use of proxy certificates
516 * @param ctx a verification context
517 * @param boolean if non zero, allow proxy certificates.
519 * @ingroup hx509_verify
522 void
523 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
525 if (boolean)
526 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
527 else
528 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
532 * Select strict RFC3280 verification of certificiates. This means
533 * checking key usage on CA certificates, this will make version 1
534 * certificiates unuseable.
536 * @param ctx a verification context
537 * @param boolean if non zero, use strict verification.
539 * @ingroup hx509_verify
542 void
543 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
545 if (boolean)
546 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
547 else
548 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
552 * Allow using the operating system builtin trust anchors if no other
553 * trust anchors are configured.
555 * @param ctx a verification context
556 * @param boolean if non zero, useing the operating systems builtin
557 * trust anchors.
560 * @return An hx509 error code, see hx509_get_error_string().
562 * @ingroup hx509_cert
565 void
566 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
568 if (boolean)
569 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
570 else
571 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
574 static const Extension *
575 find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
577 const TBSCertificate *c = &cert->tbsCertificate;
579 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
580 return NULL;
582 for (;*idx < c->extensions->len; (*idx)++) {
583 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
584 return &c->extensions->val[(*idx)++];
586 return NULL;
589 static int
590 find_extension_auth_key_id(const Certificate *subject,
591 AuthorityKeyIdentifier *ai)
593 const Extension *e;
594 size_t size;
595 int i = 0;
597 memset(ai, 0, sizeof(*ai));
599 e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i);
600 if (e == NULL)
601 return HX509_EXTENSION_NOT_FOUND;
603 return decode_AuthorityKeyIdentifier(e->extnValue.data,
604 e->extnValue.length,
605 ai, &size);
609 _hx509_find_extension_subject_key_id(const Certificate *issuer,
610 SubjectKeyIdentifier *si)
612 const Extension *e;
613 size_t size;
614 int i = 0;
616 memset(si, 0, sizeof(*si));
618 e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i);
619 if (e == NULL)
620 return HX509_EXTENSION_NOT_FOUND;
622 return decode_SubjectKeyIdentifier(e->extnValue.data,
623 e->extnValue.length,
624 si, &size);
627 static int
628 find_extension_name_constraints(const Certificate *subject,
629 NameConstraints *nc)
631 const Extension *e;
632 size_t size;
633 int i = 0;
635 memset(nc, 0, sizeof(*nc));
637 e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i);
638 if (e == NULL)
639 return HX509_EXTENSION_NOT_FOUND;
641 return decode_NameConstraints(e->extnValue.data,
642 e->extnValue.length,
643 nc, &size);
646 static int
647 find_extension_subject_alt_name(const Certificate *cert, int *i,
648 GeneralNames *sa)
650 const Extension *e;
651 size_t size;
653 memset(sa, 0, sizeof(*sa));
655 e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i);
656 if (e == NULL)
657 return HX509_EXTENSION_NOT_FOUND;
659 return decode_GeneralNames(e->extnValue.data,
660 e->extnValue.length,
661 sa, &size);
664 static int
665 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
667 const Extension *e;
668 size_t size;
669 int i = 0;
671 memset(eku, 0, sizeof(*eku));
673 e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i);
674 if (e == NULL)
675 return HX509_EXTENSION_NOT_FOUND;
677 return decode_ExtKeyUsage(e->extnValue.data,
678 e->extnValue.length,
679 eku, &size);
682 static int
683 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
685 void *p;
686 int ret;
688 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
689 if (p == NULL)
690 return ENOMEM;
691 list->val = p;
692 ret = der_copy_octet_string(entry, &list->val[list->len]);
693 if (ret)
694 return ret;
695 list->len++;
696 return 0;
700 * Free a list of octet strings returned by another hx509 library
701 * function.
703 * @param list list to be freed.
705 * @ingroup hx509_misc
708 void
709 hx509_free_octet_string_list(hx509_octet_string_list *list)
711 int i;
712 for (i = 0; i < list->len; i++)
713 der_free_octet_string(&list->val[i]);
714 free(list->val);
715 list->val = NULL;
716 list->len = 0;
720 * Return a list of subjectAltNames specified by oid in the
721 * certificate. On error the
723 * The returned list of octet string should be freed with
724 * hx509_free_octet_string_list().
726 * @param context A hx509 context.
727 * @param cert a hx509 certificate object.
728 * @param oid an oid to for SubjectAltName.
729 * @param list list of matching SubjectAltName.
731 * @return An hx509 error code, see hx509_get_error_string().
733 * @ingroup hx509_cert
737 hx509_cert_find_subjectAltName_otherName(hx509_context context,
738 hx509_cert cert,
739 const heim_oid *oid,
740 hx509_octet_string_list *list)
742 GeneralNames sa;
743 int ret, i, j;
745 list->val = NULL;
746 list->len = 0;
748 i = 0;
749 while (1) {
750 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
751 i++;
752 if (ret == HX509_EXTENSION_NOT_FOUND) {
753 ret = 0;
754 break;
755 } else if (ret != 0) {
756 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
757 hx509_free_octet_string_list(list);
758 return ret;
761 for (j = 0; j < sa.len; j++) {
762 if (sa.val[j].element == choice_GeneralName_otherName &&
763 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
765 ret = add_to_list(list, &sa.val[j].u.otherName.value);
766 if (ret) {
767 hx509_set_error_string(context, 0, ret,
768 "Error adding an exra SAN to "
769 "return list");
770 hx509_free_octet_string_list(list);
771 free_GeneralNames(&sa);
772 return ret;
776 free_GeneralNames(&sa);
778 return 0;
782 static int
783 check_key_usage(hx509_context context, const Certificate *cert,
784 unsigned flags, int req_present)
786 const Extension *e;
787 KeyUsage ku;
788 size_t size;
789 int ret, i = 0;
790 unsigned ku_flags;
792 if (_hx509_cert_get_version(cert) < 3)
793 return 0;
795 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
796 if (e == NULL) {
797 if (req_present) {
798 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
799 "Required extension key "
800 "usage missing from certifiate");
801 return HX509_KU_CERT_MISSING;
803 return 0;
806 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
807 if (ret)
808 return ret;
809 ku_flags = KeyUsage2int(ku);
810 if ((ku_flags & flags) != flags) {
811 unsigned missing = (~ku_flags) & flags;
812 char buf[256], *name;
814 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
815 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
816 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
817 "Key usage %s required but missing "
818 "from certifiate %s", buf, name);
819 free(name);
820 return HX509_KU_CERT_MISSING;
822 return 0;
826 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
827 * an error code. If 'req_present' the existance is required of the
828 * KeyUsage extension.
832 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
833 unsigned flags, int req_present)
835 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
838 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
840 static int
841 check_basic_constraints(hx509_context context, const Certificate *cert,
842 enum certtype type, int depth)
844 BasicConstraints bc;
845 const Extension *e;
846 size_t size;
847 int ret, i = 0;
849 if (_hx509_cert_get_version(cert) < 3)
850 return 0;
852 e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i);
853 if (e == NULL) {
854 switch(type) {
855 case PROXY_CERT:
856 case EE_CERT:
857 return 0;
858 case CA_CERT: {
859 char *name;
860 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
861 assert(ret == 0);
862 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
863 "basicConstraints missing from "
864 "CA certifiacte %s", name);
865 free(name);
866 return HX509_EXTENSION_NOT_FOUND;
871 ret = decode_BasicConstraints(e->extnValue.data,
872 e->extnValue.length, &bc,
873 &size);
874 if (ret)
875 return ret;
876 switch(type) {
877 case PROXY_CERT:
878 if (bc.cA != NULL && *bc.cA)
879 ret = HX509_PARENT_IS_CA;
880 break;
881 case EE_CERT:
882 ret = 0;
883 break;
884 case CA_CERT:
885 if (bc.cA == NULL || !*bc.cA)
886 ret = HX509_PARENT_NOT_CA;
887 else if (bc.pathLenConstraint)
888 if (depth - 1 > *bc.pathLenConstraint)
889 ret = HX509_CA_PATH_TOO_DEEP;
890 break;
892 free_BasicConstraints(&bc);
893 return ret;
897 _hx509_cert_is_parent_cmp(const Certificate *subject,
898 const Certificate *issuer,
899 int allow_self_signed)
901 int diff;
902 AuthorityKeyIdentifier ai;
903 SubjectKeyIdentifier si;
904 int ret_ai, ret_si;
906 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
907 &subject->tbsCertificate.issuer);
908 if (diff)
909 return diff;
911 memset(&ai, 0, sizeof(ai));
912 memset(&si, 0, sizeof(si));
915 * Try to find AuthorityKeyIdentifier, if it's not present in the
916 * subject certificate nor the parent.
919 ret_ai = find_extension_auth_key_id(subject, &ai);
920 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
921 return 1;
922 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
923 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
924 return -1;
926 if (ret_si && ret_ai)
927 goto out;
928 if (ret_ai)
929 goto out;
930 if (ret_si) {
931 if (allow_self_signed) {
932 diff = 0;
933 goto out;
934 } else if (ai.keyIdentifier) {
935 diff = -1;
936 goto out;
940 if (ai.keyIdentifier == NULL) {
941 Name name;
943 if (ai.authorityCertIssuer == NULL)
944 return -1;
945 if (ai.authorityCertSerialNumber == NULL)
946 return -1;
948 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
949 &issuer->tbsCertificate.serialNumber);
950 if (diff)
951 return diff;
952 if (ai.authorityCertIssuer->len != 1)
953 return -1;
954 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
955 return -1;
957 name.element =
958 ai.authorityCertIssuer->val[0].u.directoryName.element;
959 name.u.rdnSequence =
960 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
962 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
963 &name);
964 if (diff)
965 return diff;
966 diff = 0;
967 } else
968 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
969 if (diff)
970 goto out;
972 out:
973 free_AuthorityKeyIdentifier(&ai);
974 free_SubjectKeyIdentifier(&si);
975 return diff;
978 static int
979 certificate_is_anchor(hx509_context context,
980 hx509_certs trust_anchors,
981 const hx509_cert cert)
983 hx509_query q;
984 hx509_cert c;
985 int ret;
987 if (trust_anchors == NULL)
988 return 0;
990 _hx509_query_clear(&q);
992 q.match = HX509_QUERY_MATCH_CERTIFICATE;
993 q.certificate = _hx509_get_cert(cert);
995 ret = hx509_certs_find(context, trust_anchors, &q, &c);
996 if (ret == 0)
997 hx509_cert_free(c);
998 return ret == 0;
1001 static int
1002 certificate_is_self_signed(const Certificate *cert)
1004 return _hx509_name_cmp(&cert->tbsCertificate.subject,
1005 &cert->tbsCertificate.issuer) == 0;
1009 * The subjectName is "null" when it's empty set of relative DBs.
1012 static int
1013 subject_null_p(const Certificate *c)
1015 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1019 static int
1020 find_parent(hx509_context context,
1021 time_t time_now,
1022 hx509_certs trust_anchors,
1023 hx509_path *path,
1024 hx509_certs pool,
1025 hx509_cert current,
1026 hx509_cert *parent)
1028 AuthorityKeyIdentifier ai;
1029 hx509_query q;
1030 int ret;
1032 *parent = NULL;
1033 memset(&ai, 0, sizeof(ai));
1035 _hx509_query_clear(&q);
1037 if (!subject_null_p(current->data)) {
1038 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1039 q.subject = _hx509_get_cert(current);
1040 } else {
1041 ret = find_extension_auth_key_id(current->data, &ai);
1042 if (ret) {
1043 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1044 "Subjectless certificate missing AuthKeyID");
1045 return HX509_CERTIFICATE_MALFORMED;
1048 if (ai.keyIdentifier == NULL) {
1049 free_AuthorityKeyIdentifier(&ai);
1050 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1051 "Subjectless certificate missing keyIdentifier "
1052 "inside AuthKeyID");
1053 return HX509_CERTIFICATE_MALFORMED;
1056 q.subject_id = ai.keyIdentifier;
1057 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1060 q.path = path;
1061 q.match |= HX509_QUERY_NO_MATCH_PATH;
1063 if (pool) {
1064 q.timenow = time_now;
1065 q.match |= HX509_QUERY_MATCH_TIME;
1067 ret = hx509_certs_find(context, pool, &q, parent);
1068 if (ret == 0) {
1069 free_AuthorityKeyIdentifier(&ai);
1070 return 0;
1072 q.match &= ~HX509_QUERY_MATCH_TIME;
1075 if (trust_anchors) {
1076 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1077 if (ret == 0) {
1078 free_AuthorityKeyIdentifier(&ai);
1079 return ret;
1082 free_AuthorityKeyIdentifier(&ai);
1085 hx509_name name;
1086 char *str;
1088 ret = hx509_cert_get_subject(current, &name);
1089 if (ret) {
1090 hx509_clear_error_string(context);
1091 return HX509_ISSUER_NOT_FOUND;
1093 ret = hx509_name_to_string(name, &str);
1094 hx509_name_free(&name);
1095 if (ret) {
1096 hx509_clear_error_string(context);
1097 return HX509_ISSUER_NOT_FOUND;
1100 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1101 "Failed to find issuer for "
1102 "certificate with subject: '%s'", str);
1103 free(str);
1105 return HX509_ISSUER_NOT_FOUND;
1112 static int
1113 is_proxy_cert(hx509_context context,
1114 const Certificate *cert,
1115 ProxyCertInfo *rinfo)
1117 ProxyCertInfo info;
1118 const Extension *e;
1119 size_t size;
1120 int ret, i = 0;
1122 if (rinfo)
1123 memset(rinfo, 0, sizeof(*rinfo));
1125 e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i);
1126 if (e == NULL) {
1127 hx509_clear_error_string(context);
1128 return HX509_EXTENSION_NOT_FOUND;
1131 ret = decode_ProxyCertInfo(e->extnValue.data,
1132 e->extnValue.length,
1133 &info,
1134 &size);
1135 if (ret) {
1136 hx509_clear_error_string(context);
1137 return ret;
1139 if (size != e->extnValue.length) {
1140 free_ProxyCertInfo(&info);
1141 hx509_clear_error_string(context);
1142 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1144 if (rinfo == NULL)
1145 free_ProxyCertInfo(&info);
1146 else
1147 *rinfo = info;
1149 return 0;
1153 * Path operations are like MEMORY based keyset, but with exposed
1154 * internal so we can do easy searches.
1158 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1160 hx509_cert *val;
1161 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1162 if (val == NULL) {
1163 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1164 return ENOMEM;
1167 path->val = val;
1168 path->val[path->len] = hx509_cert_ref(cert);
1169 path->len++;
1171 return 0;
1174 void
1175 _hx509_path_free(hx509_path *path)
1177 unsigned i;
1179 for (i = 0; i < path->len; i++)
1180 hx509_cert_free(path->val[i]);
1181 free(path->val);
1182 path->val = NULL;
1183 path->len = 0;
1187 * Find path by looking up issuer for the top certificate and continue
1188 * until an anchor certificate is found or max limit is found. A
1189 * certificate never included twice in the path.
1191 * If the trust anchors are not given, calculate optimistic path, just
1192 * follow the chain upward until we no longer find a parent or we hit
1193 * the max path limit. In this case, a failure will always be returned
1194 * depending on what error condition is hit first.
1196 * The path includes a path from the top certificate to the anchor
1197 * certificate.
1199 * The caller needs to free `path´ both on successful built path and
1200 * failure.
1204 _hx509_calculate_path(hx509_context context,
1205 int flags,
1206 time_t time_now,
1207 hx509_certs anchors,
1208 unsigned int max_depth,
1209 hx509_cert cert,
1210 hx509_certs pool,
1211 hx509_path *path)
1213 hx509_cert parent, current;
1214 int ret;
1216 if (max_depth == 0)
1217 max_depth = HX509_VERIFY_MAX_DEPTH;
1219 ret = _hx509_path_append(context, path, cert);
1220 if (ret)
1221 return ret;
1223 current = hx509_cert_ref(cert);
1225 while (!certificate_is_anchor(context, anchors, current)) {
1227 ret = find_parent(context, time_now, anchors, path,
1228 pool, current, &parent);
1229 hx509_cert_free(current);
1230 if (ret)
1231 return ret;
1233 ret = _hx509_path_append(context, path, parent);
1234 if (ret)
1235 return ret;
1236 current = parent;
1238 if (path->len > max_depth) {
1239 hx509_cert_free(current);
1240 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1241 "Path too long while bulding "
1242 "certificate chain");
1243 return HX509_PATH_TOO_LONG;
1247 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1248 path->len > 0 &&
1249 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1251 hx509_cert_free(path->val[path->len - 1]);
1252 path->len--;
1255 hx509_cert_free(current);
1256 return 0;
1259 static int
1260 AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1261 const AlgorithmIdentifier *q)
1263 int diff;
1264 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1265 if (diff)
1266 return diff;
1267 if (p->parameters) {
1268 if (q->parameters)
1269 return heim_any_cmp(p->parameters,
1270 q->parameters);
1271 else
1272 return 1;
1273 } else {
1274 if (q->parameters)
1275 return -1;
1276 else
1277 return 0;
1282 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1284 int diff;
1285 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1286 if (diff)
1287 return diff;
1288 diff = AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1289 &q->signatureAlgorithm);
1290 if (diff)
1291 return diff;
1292 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1293 &q->tbsCertificate._save);
1294 return diff;
1298 * Compare to hx509 certificate object, useful for sorting.
1300 * @param p a hx509 certificate object.
1301 * @param q a hx509 certificate object.
1303 * @return 0 the objects are the same, returns > 0 is p is "larger"
1304 * then q, < 0 if p is "smaller" then q.
1306 * @ingroup hx509_cert
1310 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1312 return _hx509_Certificate_cmp(p->data, q->data);
1316 * Return the name of the issuer of the hx509 certificate.
1318 * @param p a hx509 certificate object.
1319 * @param name a pointer to a hx509 name, should be freed by
1320 * hx509_name_free().
1322 * @return An hx509 error code, see hx509_get_error_string().
1324 * @ingroup hx509_cert
1328 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1330 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1334 * Return the name of the subject of the hx509 certificate.
1336 * @param p a hx509 certificate object.
1337 * @param name a pointer to a hx509 name, should be freed by
1338 * hx509_name_free(). See also hx509_cert_get_base_subject().
1340 * @return An hx509 error code, see hx509_get_error_string().
1342 * @ingroup hx509_cert
1346 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1348 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1352 * Return the name of the base subject of the hx509 certificate. If
1353 * the certiicate is a verified proxy certificate, the this function
1354 * return the base certificate (root of the proxy chain). If the proxy
1355 * certificate is not verified with the base certificate
1356 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1358 * @param context a hx509 context.
1359 * @param c a hx509 certificate object.
1360 * @param name a pointer to a hx509 name, should be freed by
1361 * hx509_name_free(). See also hx509_cert_get_subject().
1363 * @return An hx509 error code, see hx509_get_error_string().
1365 * @ingroup hx509_cert
1369 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1370 hx509_name *name)
1372 if (c->basename)
1373 return hx509_name_copy(context, c->basename, name);
1374 if (is_proxy_cert(context, c->data, NULL) == 0) {
1375 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1376 hx509_set_error_string(context, 0, ret,
1377 "Proxy certificate have not been "
1378 "canonicalize yet, no base name");
1379 return ret;
1381 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1385 * Get serial number of the certificate.
1387 * @param p a hx509 certificate object.
1388 * @param i serial number, should be freed ith der_free_heim_integer().
1390 * @return An hx509 error code, see hx509_get_error_string().
1392 * @ingroup hx509_cert
1396 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1398 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1402 * Get notBefore time of the certificate.
1404 * @param p a hx509 certificate object.
1406 * @return return not before time
1408 * @ingroup hx509_cert
1411 time_t
1412 hx509_cert_get_notBefore(hx509_cert p)
1414 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1418 * Get notAfter time of the certificate.
1420 * @param p a hx509 certificate object.
1422 * @return return not after time.
1424 * @ingroup hx509_cert
1427 time_t
1428 hx509_cert_get_notAfter(hx509_cert p)
1430 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1434 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1436 * @param p a hx509 certificate object.
1437 * @param spki SubjectPublicKeyInfo, should be freed with
1438 * free_SubjectPublicKeyInfo().
1440 * @return An hx509 error code, see hx509_get_error_string().
1442 * @ingroup hx509_cert
1446 hx509_cert_get_SPKI(hx509_cert p, SubjectPublicKeyInfo *spki)
1448 return copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo,
1449 spki);
1452 hx509_private_key
1453 _hx509_cert_private_key(hx509_cert p)
1455 return p->private_key;
1459 _hx509_cert_private_key_exportable(hx509_cert p)
1461 if (p->private_key == NULL)
1462 return 0;
1463 return _hx509_private_key_exportable(p->private_key);
1467 _hx509_cert_private_decrypt(hx509_context context,
1468 const heim_octet_string *ciphertext,
1469 const heim_oid *encryption_oid,
1470 hx509_cert p,
1471 heim_octet_string *cleartext)
1473 cleartext->data = NULL;
1474 cleartext->length = 0;
1476 if (p->private_key == NULL) {
1477 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1478 "Private key missing");
1479 return HX509_PRIVATE_KEY_MISSING;
1482 return _hx509_private_key_private_decrypt(context,
1483 ciphertext,
1484 encryption_oid,
1485 p->private_key,
1486 cleartext);
1490 _hx509_cert_public_encrypt(hx509_context context,
1491 const heim_octet_string *cleartext,
1492 const hx509_cert p,
1493 heim_oid *encryption_oid,
1494 heim_octet_string *ciphertext)
1496 return _hx509_public_encrypt(context,
1497 cleartext, p->data,
1498 encryption_oid, ciphertext);
1505 time_t
1506 _hx509_Time2time_t(const Time *t)
1508 switch(t->element) {
1509 case choice_Time_utcTime:
1510 return t->u.utcTime;
1511 case choice_Time_generalTime:
1512 return t->u.generalTime;
1514 return 0;
1521 static int
1522 init_name_constraints(hx509_name_constraints *nc)
1524 memset(nc, 0, sizeof(*nc));
1525 return 0;
1528 static int
1529 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1530 hx509_name_constraints *nc)
1532 NameConstraints tnc;
1533 int ret;
1535 ret = find_extension_name_constraints(c, &tnc);
1536 if (ret == HX509_EXTENSION_NOT_FOUND)
1537 return 0;
1538 else if (ret) {
1539 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1540 return ret;
1541 } else if (not_ca) {
1542 ret = HX509_VERIFY_CONSTRAINTS;
1543 hx509_set_error_string(context, 0, ret, "Not a CA and "
1544 "have NameConstraints");
1545 } else {
1546 NameConstraints *val;
1547 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1548 if (val == NULL) {
1549 hx509_clear_error_string(context);
1550 ret = ENOMEM;
1551 goto out;
1553 nc->val = val;
1554 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1555 if (ret) {
1556 hx509_clear_error_string(context);
1557 goto out;
1559 nc->len += 1;
1561 out:
1562 free_NameConstraints(&tnc);
1563 return ret;
1566 static int
1567 match_RDN(const RelativeDistinguishedName *c,
1568 const RelativeDistinguishedName *n)
1570 int i;
1572 if (c->len != n->len)
1573 return HX509_NAME_CONSTRAINT_ERROR;
1575 for (i = 0; i < n->len; i++) {
1576 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1577 return HX509_NAME_CONSTRAINT_ERROR;
1578 if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0)
1579 return HX509_NAME_CONSTRAINT_ERROR;
1581 return 0;
1584 static int
1585 match_X501Name(const Name *c, const Name *n)
1587 int i, ret;
1589 if (c->element != choice_Name_rdnSequence
1590 || n->element != choice_Name_rdnSequence)
1591 return 0;
1592 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1593 return HX509_NAME_CONSTRAINT_ERROR;
1594 for (i = 0; i < c->u.rdnSequence.len; i++) {
1595 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1596 if (ret)
1597 return ret;
1599 return 0;
1603 static int
1604 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1607 * Name constraints only apply to the same name type, see RFC3280,
1608 * 4.2.1.11.
1610 assert(c->element == n->element);
1612 switch(c->element) {
1613 case choice_GeneralName_otherName:
1614 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1615 &n->u.otherName.type_id) != 0)
1616 return HX509_NAME_CONSTRAINT_ERROR;
1617 if (heim_any_cmp(&c->u.otherName.value,
1618 &n->u.otherName.value) != 0)
1619 return HX509_NAME_CONSTRAINT_ERROR;
1620 *match = 1;
1621 return 0;
1622 case choice_GeneralName_rfc822Name: {
1623 const char *s;
1624 size_t len1, len2;
1625 s = strchr(c->u.rfc822Name, '@');
1626 if (s) {
1627 if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1628 return HX509_NAME_CONSTRAINT_ERROR;
1629 } else {
1630 s = strchr(n->u.rfc822Name, '@');
1631 if (s == NULL)
1632 return HX509_NAME_CONSTRAINT_ERROR;
1633 len1 = strlen(c->u.rfc822Name);
1634 len2 = strlen(s + 1);
1635 if (len1 > len2)
1636 return HX509_NAME_CONSTRAINT_ERROR;
1637 if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1638 return HX509_NAME_CONSTRAINT_ERROR;
1639 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1640 return HX509_NAME_CONSTRAINT_ERROR;
1642 *match = 1;
1643 return 0;
1645 case choice_GeneralName_dNSName: {
1646 size_t lenc, lenn;
1648 lenc = strlen(c->u.dNSName);
1649 lenn = strlen(n->u.dNSName);
1650 if (lenc > lenn)
1651 return HX509_NAME_CONSTRAINT_ERROR;
1652 if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1653 return HX509_NAME_CONSTRAINT_ERROR;
1654 if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1655 return HX509_NAME_CONSTRAINT_ERROR;
1656 *match = 1;
1657 return 0;
1659 case choice_GeneralName_directoryName: {
1660 Name c_name, n_name;
1661 int ret;
1663 c_name._save.data = NULL;
1664 c_name._save.length = 0;
1665 c_name.element = c->u.directoryName.element;
1666 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1668 n_name._save.data = NULL;
1669 n_name._save.length = 0;
1670 n_name.element = n->u.directoryName.element;
1671 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1673 ret = match_X501Name(&c_name, &n_name);
1674 if (ret == 0)
1675 *match = 1;
1676 return ret;
1678 case choice_GeneralName_uniformResourceIdentifier:
1679 case choice_GeneralName_iPAddress:
1680 case choice_GeneralName_registeredID:
1681 default:
1682 return HX509_NAME_CONSTRAINT_ERROR;
1686 static int
1687 match_alt_name(const GeneralName *n, const Certificate *c,
1688 int *same, int *match)
1690 GeneralNames sa;
1691 int ret, i, j;
1693 i = 0;
1694 do {
1695 ret = find_extension_subject_alt_name(c, &i, &sa);
1696 if (ret == HX509_EXTENSION_NOT_FOUND) {
1697 ret = 0;
1698 break;
1699 } else if (ret != 0)
1700 break;
1702 for (j = 0; j < sa.len; j++) {
1703 if (n->element == sa.val[j].element) {
1704 *same = 1;
1705 ret = match_general_name(n, &sa.val[j], match);
1708 free_GeneralNames(&sa);
1709 } while (1);
1710 return ret;
1714 static int
1715 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1717 int name, alt_name, same;
1718 unsigned int i;
1719 int ret = 0;
1721 name = alt_name = same = *match = 0;
1722 for (i = 0; i < t->len; i++) {
1723 if (t->val[i].minimum && t->val[i].maximum)
1724 return HX509_RANGE;
1727 * If the constraint apply to directoryNames, test is with
1728 * subjectName of the certificate if the certificate have a
1729 * non-null (empty) subjectName.
1732 if (t->val[i].base.element == choice_GeneralName_directoryName
1733 && !subject_null_p(c))
1735 GeneralName certname;
1737 memset(&certname, 0, sizeof(certname));
1738 certname.element = choice_GeneralName_directoryName;
1739 certname.u.directoryName.element =
1740 c->tbsCertificate.subject.element;
1741 certname.u.directoryName.u.rdnSequence =
1742 c->tbsCertificate.subject.u.rdnSequence;
1744 ret = match_general_name(&t->val[i].base, &certname, &name);
1747 /* Handle subjectAltNames, this is icky since they
1748 * restrictions only apply if the subjectAltName is of the
1749 * same type. So if there have been a match of type, require
1750 * altname to be set.
1752 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1754 if (name && (!same || alt_name))
1755 *match = 1;
1756 return ret;
1759 static int
1760 check_name_constraints(hx509_context context,
1761 const hx509_name_constraints *nc,
1762 const Certificate *c)
1764 int match, ret;
1765 int i;
1767 for (i = 0 ; i < nc->len; i++) {
1768 GeneralSubtrees gs;
1770 if (nc->val[i].permittedSubtrees) {
1771 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1772 ret = match_tree(&gs, c, &match);
1773 if (ret) {
1774 hx509_clear_error_string(context);
1775 return ret;
1777 /* allow null subjectNames, they wont matches anything */
1778 if (match == 0 && !subject_null_p(c)) {
1779 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1780 "Error verify constraints, "
1781 "certificate didn't match any "
1782 "permitted subtree");
1783 return HX509_VERIFY_CONSTRAINTS;
1786 if (nc->val[i].excludedSubtrees) {
1787 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1788 ret = match_tree(&gs, c, &match);
1789 if (ret) {
1790 hx509_clear_error_string(context);
1791 return ret;
1793 if (match) {
1794 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1795 "Error verify constraints, "
1796 "certificate included in excluded "
1797 "subtree");
1798 return HX509_VERIFY_CONSTRAINTS;
1802 return 0;
1805 static void
1806 free_name_constraints(hx509_name_constraints *nc)
1808 int i;
1810 for (i = 0 ; i < nc->len; i++)
1811 free_NameConstraints(&nc->val[i]);
1812 free(nc->val);
1816 * Build and verify the path for the certificate to the trust anchor
1817 * specified in the verify context. The path is constructed from the
1818 * certificate, the pool and the trust anchors.
1820 * @param context A hx509 context.
1821 * @param ctx A hx509 verification context.
1822 * @param cert the certificate to build the path from.
1823 * @param pool A keyset of certificates to build the chain from.
1825 * @return An hx509 error code, see hx509_get_error_string().
1827 * @ingroup hx509_verify
1831 hx509_verify_path(hx509_context context,
1832 hx509_verify_ctx ctx,
1833 hx509_cert cert,
1834 hx509_certs pool)
1836 hx509_name_constraints nc;
1837 hx509_path path;
1838 #if 0
1839 const AlgorithmIdentifier *alg_id;
1840 #endif
1841 int ret, i, proxy_cert_depth, selfsigned_depth;
1842 enum certtype type;
1843 Name proxy_issuer;
1844 hx509_certs anchors = NULL;
1846 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1848 ret = init_name_constraints(&nc);
1849 if (ret)
1850 return ret;
1852 path.val = NULL;
1853 path.len = 0;
1855 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1856 ctx->time_now = time(NULL);
1861 if (ctx->trust_anchors)
1862 anchors = _hx509_certs_ref(ctx->trust_anchors);
1863 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1864 anchors = _hx509_certs_ref(context->default_trust_anchors);
1865 else {
1866 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1867 if (ret)
1868 goto out;
1872 * Calculate the path from the certificate user presented to the
1873 * to an anchor.
1875 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1876 anchors, ctx->max_depth,
1877 cert, pool, &path);
1878 if (ret)
1879 goto out;
1881 #if 0
1882 alg_id = path.val[path->len - 1]->data->tbsCertificate.signature;
1883 #endif
1886 * Check CA and proxy certificate chain from the top of the
1887 * certificate chain. Also check certificate is valid with respect
1888 * to the current time.
1892 proxy_cert_depth = 0;
1893 selfsigned_depth = 0;
1895 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1896 type = PROXY_CERT;
1897 else
1898 type = EE_CERT;
1900 for (i = 0; i < path.len; i++) {
1901 Certificate *c;
1902 time_t t;
1904 c = _hx509_get_cert(path.val[i]);
1907 * Lets do some basic check on issuer like
1908 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1909 * on what type of certificate this is.
1912 switch (type) {
1913 case CA_CERT:
1914 /* XXX make constants for keyusage */
1915 ret = check_key_usage(context, c, 1 << 5,
1916 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1917 if (ret) {
1918 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1919 "Key usage missing from CA certificate");
1920 goto out;
1923 if (i + 1 != path.len && certificate_is_self_signed(c))
1924 selfsigned_depth++;
1926 break;
1927 case PROXY_CERT: {
1928 ProxyCertInfo info;
1930 if (is_proxy_cert(context, c, &info) == 0) {
1931 int j;
1933 if (info.pCPathLenConstraint != NULL &&
1934 *info.pCPathLenConstraint < i)
1936 free_ProxyCertInfo(&info);
1937 ret = HX509_PATH_TOO_LONG;
1938 hx509_set_error_string(context, 0, ret,
1939 "Proxy certificate chain "
1940 "longer then allowed");
1941 goto out;
1943 /* XXX MUST check info.proxyPolicy */
1944 free_ProxyCertInfo(&info);
1946 j = 0;
1947 if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
1948 ret = HX509_PROXY_CERT_INVALID;
1949 hx509_set_error_string(context, 0, ret,
1950 "Proxy certificate have explicity "
1951 "forbidden subjectAltName");
1952 goto out;
1955 j = 0;
1956 if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
1957 ret = HX509_PROXY_CERT_INVALID;
1958 hx509_set_error_string(context, 0, ret,
1959 "Proxy certificate have explicity "
1960 "forbidden issuerAltName");
1961 goto out;
1965 * The subject name of the proxy certificate should be
1966 * CN=XXX,<proxy issuer>, prune of CN and check if its
1967 * the same over the whole chain of proxy certs and
1968 * then check with the EE cert when we get to it.
1971 if (proxy_cert_depth) {
1972 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject);
1973 if (ret) {
1974 ret = HX509_PROXY_CERT_NAME_WRONG;
1975 hx509_set_error_string(context, 0, ret,
1976 "Base proxy name not right");
1977 goto out;
1981 free_Name(&proxy_issuer);
1983 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
1984 if (ret) {
1985 hx509_clear_error_string(context);
1986 goto out;
1989 j = proxy_issuer.u.rdnSequence.len;
1990 if (proxy_issuer.u.rdnSequence.len < 2
1991 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
1992 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
1993 oid_id_at_commonName()))
1995 ret = HX509_PROXY_CERT_NAME_WRONG;
1996 hx509_set_error_string(context, 0, ret,
1997 "Proxy name too short or "
1998 "does not have Common name "
1999 "at the top");
2000 goto out;
2003 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2004 proxy_issuer.u.rdnSequence.len -= 1;
2006 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer);
2007 if (ret != 0) {
2008 ret = HX509_PROXY_CERT_NAME_WRONG;
2009 hx509_set_error_string(context, 0, ret,
2010 "Proxy issuer name not as expected");
2011 goto out;
2014 break;
2015 } else {
2017 * Now we are done with the proxy certificates, this
2018 * cert was an EE cert and we we will fall though to
2019 * EE checking below.
2021 type = EE_CERT;
2022 /* FALLTHOUGH */
2025 case EE_CERT:
2027 * If there where any proxy certificates in the chain
2028 * (proxy_cert_depth > 0), check that the proxy issuer
2029 * matched proxy certificates "base" subject.
2031 if (proxy_cert_depth) {
2033 ret = _hx509_name_cmp(&proxy_issuer,
2034 &c->tbsCertificate.subject);
2035 if (ret) {
2036 ret = HX509_PROXY_CERT_NAME_WRONG;
2037 hx509_clear_error_string(context);
2038 goto out;
2040 if (cert->basename)
2041 hx509_name_free(&cert->basename);
2043 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2044 if (ret) {
2045 hx509_clear_error_string(context);
2046 goto out;
2050 break;
2053 ret = check_basic_constraints(context, c, type,
2054 i - proxy_cert_depth - selfsigned_depth);
2055 if (ret)
2056 goto out;
2059 * Don't check the trust anchors expiration time since they
2060 * are transported out of band, from RFC3820.
2062 if (i + 1 != path.len || CHECK_TA(ctx)) {
2064 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2065 if (t > ctx->time_now) {
2066 ret = HX509_CERT_USED_BEFORE_TIME;
2067 hx509_clear_error_string(context);
2068 goto out;
2070 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2071 if (t < ctx->time_now) {
2072 ret = HX509_CERT_USED_AFTER_TIME;
2073 hx509_clear_error_string(context);
2074 goto out;
2078 if (type == EE_CERT)
2079 type = CA_CERT;
2080 else if (type == PROXY_CERT)
2081 proxy_cert_depth++;
2085 * Verify constraints, do this backward so path constraints are
2086 * checked in the right order.
2089 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2090 Certificate *c;
2092 c = _hx509_get_cert(path.val[i]);
2094 /* verify name constraints, not for selfsigned and anchor */
2095 if (!certificate_is_self_signed(c) || i + 1 != path.len) {
2096 ret = check_name_constraints(context, &nc, c);
2097 if (ret) {
2098 goto out;
2101 ret = add_name_constraints(context, c, i == 0, &nc);
2102 if (ret)
2103 goto out;
2105 /* XXX verify all other silly constraints */
2110 * Verify that no certificates has been revoked.
2113 if (ctx->revoke_ctx) {
2114 hx509_certs certs;
2116 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2117 NULL, &certs);
2118 if (ret)
2119 goto out;
2121 for (i = 0; i < path.len; i++) {
2122 ret = hx509_certs_add(context, certs, path.val[i]);
2123 if (ret) {
2124 hx509_certs_free(&certs);
2125 goto out;
2128 ret = hx509_certs_merge(context, certs, pool);
2129 if (ret) {
2130 hx509_certs_free(&certs);
2131 goto out;
2134 for (i = 0; i < path.len - 1; i++) {
2135 int parent = (i < path.len - 1) ? i + 1 : i;
2137 ret = hx509_revoke_verify(context,
2138 ctx->revoke_ctx,
2139 certs,
2140 ctx->time_now,
2141 path.val[i],
2142 path.val[parent]);
2143 if (ret) {
2144 hx509_certs_free(&certs);
2145 goto out;
2148 hx509_certs_free(&certs);
2151 #if 0
2152 for (i = path.len - 1; i >= 0; i--) {
2153 _hx509_print_cert_subject(path.val[i]);
2155 #endif
2158 * Verify signatures, do this backward so public key working
2159 * parameter is passed up from the anchor up though the chain.
2162 for (i = path.len - 1; i >= 0; i--) {
2163 Certificate *signer, *c;
2165 c = _hx509_get_cert(path.val[i]);
2167 /* is last in chain (trust anchor) */
2168 if (i + 1 == path.len) {
2169 signer = path.val[i]->data;
2171 /* if trust anchor is not self signed, don't check sig */
2172 if (!certificate_is_self_signed(signer))
2173 continue;
2174 } else {
2175 /* take next certificate in chain */
2176 signer = path.val[i + 1]->data;
2179 /* verify signatureValue */
2180 ret = _hx509_verify_signature_bitstring(context,
2181 signer,
2182 &c->signatureAlgorithm,
2183 &c->tbsCertificate._save,
2184 &c->signatureValue);
2185 if (ret) {
2186 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2187 "Failed to verify signature of certificate");
2188 goto out;
2192 out:
2193 hx509_certs_free(&anchors);
2194 free_Name(&proxy_issuer);
2195 free_name_constraints(&nc);
2196 _hx509_path_free(&path);
2198 return ret;
2202 * Verify a signature made using the private key of an certificate.
2204 * @param context A hx509 context.
2205 * @param signer the certificate that made the signature.
2206 * @param alg algorthm that was used to sign the data.
2207 * @param data the data that was signed.
2208 * @param sig the sigature to verify.
2210 * @return An hx509 error code, see hx509_get_error_string().
2212 * @ingroup hx509_crypto
2216 hx509_verify_signature(hx509_context context,
2217 const hx509_cert signer,
2218 const AlgorithmIdentifier *alg,
2219 const heim_octet_string *data,
2220 const heim_octet_string *sig)
2222 return _hx509_verify_signature(context, signer->data, alg, data, sig);
2227 * Verify that the certificate is allowed to be used for the hostname
2228 * and address.
2230 * @param context A hx509 context.
2231 * @param cert the certificate to match with
2232 * @param flags undocumented flags, use 0
2234 * @param type type of hostname: HX509_HN_HOSTNAME for plain hostname,
2235 * HX509_HN_DNSSRV for DNS SRV names.
2236 * @param hostname the hostname to check
2237 * @param sa address of the host
2238 * @param sa_size length of address
2240 * @return An hx509 error code, see hx509_get_error_string().
2242 * @ingroup hx509_cert
2246 hx509_verify_hostname(hx509_context context,
2247 const hx509_cert cert,
2248 int flags,
2249 hx509_hostname_type type,
2250 const char *hostname,
2251 const struct sockaddr *sa,
2252 /* XXX krb5_socklen_t */ int sa_size)
2254 GeneralNames san;
2255 int ret, i, j;
2257 if (sa && sa_size <= 0)
2258 return EINVAL;
2260 memset(&san, 0, sizeof(san));
2262 i = 0;
2263 do {
2264 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2265 if (ret == HX509_EXTENSION_NOT_FOUND) {
2266 ret = 0;
2267 break;
2268 } else if (ret != 0)
2269 break;
2271 for (j = 0; j < san.len; j++) {
2272 switch (san.val[j].element) {
2273 case choice_GeneralName_dNSName:
2274 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2275 free_GeneralNames(&san);
2276 return 0;
2278 break;
2279 default:
2280 break;
2283 free_GeneralNames(&san);
2284 } while (1);
2287 Name *name = &cert->data->tbsCertificate.subject;
2289 /* match if first component is a CN= */
2290 if (name->u.rdnSequence.len > 0
2291 && name->u.rdnSequence.val[0].len == 1
2292 && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
2293 oid_id_at_commonName()) == 0)
2295 DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
2297 switch (ds->element) {
2298 case choice_DirectoryString_printableString:
2299 if (strcasecmp(ds->u.printableString, hostname) == 0)
2300 return 0;
2301 break;
2302 case choice_DirectoryString_ia5String:
2303 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2304 return 0;
2305 break;
2306 case choice_DirectoryString_utf8String:
2307 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2308 return 0;
2309 default:
2310 break;
2315 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2316 ret = HX509_NAME_CONSTRAINT_ERROR;
2318 return ret;
2322 _hx509_set_cert_attribute(hx509_context context,
2323 hx509_cert cert,
2324 const heim_oid *oid,
2325 const heim_octet_string *attr)
2327 hx509_cert_attribute a;
2328 void *d;
2330 if (hx509_cert_get_attribute(cert, oid) != NULL)
2331 return 0;
2333 d = realloc(cert->attrs.val,
2334 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2335 if (d == NULL) {
2336 hx509_clear_error_string(context);
2337 return ENOMEM;
2339 cert->attrs.val = d;
2341 a = malloc(sizeof(*a));
2342 if (a == NULL)
2343 return ENOMEM;
2345 der_copy_octet_string(attr, &a->data);
2346 der_copy_oid(oid, &a->oid);
2348 cert->attrs.val[cert->attrs.len] = a;
2349 cert->attrs.len++;
2351 return 0;
2355 * Get an external attribute for the certificate, examples are
2356 * friendly name and id.
2358 * @param cert hx509 certificate object to search
2359 * @param oid an oid to search for.
2361 * @return an hx509_cert_attribute, only valid as long as the
2362 * certificate is referenced.
2364 * @ingroup hx509_cert
2367 hx509_cert_attribute
2368 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2370 int i;
2371 for (i = 0; i < cert->attrs.len; i++)
2372 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2373 return cert->attrs.val[i];
2374 return NULL;
2378 * Set the friendly name on the certificate.
2380 * @param cert The certificate to set the friendly name on
2381 * @param name Friendly name.
2383 * @return An hx509 error code, see hx509_get_error_string().
2385 * @ingroup hx509_cert
2389 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2391 if (cert->friendlyname)
2392 free(cert->friendlyname);
2393 cert->friendlyname = strdup(name);
2394 if (cert->friendlyname == NULL)
2395 return ENOMEM;
2396 return 0;
2400 * Get friendly name of the certificate.
2402 * @param cert cert to get the friendly name from.
2404 * @return an friendly name or NULL if there is. The friendly name is
2405 * only valid as long as the certificate is referenced.
2407 * @ingroup hx509_cert
2410 const char *
2411 hx509_cert_get_friendly_name(hx509_cert cert)
2413 hx509_cert_attribute a;
2414 PKCS9_friendlyName n;
2415 size_t sz;
2416 int ret, i;
2418 if (cert->friendlyname)
2419 return cert->friendlyname;
2421 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
2422 if (a == NULL) {
2423 /* XXX use subject name ? */
2424 return NULL;
2427 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2428 if (ret)
2429 return NULL;
2431 if (n.len != 1) {
2432 free_PKCS9_friendlyName(&n);
2433 return NULL;
2436 cert->friendlyname = malloc(n.val[0].length + 1);
2437 if (cert->friendlyname == NULL) {
2438 free_PKCS9_friendlyName(&n);
2439 return NULL;
2442 for (i = 0; i < n.val[0].length; i++) {
2443 if (n.val[0].data[i] <= 0xff)
2444 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2445 else
2446 cert->friendlyname[i] = 'X';
2448 cert->friendlyname[i] = '\0';
2449 free_PKCS9_friendlyName(&n);
2451 return cert->friendlyname;
2454 void
2455 _hx509_query_clear(hx509_query *q)
2457 memset(q, 0, sizeof(*q));
2461 * Allocate an query controller. Free using hx509_query_free().
2463 * @param context A hx509 context.
2464 * @param q return pointer to a hx509_query.
2466 * @return An hx509 error code, see hx509_get_error_string().
2468 * @ingroup hx509_cert
2472 hx509_query_alloc(hx509_context context, hx509_query **q)
2474 *q = calloc(1, sizeof(**q));
2475 if (*q == NULL)
2476 return ENOMEM;
2477 return 0;
2481 * Set match options for the hx509 query controller.
2483 * @param q query controller.
2484 * @param option options to control the query controller.
2486 * @return An hx509 error code, see hx509_get_error_string().
2488 * @ingroup hx509_cert
2491 void
2492 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2494 switch(option) {
2495 case HX509_QUERY_OPTION_PRIVATE_KEY:
2496 q->match |= HX509_QUERY_PRIVATE_KEY;
2497 break;
2498 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2499 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2500 break;
2501 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2502 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2503 break;
2504 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2505 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2506 break;
2507 case HX509_QUERY_OPTION_END:
2508 default:
2509 break;
2514 * Set the issuer and serial number of match in the query
2515 * controller. The function make copies of the isser and serial number.
2517 * @param q a hx509 query controller
2518 * @param issuer issuer to search for
2519 * @param serialNumber the serialNumber of the issuer.
2521 * @return An hx509 error code, see hx509_get_error_string().
2523 * @ingroup hx509_cert
2527 hx509_query_match_issuer_serial(hx509_query *q,
2528 const Name *issuer,
2529 const heim_integer *serialNumber)
2531 int ret;
2532 if (q->serial) {
2533 der_free_heim_integer(q->serial);
2534 free(q->serial);
2536 q->serial = malloc(sizeof(*q->serial));
2537 if (q->serial == NULL)
2538 return ENOMEM;
2539 ret = der_copy_heim_integer(serialNumber, q->serial);
2540 if (ret) {
2541 free(q->serial);
2542 q->serial = NULL;
2543 return ret;
2545 if (q->issuer_name) {
2546 free_Name(q->issuer_name);
2547 free(q->issuer_name);
2549 q->issuer_name = malloc(sizeof(*q->issuer_name));
2550 if (q->issuer_name == NULL)
2551 return ENOMEM;
2552 ret = copy_Name(issuer, q->issuer_name);
2553 if (ret) {
2554 free(q->issuer_name);
2555 q->issuer_name = NULL;
2556 return ret;
2558 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2559 return 0;
2563 * Set the query controller to match on a friendly name
2565 * @param q a hx509 query controller.
2566 * @param name a friendly name to match on
2568 * @return An hx509 error code, see hx509_get_error_string().
2570 * @ingroup hx509_cert
2574 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2576 if (q->friendlyname)
2577 free(q->friendlyname);
2578 q->friendlyname = strdup(name);
2579 if (q->friendlyname == NULL)
2580 return ENOMEM;
2581 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2582 return 0;
2586 * Set the query controller to match using a specific match function.
2588 * @param q a hx509 query controller.
2589 * @param func function to use for matching, if the argument is NULL,
2590 * the match function is removed.
2591 * @param ctx context passed to the function.
2593 * @return An hx509 error code, see hx509_get_error_string().
2595 * @ingroup hx509_cert
2599 hx509_query_match_cmp_func(hx509_query *q,
2600 int (*func)(void *, hx509_cert),
2601 void *ctx)
2603 if (func)
2604 q->match |= HX509_QUERY_MATCH_FUNCTION;
2605 else
2606 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2607 q->cmp_func = func;
2608 q->cmp_func_ctx = ctx;
2609 return 0;
2613 * Free the query controller.
2615 * @param context A hx509 context.
2616 * @param q a pointer to the query controller.
2618 * @ingroup hx509_cert
2621 void
2622 hx509_query_free(hx509_context context, hx509_query *q)
2624 if (q->serial) {
2625 der_free_heim_integer(q->serial);
2626 free(q->serial);
2627 q->serial = NULL;
2629 if (q->issuer_name) {
2630 free_Name(q->issuer_name);
2631 free(q->issuer_name);
2632 q->issuer_name = NULL;
2634 if (q) {
2635 free(q->friendlyname);
2636 memset(q, 0, sizeof(*q));
2638 free(q);
2642 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2644 Certificate *c = _hx509_get_cert(cert);
2646 _hx509_query_statistic(context, 1, q);
2648 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2649 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2650 return 0;
2652 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2653 _hx509_Certificate_cmp(q->certificate, c) != 0)
2654 return 0;
2656 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2657 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2658 return 0;
2660 if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
2661 && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
2662 return 0;
2664 if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
2665 && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
2666 return 0;
2668 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2669 SubjectKeyIdentifier si;
2670 int ret;
2672 ret = _hx509_find_extension_subject_key_id(c, &si);
2673 if (ret == 0) {
2674 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2675 ret = 1;
2676 free_SubjectKeyIdentifier(&si);
2678 if (ret)
2679 return 0;
2681 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2682 return 0;
2683 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2684 _hx509_cert_private_key(cert) == NULL)
2685 return 0;
2688 unsigned ku = 0;
2689 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2690 ku |= (1 << 0);
2691 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2692 ku |= (1 << 1);
2693 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2694 ku |= (1 << 2);
2695 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2696 ku |= (1 << 3);
2697 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2698 ku |= (1 << 4);
2699 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2700 ku |= (1 << 5);
2701 if (q->match & HX509_QUERY_KU_CRLSIGN)
2702 ku |= (1 << 6);
2703 if (ku && check_key_usage(context, c, ku, TRUE))
2704 return 0;
2706 if ((q->match & HX509_QUERY_ANCHOR))
2707 return 0;
2709 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2710 hx509_cert_attribute a;
2712 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2713 if (a == NULL)
2714 return 0;
2715 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2716 return 0;
2719 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2720 size_t i;
2722 for (i = 0; i < q->path->len; i++)
2723 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2724 return 0;
2726 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2727 const char *name = hx509_cert_get_friendly_name(cert);
2728 if (name == NULL)
2729 return 0;
2730 if (strcasecmp(q->friendlyname, name) != 0)
2731 return 0;
2733 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2734 int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2735 if (ret != 0)
2736 return 0;
2739 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2740 heim_octet_string os;
2741 int ret;
2743 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2744 os.length =
2745 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2747 ret = _hx509_verify_signature(context,
2748 NULL,
2749 hx509_signature_sha1(),
2750 &os,
2751 q->keyhash_sha1);
2752 if (ret != 0)
2753 return 0;
2756 if (q->match & HX509_QUERY_MATCH_TIME) {
2757 time_t t;
2758 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2759 if (t > q->timenow)
2760 return 0;
2761 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2762 if (t < q->timenow)
2763 return 0;
2766 if (q->match & ~HX509_QUERY_MASK)
2767 return 0;
2769 return 1;
2773 * Set a statistic file for the query statistics.
2775 * @param context A hx509 context.
2776 * @param fn statistics file name
2778 * @ingroup hx509_cert
2781 void
2782 hx509_query_statistic_file(hx509_context context, const char *fn)
2784 if (context->querystat)
2785 free(context->querystat);
2786 context->querystat = strdup(fn);
2789 void
2790 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2792 FILE *f;
2793 if (context->querystat == NULL)
2794 return;
2795 f = fopen(context->querystat, "a");
2796 if (f == NULL)
2797 return;
2798 fprintf(f, "%d %d\n", type, q->match);
2799 fclose(f);
2802 static const char *statname[] = {
2803 "find issuer cert",
2804 "match serialnumber",
2805 "match issuer name",
2806 "match subject name",
2807 "match subject key id",
2808 "match issuer id",
2809 "private key",
2810 "ku encipherment",
2811 "ku digitalsignature",
2812 "ku keycertsign",
2813 "ku crlsign",
2814 "ku nonrepudiation",
2815 "ku keyagreement",
2816 "ku dataencipherment",
2817 "anchor",
2818 "match certificate",
2819 "match local key id",
2820 "no match path",
2821 "match friendly name",
2822 "match function",
2823 "match key hash sha1",
2824 "match time"
2827 struct stat_el {
2828 unsigned long stats;
2829 unsigned int index;
2833 static int
2834 stat_sort(const void *a, const void *b)
2836 const struct stat_el *ae = a;
2837 const struct stat_el *be = b;
2838 return be->stats - ae->stats;
2842 * Unparse the statistics file and print the result on a FILE descriptor.
2844 * @param context A hx509 context.
2845 * @param printtype tyep to print
2846 * @param out the FILE to write the data on.
2848 * @ingroup hx509_cert
2851 void
2852 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
2854 rtbl_t t;
2855 FILE *f;
2856 int type, mask, i, num;
2857 unsigned long multiqueries = 0, totalqueries = 0;
2858 struct stat_el stats[32];
2860 if (context->querystat == NULL)
2861 return;
2862 f = fopen(context->querystat, "r");
2863 if (f == NULL) {
2864 fprintf(out, "No statistic file %s: %s.\n",
2865 context->querystat, strerror(errno));
2866 return;
2869 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2870 stats[i].index = i;
2871 stats[i].stats = 0;
2874 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
2875 if (type != printtype)
2876 continue;
2877 num = i = 0;
2878 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
2879 if (mask & 1) {
2880 stats[i].stats++;
2881 num++;
2883 mask = mask >>1 ;
2884 i++;
2886 if (num > 1)
2887 multiqueries++;
2888 totalqueries++;
2890 fclose(f);
2892 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
2894 t = rtbl_create();
2895 if (t == NULL)
2896 errx(1, "out of memory");
2898 rtbl_set_separator (t, " ");
2900 rtbl_add_column_by_id (t, 0, "Name", 0);
2901 rtbl_add_column_by_id (t, 1, "Counter", 0);
2904 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2905 char str[10];
2907 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
2908 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
2909 else {
2910 snprintf(str, sizeof(str), "%d", stats[i].index);
2911 rtbl_add_column_entry_by_id (t, 0, str);
2913 snprintf(str, sizeof(str), "%lu", stats[i].stats);
2914 rtbl_add_column_entry_by_id (t, 1, str);
2917 rtbl_format(t, out);
2918 rtbl_destroy(t);
2920 fprintf(out, "\nQueries: multi %lu total %lu\n",
2921 multiqueries, totalqueries);
2925 * Check the extended key usage on the hx509 certificate.
2927 * @param context A hx509 context.
2928 * @param cert A hx509 context.
2929 * @param eku the EKU to check for
2930 * @param allow_any_eku if the any EKU is set, allow that to be a
2931 * substitute.
2933 * @return An hx509 error code, see hx509_get_error_string().
2935 * @ingroup hx509_cert
2939 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
2940 const heim_oid *eku, int allow_any_eku)
2942 ExtKeyUsage e;
2943 int ret, i;
2945 ret = find_extension_eku(_hx509_get_cert(cert), &e);
2946 if (ret) {
2947 hx509_clear_error_string(context);
2948 return ret;
2951 for (i = 0; i < e.len; i++) {
2952 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
2953 free_ExtKeyUsage(&e);
2954 return 0;
2956 if (allow_any_eku) {
2957 #if 0
2958 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
2959 free_ExtKeyUsage(&e);
2960 return 0;
2962 #endif
2965 free_ExtKeyUsage(&e);
2966 hx509_clear_error_string(context);
2967 return HX509_CERTIFICATE_MISSING_EKU;
2971 _hx509_cert_get_keyusage(hx509_context context,
2972 hx509_cert c,
2973 KeyUsage *ku)
2975 Certificate *cert;
2976 const Extension *e;
2977 size_t size;
2978 int ret, i = 0;
2980 memset(ku, 0, sizeof(*ku));
2982 cert = _hx509_get_cert(c);
2984 if (_hx509_cert_get_version(cert) < 3)
2985 return 0;
2987 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
2988 if (e == NULL)
2989 return HX509_KU_CERT_MISSING;
2991 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
2992 if (ret)
2993 return ret;
2994 return 0;
2998 _hx509_cert_get_eku(hx509_context context,
2999 hx509_cert cert,
3000 ExtKeyUsage *e)
3002 int ret;
3004 memset(e, 0, sizeof(*e));
3006 ret = find_extension_eku(_hx509_get_cert(cert), e);
3007 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3008 hx509_clear_error_string(context);
3009 return ret;
3011 return 0;
3015 * Encodes the hx509 certificate as a DER encode binary.
3017 * @param context A hx509 context.
3018 * @param c the certificate to encode.
3019 * @param os the encode certificate, set to NULL, 0 on case of error.
3021 * @return An hx509 error code, see hx509_get_error_string().
3023 * @ingroup hx509_cert
3027 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3029 size_t size;
3030 int ret;
3032 os->data = NULL;
3033 os->length = 0;
3035 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3036 _hx509_get_cert(c), &size, ret);
3037 if (ret) {
3038 os->data = NULL;
3039 os->length = 0;
3040 return ret;
3042 if (os->length != size)
3043 _hx509_abort("internal ASN.1 encoder error");
3045 return ret;
3049 * Last to avoid lost __attribute__s due to #undef.
3052 #undef __attribute__
3053 #define __attribute__(X)
3055 void
3056 _hx509_abort(const char *fmt, ...)
3057 __attribute__ ((noreturn, format (printf, 1, 2)))
3059 va_list ap;
3060 va_start(ap, fmt);
3061 vprintf(fmt, ap);
3062 va_end(ap);
3063 printf("\n");
3064 fflush(stdout);
3065 abort();