document flags
[heimdal.git] / lib / hx509 / cert.c
blobfa7fdf34aa5302271f07cbddbefd4cf5077da519
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 Flags to modify the behavior:
2233 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2234 * @param type type of hostname:
2235 * - HX509_HN_HOSTNAME for plain hostname.
2236 * - HX509_HN_DNSSRV for DNS SRV names.
2237 * @param hostname the hostname to check
2238 * @param sa address of the host
2239 * @param sa_size length of address
2241 * @return An hx509 error code, see hx509_get_error_string().
2243 * @ingroup hx509_cert
2247 hx509_verify_hostname(hx509_context context,
2248 const hx509_cert cert,
2249 int flags,
2250 hx509_hostname_type type,
2251 const char *hostname,
2252 const struct sockaddr *sa,
2253 /* XXX krb5_socklen_t */ int sa_size)
2255 GeneralNames san;
2256 int ret, i, j;
2258 if (sa && sa_size <= 0)
2259 return EINVAL;
2261 memset(&san, 0, sizeof(san));
2263 i = 0;
2264 do {
2265 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2266 if (ret == HX509_EXTENSION_NOT_FOUND) {
2267 ret = 0;
2268 break;
2269 } else if (ret != 0)
2270 break;
2272 for (j = 0; j < san.len; j++) {
2273 switch (san.val[j].element) {
2274 case choice_GeneralName_dNSName:
2275 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2276 free_GeneralNames(&san);
2277 return 0;
2279 break;
2280 default:
2281 break;
2284 free_GeneralNames(&san);
2285 } while (1);
2288 Name *name = &cert->data->tbsCertificate.subject;
2290 /* match if first component is a CN= */
2291 if (name->u.rdnSequence.len > 0
2292 && name->u.rdnSequence.val[0].len == 1
2293 && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
2294 oid_id_at_commonName()) == 0)
2296 DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
2298 switch (ds->element) {
2299 case choice_DirectoryString_printableString:
2300 if (strcasecmp(ds->u.printableString, hostname) == 0)
2301 return 0;
2302 break;
2303 case choice_DirectoryString_ia5String:
2304 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2305 return 0;
2306 break;
2307 case choice_DirectoryString_utf8String:
2308 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2309 return 0;
2310 default:
2311 break;
2316 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2317 ret = HX509_NAME_CONSTRAINT_ERROR;
2319 return ret;
2323 _hx509_set_cert_attribute(hx509_context context,
2324 hx509_cert cert,
2325 const heim_oid *oid,
2326 const heim_octet_string *attr)
2328 hx509_cert_attribute a;
2329 void *d;
2331 if (hx509_cert_get_attribute(cert, oid) != NULL)
2332 return 0;
2334 d = realloc(cert->attrs.val,
2335 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2336 if (d == NULL) {
2337 hx509_clear_error_string(context);
2338 return ENOMEM;
2340 cert->attrs.val = d;
2342 a = malloc(sizeof(*a));
2343 if (a == NULL)
2344 return ENOMEM;
2346 der_copy_octet_string(attr, &a->data);
2347 der_copy_oid(oid, &a->oid);
2349 cert->attrs.val[cert->attrs.len] = a;
2350 cert->attrs.len++;
2352 return 0;
2356 * Get an external attribute for the certificate, examples are
2357 * friendly name and id.
2359 * @param cert hx509 certificate object to search
2360 * @param oid an oid to search for.
2362 * @return an hx509_cert_attribute, only valid as long as the
2363 * certificate is referenced.
2365 * @ingroup hx509_cert
2368 hx509_cert_attribute
2369 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2371 int i;
2372 for (i = 0; i < cert->attrs.len; i++)
2373 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2374 return cert->attrs.val[i];
2375 return NULL;
2379 * Set the friendly name on the certificate.
2381 * @param cert The certificate to set the friendly name on
2382 * @param name Friendly name.
2384 * @return An hx509 error code, see hx509_get_error_string().
2386 * @ingroup hx509_cert
2390 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2392 if (cert->friendlyname)
2393 free(cert->friendlyname);
2394 cert->friendlyname = strdup(name);
2395 if (cert->friendlyname == NULL)
2396 return ENOMEM;
2397 return 0;
2401 * Get friendly name of the certificate.
2403 * @param cert cert to get the friendly name from.
2405 * @return an friendly name or NULL if there is. The friendly name is
2406 * only valid as long as the certificate is referenced.
2408 * @ingroup hx509_cert
2411 const char *
2412 hx509_cert_get_friendly_name(hx509_cert cert)
2414 hx509_cert_attribute a;
2415 PKCS9_friendlyName n;
2416 size_t sz;
2417 int ret, i;
2419 if (cert->friendlyname)
2420 return cert->friendlyname;
2422 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
2423 if (a == NULL) {
2424 /* XXX use subject name ? */
2425 return NULL;
2428 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2429 if (ret)
2430 return NULL;
2432 if (n.len != 1) {
2433 free_PKCS9_friendlyName(&n);
2434 return NULL;
2437 cert->friendlyname = malloc(n.val[0].length + 1);
2438 if (cert->friendlyname == NULL) {
2439 free_PKCS9_friendlyName(&n);
2440 return NULL;
2443 for (i = 0; i < n.val[0].length; i++) {
2444 if (n.val[0].data[i] <= 0xff)
2445 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2446 else
2447 cert->friendlyname[i] = 'X';
2449 cert->friendlyname[i] = '\0';
2450 free_PKCS9_friendlyName(&n);
2452 return cert->friendlyname;
2455 void
2456 _hx509_query_clear(hx509_query *q)
2458 memset(q, 0, sizeof(*q));
2462 * Allocate an query controller. Free using hx509_query_free().
2464 * @param context A hx509 context.
2465 * @param q return pointer to a hx509_query.
2467 * @return An hx509 error code, see hx509_get_error_string().
2469 * @ingroup hx509_cert
2473 hx509_query_alloc(hx509_context context, hx509_query **q)
2475 *q = calloc(1, sizeof(**q));
2476 if (*q == NULL)
2477 return ENOMEM;
2478 return 0;
2482 * Set match options for the hx509 query controller.
2484 * @param q query controller.
2485 * @param option options to control the query controller.
2487 * @return An hx509 error code, see hx509_get_error_string().
2489 * @ingroup hx509_cert
2492 void
2493 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2495 switch(option) {
2496 case HX509_QUERY_OPTION_PRIVATE_KEY:
2497 q->match |= HX509_QUERY_PRIVATE_KEY;
2498 break;
2499 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2500 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2501 break;
2502 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2503 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2504 break;
2505 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2506 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2507 break;
2508 case HX509_QUERY_OPTION_END:
2509 default:
2510 break;
2515 * Set the issuer and serial number of match in the query
2516 * controller. The function make copies of the isser and serial number.
2518 * @param q a hx509 query controller
2519 * @param issuer issuer to search for
2520 * @param serialNumber the serialNumber of the issuer.
2522 * @return An hx509 error code, see hx509_get_error_string().
2524 * @ingroup hx509_cert
2528 hx509_query_match_issuer_serial(hx509_query *q,
2529 const Name *issuer,
2530 const heim_integer *serialNumber)
2532 int ret;
2533 if (q->serial) {
2534 der_free_heim_integer(q->serial);
2535 free(q->serial);
2537 q->serial = malloc(sizeof(*q->serial));
2538 if (q->serial == NULL)
2539 return ENOMEM;
2540 ret = der_copy_heim_integer(serialNumber, q->serial);
2541 if (ret) {
2542 free(q->serial);
2543 q->serial = NULL;
2544 return ret;
2546 if (q->issuer_name) {
2547 free_Name(q->issuer_name);
2548 free(q->issuer_name);
2550 q->issuer_name = malloc(sizeof(*q->issuer_name));
2551 if (q->issuer_name == NULL)
2552 return ENOMEM;
2553 ret = copy_Name(issuer, q->issuer_name);
2554 if (ret) {
2555 free(q->issuer_name);
2556 q->issuer_name = NULL;
2557 return ret;
2559 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2560 return 0;
2564 * Set the query controller to match on a friendly name
2566 * @param q a hx509 query controller.
2567 * @param name a friendly name to match on
2569 * @return An hx509 error code, see hx509_get_error_string().
2571 * @ingroup hx509_cert
2575 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2577 if (q->friendlyname)
2578 free(q->friendlyname);
2579 q->friendlyname = strdup(name);
2580 if (q->friendlyname == NULL)
2581 return ENOMEM;
2582 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2583 return 0;
2587 * Set the query controller to match using a specific match function.
2589 * @param q a hx509 query controller.
2590 * @param func function to use for matching, if the argument is NULL,
2591 * the match function is removed.
2592 * @param ctx context passed to the function.
2594 * @return An hx509 error code, see hx509_get_error_string().
2596 * @ingroup hx509_cert
2600 hx509_query_match_cmp_func(hx509_query *q,
2601 int (*func)(void *, hx509_cert),
2602 void *ctx)
2604 if (func)
2605 q->match |= HX509_QUERY_MATCH_FUNCTION;
2606 else
2607 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2608 q->cmp_func = func;
2609 q->cmp_func_ctx = ctx;
2610 return 0;
2614 * Free the query controller.
2616 * @param context A hx509 context.
2617 * @param q a pointer to the query controller.
2619 * @ingroup hx509_cert
2622 void
2623 hx509_query_free(hx509_context context, hx509_query *q)
2625 if (q->serial) {
2626 der_free_heim_integer(q->serial);
2627 free(q->serial);
2628 q->serial = NULL;
2630 if (q->issuer_name) {
2631 free_Name(q->issuer_name);
2632 free(q->issuer_name);
2633 q->issuer_name = NULL;
2635 if (q) {
2636 free(q->friendlyname);
2637 memset(q, 0, sizeof(*q));
2639 free(q);
2643 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2645 Certificate *c = _hx509_get_cert(cert);
2647 _hx509_query_statistic(context, 1, q);
2649 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2650 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2651 return 0;
2653 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2654 _hx509_Certificate_cmp(q->certificate, c) != 0)
2655 return 0;
2657 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2658 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2659 return 0;
2661 if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
2662 && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
2663 return 0;
2665 if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
2666 && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
2667 return 0;
2669 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2670 SubjectKeyIdentifier si;
2671 int ret;
2673 ret = _hx509_find_extension_subject_key_id(c, &si);
2674 if (ret == 0) {
2675 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2676 ret = 1;
2677 free_SubjectKeyIdentifier(&si);
2679 if (ret)
2680 return 0;
2682 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2683 return 0;
2684 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2685 _hx509_cert_private_key(cert) == NULL)
2686 return 0;
2689 unsigned ku = 0;
2690 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2691 ku |= (1 << 0);
2692 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2693 ku |= (1 << 1);
2694 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2695 ku |= (1 << 2);
2696 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2697 ku |= (1 << 3);
2698 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2699 ku |= (1 << 4);
2700 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2701 ku |= (1 << 5);
2702 if (q->match & HX509_QUERY_KU_CRLSIGN)
2703 ku |= (1 << 6);
2704 if (ku && check_key_usage(context, c, ku, TRUE))
2705 return 0;
2707 if ((q->match & HX509_QUERY_ANCHOR))
2708 return 0;
2710 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2711 hx509_cert_attribute a;
2713 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2714 if (a == NULL)
2715 return 0;
2716 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2717 return 0;
2720 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2721 size_t i;
2723 for (i = 0; i < q->path->len; i++)
2724 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2725 return 0;
2727 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2728 const char *name = hx509_cert_get_friendly_name(cert);
2729 if (name == NULL)
2730 return 0;
2731 if (strcasecmp(q->friendlyname, name) != 0)
2732 return 0;
2734 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2735 int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2736 if (ret != 0)
2737 return 0;
2740 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2741 heim_octet_string os;
2742 int ret;
2744 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2745 os.length =
2746 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2748 ret = _hx509_verify_signature(context,
2749 NULL,
2750 hx509_signature_sha1(),
2751 &os,
2752 q->keyhash_sha1);
2753 if (ret != 0)
2754 return 0;
2757 if (q->match & HX509_QUERY_MATCH_TIME) {
2758 time_t t;
2759 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2760 if (t > q->timenow)
2761 return 0;
2762 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2763 if (t < q->timenow)
2764 return 0;
2767 if (q->match & ~HX509_QUERY_MASK)
2768 return 0;
2770 return 1;
2774 * Set a statistic file for the query statistics.
2776 * @param context A hx509 context.
2777 * @param fn statistics file name
2779 * @ingroup hx509_cert
2782 void
2783 hx509_query_statistic_file(hx509_context context, const char *fn)
2785 if (context->querystat)
2786 free(context->querystat);
2787 context->querystat = strdup(fn);
2790 void
2791 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2793 FILE *f;
2794 if (context->querystat == NULL)
2795 return;
2796 f = fopen(context->querystat, "a");
2797 if (f == NULL)
2798 return;
2799 fprintf(f, "%d %d\n", type, q->match);
2800 fclose(f);
2803 static const char *statname[] = {
2804 "find issuer cert",
2805 "match serialnumber",
2806 "match issuer name",
2807 "match subject name",
2808 "match subject key id",
2809 "match issuer id",
2810 "private key",
2811 "ku encipherment",
2812 "ku digitalsignature",
2813 "ku keycertsign",
2814 "ku crlsign",
2815 "ku nonrepudiation",
2816 "ku keyagreement",
2817 "ku dataencipherment",
2818 "anchor",
2819 "match certificate",
2820 "match local key id",
2821 "no match path",
2822 "match friendly name",
2823 "match function",
2824 "match key hash sha1",
2825 "match time"
2828 struct stat_el {
2829 unsigned long stats;
2830 unsigned int index;
2834 static int
2835 stat_sort(const void *a, const void *b)
2837 const struct stat_el *ae = a;
2838 const struct stat_el *be = b;
2839 return be->stats - ae->stats;
2843 * Unparse the statistics file and print the result on a FILE descriptor.
2845 * @param context A hx509 context.
2846 * @param printtype tyep to print
2847 * @param out the FILE to write the data on.
2849 * @ingroup hx509_cert
2852 void
2853 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
2855 rtbl_t t;
2856 FILE *f;
2857 int type, mask, i, num;
2858 unsigned long multiqueries = 0, totalqueries = 0;
2859 struct stat_el stats[32];
2861 if (context->querystat == NULL)
2862 return;
2863 f = fopen(context->querystat, "r");
2864 if (f == NULL) {
2865 fprintf(out, "No statistic file %s: %s.\n",
2866 context->querystat, strerror(errno));
2867 return;
2870 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2871 stats[i].index = i;
2872 stats[i].stats = 0;
2875 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
2876 if (type != printtype)
2877 continue;
2878 num = i = 0;
2879 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
2880 if (mask & 1) {
2881 stats[i].stats++;
2882 num++;
2884 mask = mask >>1 ;
2885 i++;
2887 if (num > 1)
2888 multiqueries++;
2889 totalqueries++;
2891 fclose(f);
2893 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
2895 t = rtbl_create();
2896 if (t == NULL)
2897 errx(1, "out of memory");
2899 rtbl_set_separator (t, " ");
2901 rtbl_add_column_by_id (t, 0, "Name", 0);
2902 rtbl_add_column_by_id (t, 1, "Counter", 0);
2905 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2906 char str[10];
2908 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
2909 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
2910 else {
2911 snprintf(str, sizeof(str), "%d", stats[i].index);
2912 rtbl_add_column_entry_by_id (t, 0, str);
2914 snprintf(str, sizeof(str), "%lu", stats[i].stats);
2915 rtbl_add_column_entry_by_id (t, 1, str);
2918 rtbl_format(t, out);
2919 rtbl_destroy(t);
2921 fprintf(out, "\nQueries: multi %lu total %lu\n",
2922 multiqueries, totalqueries);
2926 * Check the extended key usage on the hx509 certificate.
2928 * @param context A hx509 context.
2929 * @param cert A hx509 context.
2930 * @param eku the EKU to check for
2931 * @param allow_any_eku if the any EKU is set, allow that to be a
2932 * substitute.
2934 * @return An hx509 error code, see hx509_get_error_string().
2936 * @ingroup hx509_cert
2940 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
2941 const heim_oid *eku, int allow_any_eku)
2943 ExtKeyUsage e;
2944 int ret, i;
2946 ret = find_extension_eku(_hx509_get_cert(cert), &e);
2947 if (ret) {
2948 hx509_clear_error_string(context);
2949 return ret;
2952 for (i = 0; i < e.len; i++) {
2953 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
2954 free_ExtKeyUsage(&e);
2955 return 0;
2957 if (allow_any_eku) {
2958 #if 0
2959 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
2960 free_ExtKeyUsage(&e);
2961 return 0;
2963 #endif
2966 free_ExtKeyUsage(&e);
2967 hx509_clear_error_string(context);
2968 return HX509_CERTIFICATE_MISSING_EKU;
2972 _hx509_cert_get_keyusage(hx509_context context,
2973 hx509_cert c,
2974 KeyUsage *ku)
2976 Certificate *cert;
2977 const Extension *e;
2978 size_t size;
2979 int ret, i = 0;
2981 memset(ku, 0, sizeof(*ku));
2983 cert = _hx509_get_cert(c);
2985 if (_hx509_cert_get_version(cert) < 3)
2986 return 0;
2988 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
2989 if (e == NULL)
2990 return HX509_KU_CERT_MISSING;
2992 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
2993 if (ret)
2994 return ret;
2995 return 0;
2999 _hx509_cert_get_eku(hx509_context context,
3000 hx509_cert cert,
3001 ExtKeyUsage *e)
3003 int ret;
3005 memset(e, 0, sizeof(*e));
3007 ret = find_extension_eku(_hx509_get_cert(cert), e);
3008 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3009 hx509_clear_error_string(context);
3010 return ret;
3012 return 0;
3016 * Encodes the hx509 certificate as a DER encode binary.
3018 * @param context A hx509 context.
3019 * @param c the certificate to encode.
3020 * @param os the encode certificate, set to NULL, 0 on case of error.
3022 * @return An hx509 error code, see hx509_get_error_string().
3024 * @ingroup hx509_cert
3028 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3030 size_t size;
3031 int ret;
3033 os->data = NULL;
3034 os->length = 0;
3036 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3037 _hx509_get_cert(c), &size, ret);
3038 if (ret) {
3039 os->data = NULL;
3040 os->length = 0;
3041 return ret;
3043 if (os->length != size)
3044 _hx509_abort("internal ASN.1 encoder error");
3046 return ret;
3050 * Last to avoid lost __attribute__s due to #undef.
3053 #undef __attribute__
3054 #define __attribute__(X)
3056 void
3057 _hx509_abort(const char *fmt, ...)
3058 __attribute__ ((noreturn, format (printf, 1, 2)))
3060 va_list ap;
3061 va_start(ap, fmt);
3062 vprintf(fmt, ap);
3063 va_end(ap);
3064 printf("\n");
3065 fflush(stdout);
3066 abort();