Use DES_set_key_unchecked().
[heimdal.git] / lib / hx509 / cert.c
blob370633f2a921f26bcc2224c1ee62e56a5df7da34
1 /*
2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "hx_locl.h"
35 RCSID("$Id$");
36 #include "crypto-headers.h"
37 #include <rtbl.h>
39 /**
40 * @page page_cert The basic certificate
42 * The basic hx509 cerificate object in hx509 is hx509_cert. The
43 * hx509_cert object is representing one X509/PKIX certificate and
44 * associated attributes; like private key, friendly name, etc.
46 * A hx509_cert object is usully found via the keyset interfaces (@ref
47 * page_keyset), but its also possible to create a certificate
48 * directly from a parsed object with hx509_cert_init() and
49 * hx509_cert_init_data().
51 * See the library functions here: @ref hx509_cert
54 struct hx509_verify_ctx_data {
55 hx509_certs trust_anchors;
56 int flags;
57 #define HX509_VERIFY_CTX_F_TIME_SET 1
58 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
59 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
60 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
61 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
62 time_t time_now;
63 unsigned int max_depth;
64 #define HX509_VERIFY_MAX_DEPTH 30
65 hx509_revoke_ctx revoke_ctx;
68 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
69 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
70 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
72 struct _hx509_cert_attrs {
73 size_t len;
74 hx509_cert_attribute *val;
77 struct hx509_cert_data {
78 unsigned int ref;
79 char *friendlyname;
80 Certificate *data;
81 hx509_private_key private_key;
82 struct _hx509_cert_attrs attrs;
83 hx509_name basename;
84 _hx509_cert_release_func release;
85 void *ctx;
88 typedef struct hx509_name_constraints {
89 NameConstraints *val;
90 size_t len;
91 } hx509_name_constraints;
93 #define GeneralSubtrees_SET(g,var) \
94 (g)->len = (var)->len, (g)->val = (var)->val;
96 /**
97 * Creates a hx509 context that most functions in the library
98 * uses. The context is only allowed to be used by one thread at each
99 * moment. Free the context with hx509_context_free().
101 * @param context Returns a pointer to new hx509 context.
103 * @return Returns an hx509 error code.
105 * @ingroup hx509
109 hx509_context_init(hx509_context *context)
111 *context = calloc(1, sizeof(**context));
112 if (*context == NULL)
113 return ENOMEM;
115 _hx509_ks_null_register(*context);
116 _hx509_ks_mem_register(*context);
117 _hx509_ks_file_register(*context);
118 _hx509_ks_pkcs12_register(*context);
119 _hx509_ks_pkcs11_register(*context);
120 _hx509_ks_dir_register(*context);
121 _hx509_ks_keychain_register(*context);
123 ENGINE_add_conf_module();
124 OpenSSL_add_all_algorithms();
126 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
128 initialize_hx_error_table_r(&(*context)->et_list);
129 initialize_asn1_error_table_r(&(*context)->et_list);
131 #ifdef HX509_DEFAULT_ANCHORS
132 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
133 NULL, &(*context)->default_trust_anchors);
134 #endif
136 return 0;
140 * Selects if the hx509_revoke_verify() function is going to require
141 * the existans of a revokation method (OSCP, CRL) or not. Note that
142 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
143 * call hx509_revoke_verify().
145 * @param context hx509 context to change the flag for.
146 * @param flag zero, revokation method required, non zero missing
147 * revokation method ok
149 * @ingroup hx509_verify
152 void
153 hx509_context_set_missing_revoke(hx509_context context, int flag)
155 if (flag)
156 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
157 else
158 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
162 * Free the context allocated by hx509_context_init().
164 * @param context context to be freed.
166 * @ingroup hx509
169 void
170 hx509_context_free(hx509_context *context)
172 hx509_clear_error_string(*context);
173 if ((*context)->ks_ops) {
174 free((*context)->ks_ops);
175 (*context)->ks_ops = NULL;
177 (*context)->ks_num_ops = 0;
178 free_error_table ((*context)->et_list);
179 if ((*context)->querystat)
180 free((*context)->querystat);
181 memset(*context, 0, sizeof(**context));
182 free(*context);
183 *context = NULL;
190 Certificate *
191 _hx509_get_cert(hx509_cert cert)
193 return cert->data;
201 _hx509_cert_get_version(const Certificate *t)
203 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
207 * Allocate and init an hx509 certificate object from the decoded
208 * certificate `c´.
210 * @param context A hx509 context.
211 * @param c
212 * @param cert
214 * @return Returns an hx509 error code.
216 * @ingroup hx509_cert
220 hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
222 int ret;
224 *cert = malloc(sizeof(**cert));
225 if (*cert == NULL)
226 return ENOMEM;
227 (*cert)->ref = 1;
228 (*cert)->friendlyname = NULL;
229 (*cert)->attrs.len = 0;
230 (*cert)->attrs.val = NULL;
231 (*cert)->private_key = NULL;
232 (*cert)->basename = NULL;
233 (*cert)->release = NULL;
234 (*cert)->ctx = NULL;
236 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
237 if ((*cert)->data == NULL) {
238 free(*cert);
239 return ENOMEM;
241 ret = copy_Certificate(c, (*cert)->data);
242 if (ret) {
243 free((*cert)->data);
244 free(*cert);
245 *cert = NULL;
247 return ret;
251 * Just like hx509_cert_init(), but instead of a decode certificate
252 * takes an pointer and length to a memory region that contains a
253 * DER/BER encoded certificate.
255 * If the memory region doesn't contain just the certificate and
256 * nothing more the function will fail with
257 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
259 * @param context A hx509 context.
260 * @param ptr pointer to memory region containing encoded certificate.
261 * @param len length of memory region.
262 * @param cert a return pointer to a hx509 certificate object, will
263 * contain NULL on error.
265 * @return An hx509 error code, see hx509_get_error_string().
267 * @ingroup hx509_cert
271 hx509_cert_init_data(hx509_context context,
272 const void *ptr,
273 size_t len,
274 hx509_cert *cert)
276 Certificate t;
277 size_t size;
278 int ret;
280 ret = decode_Certificate(ptr, len, &t, &size);
281 if (ret) {
282 hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
283 return ret;
285 if (size != len) {
286 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
287 "Extra data after certificate");
288 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
291 ret = hx509_cert_init(context, &t, cert);
292 free_Certificate(&t);
293 return ret;
296 void
297 _hx509_cert_set_release(hx509_cert cert,
298 _hx509_cert_release_func release,
299 void *ctx)
301 cert->release = release;
302 cert->ctx = ctx;
306 /* Doesn't make a copy of `private_key'. */
309 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
311 if (cert->private_key)
312 _hx509_private_key_free(&cert->private_key);
313 cert->private_key = _hx509_private_key_ref(private_key);
314 return 0;
318 * Free reference to the hx509 certificate object, if the refcounter
319 * reaches 0, the object if freed. Its allowed to pass in NULL.
321 * @param cert the cert to free.
323 * @ingroup hx509_cert
326 void
327 hx509_cert_free(hx509_cert cert)
329 int i;
331 if (cert == NULL)
332 return;
334 if (cert->ref <= 0)
335 _hx509_abort("cert refcount <= 0 on free");
336 if (--cert->ref > 0)
337 return;
339 if (cert->release)
340 (cert->release)(cert, cert->ctx);
342 if (cert->private_key)
343 _hx509_private_key_free(&cert->private_key);
345 free_Certificate(cert->data);
346 free(cert->data);
348 for (i = 0; i < cert->attrs.len; i++) {
349 der_free_octet_string(&cert->attrs.val[i]->data);
350 der_free_oid(&cert->attrs.val[i]->oid);
351 free(cert->attrs.val[i]);
353 free(cert->attrs.val);
354 free(cert->friendlyname);
355 if (cert->basename)
356 hx509_name_free(&cert->basename);
357 memset(cert, 0, sizeof(cert));
358 free(cert);
362 * Add a reference to a hx509 certificate object.
364 * @param cert a pointer to an hx509 certificate object.
366 * @return the same object as is passed in.
368 * @ingroup hx509_cert
371 hx509_cert
372 hx509_cert_ref(hx509_cert cert)
374 if (cert == NULL)
375 return NULL;
376 if (cert->ref <= 0)
377 _hx509_abort("cert refcount <= 0");
378 cert->ref++;
379 if (cert->ref == 0)
380 _hx509_abort("cert refcount == 0");
381 return cert;
385 * Allocate an verification context that is used fo control the
386 * verification process.
388 * @param context A hx509 context.
389 * @param ctx returns a pointer to a hx509_verify_ctx object.
391 * @return An hx509 error code, see hx509_get_error_string().
393 * @ingroup hx509_verify
397 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
399 hx509_verify_ctx c;
401 c = calloc(1, sizeof(*c));
402 if (c == NULL)
403 return ENOMEM;
405 c->max_depth = HX509_VERIFY_MAX_DEPTH;
407 *ctx = c;
409 return 0;
413 * Free an hx509 verification context.
415 * @param ctx the context to be freed.
417 * @ingroup hx509_verify
420 void
421 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
423 if (ctx) {
424 hx509_certs_free(&ctx->trust_anchors);
425 hx509_revoke_free(&ctx->revoke_ctx);
426 memset(ctx, 0, sizeof(*ctx));
428 free(ctx);
432 * Set the trust anchors in the verification context, makes an
433 * reference to the keyset, so the consumer can free the keyset
434 * independent of the destruction of the verification context (ctx).
436 * @param ctx a verification context
437 * @param set a keyset containing the trust anchors.
439 * @ingroup hx509_verify
442 void
443 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
445 ctx->trust_anchors = _hx509_certs_ref(set);
449 * Attach an revocation context to the verfication context, , makes an
450 * reference to the revoke context, so the consumer can free the
451 * revoke context independent of the destruction of the verification
452 * context. If there is no revoke context, the verification process is
453 * NOT going to check any verification status.
455 * @param ctx a verification context.
456 * @param revoke_ctx a revoke context.
458 * @ingroup hx509_verify
461 void
462 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
464 if (ctx->revoke_ctx)
465 hx509_revoke_free(&ctx->revoke_ctx);
466 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
470 * Set the clock time the the verification process is going to
471 * use. Used to check certificate in the past and future time. If not
472 * set the current time will be used.
474 * @param ctx a verification context.
475 * @param t the time the verifiation is using.
478 * @ingroup hx509_verify
481 void
482 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
484 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
485 ctx->time_now = t;
489 * Set the maximum depth of the certificate chain that the path
490 * builder is going to try.
492 * @param ctx a verification context
493 * @param max_depth maxium depth of the certificate chain, include
494 * trust anchor.
496 * @ingroup hx509_verify
499 void
500 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
502 ctx->max_depth = max_depth;
506 * Allow or deny the use of proxy certificates
508 * @param ctx a verification context
509 * @param boolean if non zero, allow proxy certificates.
511 * @ingroup hx509_verify
514 void
515 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
517 if (boolean)
518 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
519 else
520 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
524 * Select strict RFC3280 verification of certificiates. This means
525 * checking key usage on CA certificates, this will make version 1
526 * certificiates unuseable.
528 * @param ctx a verification context
529 * @param boolean if non zero, use strict verification.
531 * @ingroup hx509_verify
534 void
535 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
537 if (boolean)
538 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
539 else
540 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
544 * Allow using the operating system builtin trust anchors if no other
545 * trust anchors are configured.
547 * @param ctx a verification context
548 * @param boolean if non zero, useing the operating systems builtin
549 * trust anchors.
552 * @return An hx509 error code, see hx509_get_error_string().
554 * @ingroup hx509_cert
557 void
558 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
560 if (boolean)
561 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
562 else
563 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
566 static const Extension *
567 find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
569 const TBSCertificate *c = &cert->tbsCertificate;
571 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
572 return NULL;
574 for (;*idx < c->extensions->len; (*idx)++) {
575 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
576 return &c->extensions->val[(*idx)++];
578 return NULL;
581 static int
582 find_extension_auth_key_id(const Certificate *subject,
583 AuthorityKeyIdentifier *ai)
585 const Extension *e;
586 size_t size;
587 int i = 0;
589 memset(ai, 0, sizeof(*ai));
591 e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i);
592 if (e == NULL)
593 return HX509_EXTENSION_NOT_FOUND;
595 return decode_AuthorityKeyIdentifier(e->extnValue.data,
596 e->extnValue.length,
597 ai, &size);
601 _hx509_find_extension_subject_key_id(const Certificate *issuer,
602 SubjectKeyIdentifier *si)
604 const Extension *e;
605 size_t size;
606 int i = 0;
608 memset(si, 0, sizeof(*si));
610 e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i);
611 if (e == NULL)
612 return HX509_EXTENSION_NOT_FOUND;
614 return decode_SubjectKeyIdentifier(e->extnValue.data,
615 e->extnValue.length,
616 si, &size);
619 static int
620 find_extension_name_constraints(const Certificate *subject,
621 NameConstraints *nc)
623 const Extension *e;
624 size_t size;
625 int i = 0;
627 memset(nc, 0, sizeof(*nc));
629 e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i);
630 if (e == NULL)
631 return HX509_EXTENSION_NOT_FOUND;
633 return decode_NameConstraints(e->extnValue.data,
634 e->extnValue.length,
635 nc, &size);
638 static int
639 find_extension_subject_alt_name(const Certificate *cert, int *i,
640 GeneralNames *sa)
642 const Extension *e;
643 size_t size;
645 memset(sa, 0, sizeof(*sa));
647 e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i);
648 if (e == NULL)
649 return HX509_EXTENSION_NOT_FOUND;
651 return decode_GeneralNames(e->extnValue.data,
652 e->extnValue.length,
653 sa, &size);
656 static int
657 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
659 const Extension *e;
660 size_t size;
661 int i = 0;
663 memset(eku, 0, sizeof(*eku));
665 e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i);
666 if (e == NULL)
667 return HX509_EXTENSION_NOT_FOUND;
669 return decode_ExtKeyUsage(e->extnValue.data,
670 e->extnValue.length,
671 eku, &size);
674 static int
675 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
677 void *p;
678 int ret;
680 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
681 if (p == NULL)
682 return ENOMEM;
683 list->val = p;
684 ret = der_copy_octet_string(entry, &list->val[list->len]);
685 if (ret)
686 return ret;
687 list->len++;
688 return 0;
692 * Free a list of octet strings returned by another hx509 library
693 * function.
695 * @param list list to be freed.
697 * @ingroup hx509_misc
700 void
701 hx509_free_octet_string_list(hx509_octet_string_list *list)
703 int i;
704 for (i = 0; i < list->len; i++)
705 der_free_octet_string(&list->val[i]);
706 free(list->val);
707 list->val = NULL;
708 list->len = 0;
712 * Return a list of subjectAltNames specified by oid in the
713 * certificate. On error the
715 * The returned list of octet string should be freed with
716 * hx509_free_octet_string_list().
718 * @param context A hx509 context.
719 * @param cert a hx509 certificate object.
720 * @param oid an oid to for SubjectAltName.
721 * @param list list of matching SubjectAltName.
723 * @return An hx509 error code, see hx509_get_error_string().
725 * @ingroup hx509_cert
729 hx509_cert_find_subjectAltName_otherName(hx509_context context,
730 hx509_cert cert,
731 const heim_oid *oid,
732 hx509_octet_string_list *list)
734 GeneralNames sa;
735 int ret, i, j;
737 list->val = NULL;
738 list->len = 0;
740 i = 0;
741 while (1) {
742 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
743 i++;
744 if (ret == HX509_EXTENSION_NOT_FOUND) {
745 ret = 0;
746 break;
747 } else if (ret != 0) {
748 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
749 hx509_free_octet_string_list(list);
750 return ret;
753 for (j = 0; j < sa.len; j++) {
754 if (sa.val[j].element == choice_GeneralName_otherName &&
755 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
757 ret = add_to_list(list, &sa.val[j].u.otherName.value);
758 if (ret) {
759 hx509_set_error_string(context, 0, ret,
760 "Error adding an exra SAN to "
761 "return list");
762 hx509_free_octet_string_list(list);
763 free_GeneralNames(&sa);
764 return ret;
768 free_GeneralNames(&sa);
770 return 0;
774 static int
775 check_key_usage(hx509_context context, const Certificate *cert,
776 unsigned flags, int req_present)
778 const Extension *e;
779 KeyUsage ku;
780 size_t size;
781 int ret, i = 0;
782 unsigned ku_flags;
784 if (_hx509_cert_get_version(cert) < 3)
785 return 0;
787 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
788 if (e == NULL) {
789 if (req_present) {
790 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
791 "Required extension key "
792 "usage missing from certifiate");
793 return HX509_KU_CERT_MISSING;
795 return 0;
798 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
799 if (ret)
800 return ret;
801 ku_flags = KeyUsage2int(ku);
802 if ((ku_flags & flags) != flags) {
803 unsigned missing = (~ku_flags) & flags;
804 char buf[256], *name;
806 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
807 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
808 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
809 "Key usage %s required but missing "
810 "from certifiate %s", buf, name);
811 free(name);
812 return HX509_KU_CERT_MISSING;
814 return 0;
818 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
819 * an error code. If 'req_present' the existance is required of the
820 * KeyUsage extension.
824 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
825 unsigned flags, int req_present)
827 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
830 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
832 static int
833 check_basic_constraints(hx509_context context, const Certificate *cert,
834 enum certtype type, int depth)
836 BasicConstraints bc;
837 const Extension *e;
838 size_t size;
839 int ret, i = 0;
841 if (_hx509_cert_get_version(cert) < 3)
842 return 0;
844 e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i);
845 if (e == NULL) {
846 switch(type) {
847 case PROXY_CERT:
848 case EE_CERT:
849 return 0;
850 case CA_CERT: {
851 char *name;
852 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
853 assert(ret == 0);
854 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
855 "basicConstraints missing from "
856 "CA certifiacte %s", name);
857 free(name);
858 return HX509_EXTENSION_NOT_FOUND;
863 ret = decode_BasicConstraints(e->extnValue.data,
864 e->extnValue.length, &bc,
865 &size);
866 if (ret)
867 return ret;
868 switch(type) {
869 case PROXY_CERT:
870 if (bc.cA != NULL && *bc.cA)
871 ret = HX509_PARENT_IS_CA;
872 break;
873 case EE_CERT:
874 ret = 0;
875 break;
876 case CA_CERT:
877 if (bc.cA == NULL || !*bc.cA)
878 ret = HX509_PARENT_NOT_CA;
879 else if (bc.pathLenConstraint)
880 if (depth - 1 > *bc.pathLenConstraint)
881 ret = HX509_CA_PATH_TOO_DEEP;
882 break;
884 free_BasicConstraints(&bc);
885 return ret;
889 _hx509_cert_is_parent_cmp(const Certificate *subject,
890 const Certificate *issuer,
891 int allow_self_signed)
893 int diff;
894 AuthorityKeyIdentifier ai;
895 SubjectKeyIdentifier si;
896 int ret_ai, ret_si, ret;
898 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
899 &subject->tbsCertificate.issuer,
900 &diff);
901 if (ret)
902 return ret;
903 if (diff)
904 return diff;
906 memset(&ai, 0, sizeof(ai));
907 memset(&si, 0, sizeof(si));
910 * Try to find AuthorityKeyIdentifier, if it's not present in the
911 * subject certificate nor the parent.
914 ret_ai = find_extension_auth_key_id(subject, &ai);
915 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
916 return 1;
917 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
918 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
919 return -1;
921 if (ret_si && ret_ai)
922 goto out;
923 if (ret_ai)
924 goto out;
925 if (ret_si) {
926 if (allow_self_signed) {
927 diff = 0;
928 goto out;
929 } else if (ai.keyIdentifier) {
930 diff = -1;
931 goto out;
935 if (ai.keyIdentifier == NULL) {
936 Name name;
938 if (ai.authorityCertIssuer == NULL)
939 return -1;
940 if (ai.authorityCertSerialNumber == NULL)
941 return -1;
943 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
944 &issuer->tbsCertificate.serialNumber);
945 if (diff)
946 return diff;
947 if (ai.authorityCertIssuer->len != 1)
948 return -1;
949 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
950 return -1;
952 name.element =
953 ai.authorityCertIssuer->val[0].u.directoryName.element;
954 name.u.rdnSequence =
955 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
957 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
958 &name,
959 &diff);
960 if (ret)
961 return ret;
962 if (diff)
963 return diff;
964 diff = 0;
965 } else
966 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
967 if (diff)
968 goto out;
970 out:
971 free_AuthorityKeyIdentifier(&ai);
972 free_SubjectKeyIdentifier(&si);
973 return diff;
976 static int
977 certificate_is_anchor(hx509_context context,
978 hx509_certs trust_anchors,
979 const hx509_cert cert)
981 hx509_query q;
982 hx509_cert c;
983 int ret;
985 if (trust_anchors == NULL)
986 return 0;
988 _hx509_query_clear(&q);
990 q.match = HX509_QUERY_MATCH_CERTIFICATE;
991 q.certificate = _hx509_get_cert(cert);
993 ret = hx509_certs_find(context, trust_anchors, &q, &c);
994 if (ret == 0)
995 hx509_cert_free(c);
996 return ret == 0;
999 static int
1000 certificate_is_self_signed(hx509_context context,
1001 const Certificate *cert,
1002 int *self_signed)
1004 int ret, diff;
1005 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1006 &cert->tbsCertificate.issuer, &diff);
1007 *self_signed = (diff == 0);
1008 if (ret)
1009 hx509_set_error_string(context, 0, ret,
1010 "Failed to check if self signed");
1011 return ret;
1015 * The subjectName is "null" when it's empty set of relative DBs.
1018 static int
1019 subject_null_p(const Certificate *c)
1021 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1025 static int
1026 find_parent(hx509_context context,
1027 time_t time_now,
1028 hx509_certs trust_anchors,
1029 hx509_path *path,
1030 hx509_certs pool,
1031 hx509_cert current,
1032 hx509_cert *parent)
1034 AuthorityKeyIdentifier ai;
1035 hx509_query q;
1036 int ret;
1038 *parent = NULL;
1039 memset(&ai, 0, sizeof(ai));
1041 _hx509_query_clear(&q);
1043 if (!subject_null_p(current->data)) {
1044 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1045 q.subject = _hx509_get_cert(current);
1046 } else {
1047 ret = find_extension_auth_key_id(current->data, &ai);
1048 if (ret) {
1049 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1050 "Subjectless certificate missing AuthKeyID");
1051 return HX509_CERTIFICATE_MALFORMED;
1054 if (ai.keyIdentifier == NULL) {
1055 free_AuthorityKeyIdentifier(&ai);
1056 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1057 "Subjectless certificate missing keyIdentifier "
1058 "inside AuthKeyID");
1059 return HX509_CERTIFICATE_MALFORMED;
1062 q.subject_id = ai.keyIdentifier;
1063 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1066 q.path = path;
1067 q.match |= HX509_QUERY_NO_MATCH_PATH;
1069 if (pool) {
1070 q.timenow = time_now;
1071 q.match |= HX509_QUERY_MATCH_TIME;
1073 ret = hx509_certs_find(context, pool, &q, parent);
1074 if (ret == 0) {
1075 free_AuthorityKeyIdentifier(&ai);
1076 return 0;
1078 q.match &= ~HX509_QUERY_MATCH_TIME;
1081 if (trust_anchors) {
1082 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1083 if (ret == 0) {
1084 free_AuthorityKeyIdentifier(&ai);
1085 return ret;
1088 free_AuthorityKeyIdentifier(&ai);
1091 hx509_name name;
1092 char *str;
1094 ret = hx509_cert_get_subject(current, &name);
1095 if (ret) {
1096 hx509_clear_error_string(context);
1097 return HX509_ISSUER_NOT_FOUND;
1099 ret = hx509_name_to_string(name, &str);
1100 hx509_name_free(&name);
1101 if (ret) {
1102 hx509_clear_error_string(context);
1103 return HX509_ISSUER_NOT_FOUND;
1106 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1107 "Failed to find issuer for "
1108 "certificate with subject: '%s'", str);
1109 free(str);
1111 return HX509_ISSUER_NOT_FOUND;
1118 static int
1119 is_proxy_cert(hx509_context context,
1120 const Certificate *cert,
1121 ProxyCertInfo *rinfo)
1123 ProxyCertInfo info;
1124 const Extension *e;
1125 size_t size;
1126 int ret, i = 0;
1128 if (rinfo)
1129 memset(rinfo, 0, sizeof(*rinfo));
1131 e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i);
1132 if (e == NULL) {
1133 hx509_clear_error_string(context);
1134 return HX509_EXTENSION_NOT_FOUND;
1137 ret = decode_ProxyCertInfo(e->extnValue.data,
1138 e->extnValue.length,
1139 &info,
1140 &size);
1141 if (ret) {
1142 hx509_clear_error_string(context);
1143 return ret;
1145 if (size != e->extnValue.length) {
1146 free_ProxyCertInfo(&info);
1147 hx509_clear_error_string(context);
1148 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1150 if (rinfo == NULL)
1151 free_ProxyCertInfo(&info);
1152 else
1153 *rinfo = info;
1155 return 0;
1159 * Path operations are like MEMORY based keyset, but with exposed
1160 * internal so we can do easy searches.
1164 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1166 hx509_cert *val;
1167 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1168 if (val == NULL) {
1169 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1170 return ENOMEM;
1173 path->val = val;
1174 path->val[path->len] = hx509_cert_ref(cert);
1175 path->len++;
1177 return 0;
1180 void
1181 _hx509_path_free(hx509_path *path)
1183 unsigned i;
1185 for (i = 0; i < path->len; i++)
1186 hx509_cert_free(path->val[i]);
1187 free(path->val);
1188 path->val = NULL;
1189 path->len = 0;
1193 * Find path by looking up issuer for the top certificate and continue
1194 * until an anchor certificate is found or max limit is found. A
1195 * certificate never included twice in the path.
1197 * If the trust anchors are not given, calculate optimistic path, just
1198 * follow the chain upward until we no longer find a parent or we hit
1199 * the max path limit. In this case, a failure will always be returned
1200 * depending on what error condition is hit first.
1202 * The path includes a path from the top certificate to the anchor
1203 * certificate.
1205 * The caller needs to free `path´ both on successful built path and
1206 * failure.
1210 _hx509_calculate_path(hx509_context context,
1211 int flags,
1212 time_t time_now,
1213 hx509_certs anchors,
1214 unsigned int max_depth,
1215 hx509_cert cert,
1216 hx509_certs pool,
1217 hx509_path *path)
1219 hx509_cert parent, current;
1220 int ret;
1222 if (max_depth == 0)
1223 max_depth = HX509_VERIFY_MAX_DEPTH;
1225 ret = _hx509_path_append(context, path, cert);
1226 if (ret)
1227 return ret;
1229 current = hx509_cert_ref(cert);
1231 while (!certificate_is_anchor(context, anchors, current)) {
1233 ret = find_parent(context, time_now, anchors, path,
1234 pool, current, &parent);
1235 hx509_cert_free(current);
1236 if (ret)
1237 return ret;
1239 ret = _hx509_path_append(context, path, parent);
1240 if (ret)
1241 return ret;
1242 current = parent;
1244 if (path->len > max_depth) {
1245 hx509_cert_free(current);
1246 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1247 "Path too long while bulding "
1248 "certificate chain");
1249 return HX509_PATH_TOO_LONG;
1253 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1254 path->len > 0 &&
1255 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1257 hx509_cert_free(path->val[path->len - 1]);
1258 path->len--;
1261 hx509_cert_free(current);
1262 return 0;
1266 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1267 const AlgorithmIdentifier *q)
1269 int diff;
1270 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1271 if (diff)
1272 return diff;
1273 if (p->parameters) {
1274 if (q->parameters)
1275 return heim_any_cmp(p->parameters,
1276 q->parameters);
1277 else
1278 return 1;
1279 } else {
1280 if (q->parameters)
1281 return -1;
1282 else
1283 return 0;
1288 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1290 int diff;
1291 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1292 if (diff)
1293 return diff;
1294 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1295 &q->signatureAlgorithm);
1296 if (diff)
1297 return diff;
1298 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1299 &q->tbsCertificate._save);
1300 return diff;
1304 * Compare to hx509 certificate object, useful for sorting.
1306 * @param p a hx509 certificate object.
1307 * @param q a hx509 certificate object.
1309 * @return 0 the objects are the same, returns > 0 is p is "larger"
1310 * then q, < 0 if p is "smaller" then q.
1312 * @ingroup hx509_cert
1316 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1318 return _hx509_Certificate_cmp(p->data, q->data);
1322 * Return the name of the issuer of the hx509 certificate.
1324 * @param p a hx509 certificate object.
1325 * @param name a pointer to a hx509 name, should be freed by
1326 * hx509_name_free().
1328 * @return An hx509 error code, see hx509_get_error_string().
1330 * @ingroup hx509_cert
1334 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1336 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1340 * Return the name of the subject of the hx509 certificate.
1342 * @param p a hx509 certificate object.
1343 * @param name a pointer to a hx509 name, should be freed by
1344 * hx509_name_free(). See also hx509_cert_get_base_subject().
1346 * @return An hx509 error code, see hx509_get_error_string().
1348 * @ingroup hx509_cert
1352 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1354 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1358 * Return the name of the base subject of the hx509 certificate. If
1359 * the certiicate is a verified proxy certificate, the this function
1360 * return the base certificate (root of the proxy chain). If the proxy
1361 * certificate is not verified with the base certificate
1362 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1364 * @param context a hx509 context.
1365 * @param c a hx509 certificate object.
1366 * @param name a pointer to a hx509 name, should be freed by
1367 * hx509_name_free(). See also hx509_cert_get_subject().
1369 * @return An hx509 error code, see hx509_get_error_string().
1371 * @ingroup hx509_cert
1375 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1376 hx509_name *name)
1378 if (c->basename)
1379 return hx509_name_copy(context, c->basename, name);
1380 if (is_proxy_cert(context, c->data, NULL) == 0) {
1381 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1382 hx509_set_error_string(context, 0, ret,
1383 "Proxy certificate have not been "
1384 "canonicalize yet, no base name");
1385 return ret;
1387 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1391 * Get serial number of the certificate.
1393 * @param p a hx509 certificate object.
1394 * @param i serial number, should be freed ith der_free_heim_integer().
1396 * @return An hx509 error code, see hx509_get_error_string().
1398 * @ingroup hx509_cert
1402 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1404 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1408 * Get notBefore time of the certificate.
1410 * @param p a hx509 certificate object.
1412 * @return return not before time
1414 * @ingroup hx509_cert
1417 time_t
1418 hx509_cert_get_notBefore(hx509_cert p)
1420 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1424 * Get notAfter time of the certificate.
1426 * @param p a hx509 certificate object.
1428 * @return return not after time.
1430 * @ingroup hx509_cert
1433 time_t
1434 hx509_cert_get_notAfter(hx509_cert p)
1436 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1440 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1442 * @param context a hx509 context.
1443 * @param p a hx509 certificate object.
1444 * @param spki SubjectPublicKeyInfo, should be freed with
1445 * free_SubjectPublicKeyInfo().
1447 * @return An hx509 error code, see hx509_get_error_string().
1449 * @ingroup hx509_cert
1453 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1455 int ret;
1457 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1458 if (ret)
1459 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1460 return ret;
1464 * Get the AlgorithmIdentifier from the hx509 certificate.
1466 * @param context a hx509 context.
1467 * @param p a hx509 certificate object.
1468 * @param alg AlgorithmIdentifier, should be freed with
1469 * free_AlgorithmIdentifier().
1471 * @return An hx509 error code, see hx509_get_error_string().
1473 * @ingroup hx509_cert
1477 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1478 hx509_cert p,
1479 AlgorithmIdentifier *alg)
1481 int ret;
1483 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1484 if (ret)
1485 hx509_set_error_string(context, 0, ret,
1486 "Failed to copy SPKI AlgorithmIdentifier");
1487 return ret;
1491 hx509_private_key
1492 _hx509_cert_private_key(hx509_cert p)
1494 return p->private_key;
1498 hx509_cert_have_private_key(hx509_cert p)
1500 return p->private_key ? 1 : 0;
1505 _hx509_cert_private_key_exportable(hx509_cert p)
1507 if (p->private_key == NULL)
1508 return 0;
1509 return _hx509_private_key_exportable(p->private_key);
1513 _hx509_cert_private_decrypt(hx509_context context,
1514 const heim_octet_string *ciphertext,
1515 const heim_oid *encryption_oid,
1516 hx509_cert p,
1517 heim_octet_string *cleartext)
1519 cleartext->data = NULL;
1520 cleartext->length = 0;
1522 if (p->private_key == NULL) {
1523 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1524 "Private key missing");
1525 return HX509_PRIVATE_KEY_MISSING;
1528 return _hx509_private_key_private_decrypt(context,
1529 ciphertext,
1530 encryption_oid,
1531 p->private_key,
1532 cleartext);
1536 _hx509_cert_public_encrypt(hx509_context context,
1537 const heim_octet_string *cleartext,
1538 const hx509_cert p,
1539 heim_oid *encryption_oid,
1540 heim_octet_string *ciphertext)
1542 return _hx509_public_encrypt(context,
1543 cleartext, p->data,
1544 encryption_oid, ciphertext);
1551 time_t
1552 _hx509_Time2time_t(const Time *t)
1554 switch(t->element) {
1555 case choice_Time_utcTime:
1556 return t->u.utcTime;
1557 case choice_Time_generalTime:
1558 return t->u.generalTime;
1560 return 0;
1567 static int
1568 init_name_constraints(hx509_name_constraints *nc)
1570 memset(nc, 0, sizeof(*nc));
1571 return 0;
1574 static int
1575 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1576 hx509_name_constraints *nc)
1578 NameConstraints tnc;
1579 int ret;
1581 ret = find_extension_name_constraints(c, &tnc);
1582 if (ret == HX509_EXTENSION_NOT_FOUND)
1583 return 0;
1584 else if (ret) {
1585 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1586 return ret;
1587 } else if (not_ca) {
1588 ret = HX509_VERIFY_CONSTRAINTS;
1589 hx509_set_error_string(context, 0, ret, "Not a CA and "
1590 "have NameConstraints");
1591 } else {
1592 NameConstraints *val;
1593 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1594 if (val == NULL) {
1595 hx509_clear_error_string(context);
1596 ret = ENOMEM;
1597 goto out;
1599 nc->val = val;
1600 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1601 if (ret) {
1602 hx509_clear_error_string(context);
1603 goto out;
1605 nc->len += 1;
1607 out:
1608 free_NameConstraints(&tnc);
1609 return ret;
1612 static int
1613 match_RDN(const RelativeDistinguishedName *c,
1614 const RelativeDistinguishedName *n)
1616 int i;
1618 if (c->len != n->len)
1619 return HX509_NAME_CONSTRAINT_ERROR;
1621 for (i = 0; i < n->len; i++) {
1622 int diff, ret;
1624 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1625 return HX509_NAME_CONSTRAINT_ERROR;
1626 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1627 if (ret)
1628 return ret;
1629 if (diff != 0)
1630 return HX509_NAME_CONSTRAINT_ERROR;
1632 return 0;
1635 static int
1636 match_X501Name(const Name *c, const Name *n)
1638 int i, ret;
1640 if (c->element != choice_Name_rdnSequence
1641 || n->element != choice_Name_rdnSequence)
1642 return 0;
1643 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1644 return HX509_NAME_CONSTRAINT_ERROR;
1645 for (i = 0; i < c->u.rdnSequence.len; i++) {
1646 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1647 if (ret)
1648 return ret;
1650 return 0;
1654 static int
1655 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1658 * Name constraints only apply to the same name type, see RFC3280,
1659 * 4.2.1.11.
1661 assert(c->element == n->element);
1663 switch(c->element) {
1664 case choice_GeneralName_otherName:
1665 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1666 &n->u.otherName.type_id) != 0)
1667 return HX509_NAME_CONSTRAINT_ERROR;
1668 if (heim_any_cmp(&c->u.otherName.value,
1669 &n->u.otherName.value) != 0)
1670 return HX509_NAME_CONSTRAINT_ERROR;
1671 *match = 1;
1672 return 0;
1673 case choice_GeneralName_rfc822Name: {
1674 const char *s;
1675 size_t len1, len2;
1676 s = strchr(c->u.rfc822Name, '@');
1677 if (s) {
1678 if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1679 return HX509_NAME_CONSTRAINT_ERROR;
1680 } else {
1681 s = strchr(n->u.rfc822Name, '@');
1682 if (s == NULL)
1683 return HX509_NAME_CONSTRAINT_ERROR;
1684 len1 = strlen(c->u.rfc822Name);
1685 len2 = strlen(s + 1);
1686 if (len1 > len2)
1687 return HX509_NAME_CONSTRAINT_ERROR;
1688 if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1689 return HX509_NAME_CONSTRAINT_ERROR;
1690 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1691 return HX509_NAME_CONSTRAINT_ERROR;
1693 *match = 1;
1694 return 0;
1696 case choice_GeneralName_dNSName: {
1697 size_t lenc, lenn;
1699 lenc = strlen(c->u.dNSName);
1700 lenn = strlen(n->u.dNSName);
1701 if (lenc > lenn)
1702 return HX509_NAME_CONSTRAINT_ERROR;
1703 if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1704 return HX509_NAME_CONSTRAINT_ERROR;
1705 if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1706 return HX509_NAME_CONSTRAINT_ERROR;
1707 *match = 1;
1708 return 0;
1710 case choice_GeneralName_directoryName: {
1711 Name c_name, n_name;
1712 int ret;
1714 c_name._save.data = NULL;
1715 c_name._save.length = 0;
1716 c_name.element = c->u.directoryName.element;
1717 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1719 n_name._save.data = NULL;
1720 n_name._save.length = 0;
1721 n_name.element = n->u.directoryName.element;
1722 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1724 ret = match_X501Name(&c_name, &n_name);
1725 if (ret == 0)
1726 *match = 1;
1727 return ret;
1729 case choice_GeneralName_uniformResourceIdentifier:
1730 case choice_GeneralName_iPAddress:
1731 case choice_GeneralName_registeredID:
1732 default:
1733 return HX509_NAME_CONSTRAINT_ERROR;
1737 static int
1738 match_alt_name(const GeneralName *n, const Certificate *c,
1739 int *same, int *match)
1741 GeneralNames sa;
1742 int ret, i, j;
1744 i = 0;
1745 do {
1746 ret = find_extension_subject_alt_name(c, &i, &sa);
1747 if (ret == HX509_EXTENSION_NOT_FOUND) {
1748 ret = 0;
1749 break;
1750 } else if (ret != 0)
1751 break;
1753 for (j = 0; j < sa.len; j++) {
1754 if (n->element == sa.val[j].element) {
1755 *same = 1;
1756 ret = match_general_name(n, &sa.val[j], match);
1759 free_GeneralNames(&sa);
1760 } while (1);
1761 return ret;
1765 static int
1766 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1768 int name, alt_name, same;
1769 unsigned int i;
1770 int ret = 0;
1772 name = alt_name = same = *match = 0;
1773 for (i = 0; i < t->len; i++) {
1774 if (t->val[i].minimum && t->val[i].maximum)
1775 return HX509_RANGE;
1778 * If the constraint apply to directoryNames, test is with
1779 * subjectName of the certificate if the certificate have a
1780 * non-null (empty) subjectName.
1783 if (t->val[i].base.element == choice_GeneralName_directoryName
1784 && !subject_null_p(c))
1786 GeneralName certname;
1788 memset(&certname, 0, sizeof(certname));
1789 certname.element = choice_GeneralName_directoryName;
1790 certname.u.directoryName.element =
1791 c->tbsCertificate.subject.element;
1792 certname.u.directoryName.u.rdnSequence =
1793 c->tbsCertificate.subject.u.rdnSequence;
1795 ret = match_general_name(&t->val[i].base, &certname, &name);
1798 /* Handle subjectAltNames, this is icky since they
1799 * restrictions only apply if the subjectAltName is of the
1800 * same type. So if there have been a match of type, require
1801 * altname to be set.
1803 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1805 if (name && (!same || alt_name))
1806 *match = 1;
1807 return ret;
1810 static int
1811 check_name_constraints(hx509_context context,
1812 const hx509_name_constraints *nc,
1813 const Certificate *c)
1815 int match, ret;
1816 int i;
1818 for (i = 0 ; i < nc->len; i++) {
1819 GeneralSubtrees gs;
1821 if (nc->val[i].permittedSubtrees) {
1822 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1823 ret = match_tree(&gs, c, &match);
1824 if (ret) {
1825 hx509_clear_error_string(context);
1826 return ret;
1828 /* allow null subjectNames, they wont matches anything */
1829 if (match == 0 && !subject_null_p(c)) {
1830 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1831 "Error verify constraints, "
1832 "certificate didn't match any "
1833 "permitted subtree");
1834 return HX509_VERIFY_CONSTRAINTS;
1837 if (nc->val[i].excludedSubtrees) {
1838 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1839 ret = match_tree(&gs, c, &match);
1840 if (ret) {
1841 hx509_clear_error_string(context);
1842 return ret;
1844 if (match) {
1845 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1846 "Error verify constraints, "
1847 "certificate included in excluded "
1848 "subtree");
1849 return HX509_VERIFY_CONSTRAINTS;
1853 return 0;
1856 static void
1857 free_name_constraints(hx509_name_constraints *nc)
1859 int i;
1861 for (i = 0 ; i < nc->len; i++)
1862 free_NameConstraints(&nc->val[i]);
1863 free(nc->val);
1867 * Build and verify the path for the certificate to the trust anchor
1868 * specified in the verify context. The path is constructed from the
1869 * certificate, the pool and the trust anchors.
1871 * @param context A hx509 context.
1872 * @param ctx A hx509 verification context.
1873 * @param cert the certificate to build the path from.
1874 * @param pool A keyset of certificates to build the chain from.
1876 * @return An hx509 error code, see hx509_get_error_string().
1878 * @ingroup hx509_verify
1882 hx509_verify_path(hx509_context context,
1883 hx509_verify_ctx ctx,
1884 hx509_cert cert,
1885 hx509_certs pool)
1887 hx509_name_constraints nc;
1888 hx509_path path;
1889 int ret, i, proxy_cert_depth, selfsigned_depth, diff;
1890 enum certtype type;
1891 Name proxy_issuer;
1892 hx509_certs anchors = NULL;
1894 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1896 ret = init_name_constraints(&nc);
1897 if (ret)
1898 return ret;
1900 path.val = NULL;
1901 path.len = 0;
1903 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1904 ctx->time_now = time(NULL);
1909 if (ctx->trust_anchors)
1910 anchors = _hx509_certs_ref(ctx->trust_anchors);
1911 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1912 anchors = _hx509_certs_ref(context->default_trust_anchors);
1913 else {
1914 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1915 if (ret)
1916 goto out;
1920 * Calculate the path from the certificate user presented to the
1921 * to an anchor.
1923 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1924 anchors, ctx->max_depth,
1925 cert, pool, &path);
1926 if (ret)
1927 goto out;
1930 * Check CA and proxy certificate chain from the top of the
1931 * certificate chain. Also check certificate is valid with respect
1932 * to the current time.
1936 proxy_cert_depth = 0;
1937 selfsigned_depth = 0;
1939 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1940 type = PROXY_CERT;
1941 else
1942 type = EE_CERT;
1944 for (i = 0; i < path.len; i++) {
1945 Certificate *c;
1946 time_t t;
1948 c = _hx509_get_cert(path.val[i]);
1951 * Lets do some basic check on issuer like
1952 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1953 * on what type of certificate this is.
1956 switch (type) {
1957 case CA_CERT:
1959 /* XXX make constants for keyusage */
1960 ret = check_key_usage(context, c, 1 << 5,
1961 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1962 if (ret) {
1963 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1964 "Key usage missing from CA certificate");
1965 goto out;
1968 /* self signed cert doesn't add to path length */
1969 if (i + 1 != path.len) {
1970 int selfsigned;
1972 ret = certificate_is_self_signed(context, c, &selfsigned);
1973 if (ret)
1974 goto out;
1975 if (selfsigned)
1976 selfsigned_depth++;
1979 break;
1980 case PROXY_CERT: {
1981 ProxyCertInfo info;
1983 if (is_proxy_cert(context, c, &info) == 0) {
1984 int j;
1986 if (info.pCPathLenConstraint != NULL &&
1987 *info.pCPathLenConstraint < i)
1989 free_ProxyCertInfo(&info);
1990 ret = HX509_PATH_TOO_LONG;
1991 hx509_set_error_string(context, 0, ret,
1992 "Proxy certificate chain "
1993 "longer then allowed");
1994 goto out;
1996 /* XXX MUST check info.proxyPolicy */
1997 free_ProxyCertInfo(&info);
1999 j = 0;
2000 if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
2001 ret = HX509_PROXY_CERT_INVALID;
2002 hx509_set_error_string(context, 0, ret,
2003 "Proxy certificate have explicity "
2004 "forbidden subjectAltName");
2005 goto out;
2008 j = 0;
2009 if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
2010 ret = HX509_PROXY_CERT_INVALID;
2011 hx509_set_error_string(context, 0, ret,
2012 "Proxy certificate have explicity "
2013 "forbidden issuerAltName");
2014 goto out;
2018 * The subject name of the proxy certificate should be
2019 * CN=XXX,<proxy issuer>, prune of CN and check if its
2020 * the same over the whole chain of proxy certs and
2021 * then check with the EE cert when we get to it.
2024 if (proxy_cert_depth) {
2025 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2026 if (ret) {
2027 hx509_set_error_string(context, 0, ret, "Out of memory");
2028 goto out;
2030 if (diff) {
2031 ret = HX509_PROXY_CERT_NAME_WRONG;
2032 hx509_set_error_string(context, 0, ret,
2033 "Base proxy name not right");
2034 goto out;
2038 free_Name(&proxy_issuer);
2040 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2041 if (ret) {
2042 hx509_clear_error_string(context);
2043 goto out;
2046 j = proxy_issuer.u.rdnSequence.len;
2047 if (proxy_issuer.u.rdnSequence.len < 2
2048 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2049 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2050 oid_id_at_commonName()))
2052 ret = HX509_PROXY_CERT_NAME_WRONG;
2053 hx509_set_error_string(context, 0, ret,
2054 "Proxy name too short or "
2055 "does not have Common name "
2056 "at the top");
2057 goto out;
2060 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2061 proxy_issuer.u.rdnSequence.len -= 1;
2063 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2064 if (ret) {
2065 hx509_set_error_string(context, 0, ret, "Out of memory");
2066 goto out;
2068 if (diff != 0) {
2069 ret = HX509_PROXY_CERT_NAME_WRONG;
2070 hx509_set_error_string(context, 0, ret,
2071 "Proxy issuer name not as expected");
2072 goto out;
2075 break;
2076 } else {
2078 * Now we are done with the proxy certificates, this
2079 * cert was an EE cert and we we will fall though to
2080 * EE checking below.
2082 type = EE_CERT;
2083 /* FALLTHOUGH */
2086 case EE_CERT:
2088 * If there where any proxy certificates in the chain
2089 * (proxy_cert_depth > 0), check that the proxy issuer
2090 * matched proxy certificates "base" subject.
2092 if (proxy_cert_depth) {
2094 ret = _hx509_name_cmp(&proxy_issuer,
2095 &c->tbsCertificate.subject, &diff);
2096 if (ret) {
2097 hx509_set_error_string(context, 0, ret, "out of memory");
2098 goto out;
2100 if (diff) {
2101 ret = HX509_PROXY_CERT_NAME_WRONG;
2102 hx509_clear_error_string(context);
2103 goto out;
2105 if (cert->basename)
2106 hx509_name_free(&cert->basename);
2108 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2109 if (ret) {
2110 hx509_clear_error_string(context);
2111 goto out;
2115 break;
2118 ret = check_basic_constraints(context, c, type,
2119 i - proxy_cert_depth - selfsigned_depth);
2120 if (ret)
2121 goto out;
2124 * Don't check the trust anchors expiration time since they
2125 * are transported out of band, from RFC3820.
2127 if (i + 1 != path.len || CHECK_TA(ctx)) {
2129 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2130 if (t > ctx->time_now) {
2131 ret = HX509_CERT_USED_BEFORE_TIME;
2132 hx509_clear_error_string(context);
2133 goto out;
2135 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2136 if (t < ctx->time_now) {
2137 ret = HX509_CERT_USED_AFTER_TIME;
2138 hx509_clear_error_string(context);
2139 goto out;
2143 if (type == EE_CERT)
2144 type = CA_CERT;
2145 else if (type == PROXY_CERT)
2146 proxy_cert_depth++;
2150 * Verify constraints, do this backward so path constraints are
2151 * checked in the right order.
2154 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2155 Certificate *c;
2156 int selfsigned;
2158 c = _hx509_get_cert(path.val[i]);
2160 ret = certificate_is_self_signed(context, c, &selfsigned);
2161 if (ret)
2162 goto out;
2164 /* verify name constraints, not for selfsigned and anchor */
2165 if (!selfsigned || i + 1 != path.len) {
2166 ret = check_name_constraints(context, &nc, c);
2167 if (ret) {
2168 goto out;
2171 ret = add_name_constraints(context, c, i == 0, &nc);
2172 if (ret)
2173 goto out;
2175 /* XXX verify all other silly constraints */
2180 * Verify that no certificates has been revoked.
2183 if (ctx->revoke_ctx) {
2184 hx509_certs certs;
2186 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2187 NULL, &certs);
2188 if (ret)
2189 goto out;
2191 for (i = 0; i < path.len; i++) {
2192 ret = hx509_certs_add(context, certs, path.val[i]);
2193 if (ret) {
2194 hx509_certs_free(&certs);
2195 goto out;
2198 ret = hx509_certs_merge(context, certs, pool);
2199 if (ret) {
2200 hx509_certs_free(&certs);
2201 goto out;
2204 for (i = 0; i < path.len - 1; i++) {
2205 int parent = (i < path.len - 1) ? i + 1 : i;
2207 ret = hx509_revoke_verify(context,
2208 ctx->revoke_ctx,
2209 certs,
2210 ctx->time_now,
2211 path.val[i],
2212 path.val[parent]);
2213 if (ret) {
2214 hx509_certs_free(&certs);
2215 goto out;
2218 hx509_certs_free(&certs);
2222 * Verify signatures, do this backward so public key working
2223 * parameter is passed up from the anchor up though the chain.
2226 for (i = path.len - 1; i >= 0; i--) {
2227 Certificate *signer, *c;
2229 c = _hx509_get_cert(path.val[i]);
2231 /* is last in chain (trust anchor) */
2232 if (i + 1 == path.len) {
2233 int selfsigned;
2235 signer = path.val[i]->data;
2237 ret = certificate_is_self_signed(context, signer, &selfsigned);
2238 if (ret)
2239 goto out;
2241 /* if trust anchor is not self signed, don't check sig */
2242 if (!selfsigned)
2243 continue;
2244 } else {
2245 /* take next certificate in chain */
2246 signer = path.val[i + 1]->data;
2249 /* verify signatureValue */
2250 ret = _hx509_verify_signature_bitstring(context,
2251 signer,
2252 &c->signatureAlgorithm,
2253 &c->tbsCertificate._save,
2254 &c->signatureValue);
2255 if (ret) {
2256 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2257 "Failed to verify signature of certificate");
2258 goto out;
2262 out:
2263 hx509_certs_free(&anchors);
2264 free_Name(&proxy_issuer);
2265 free_name_constraints(&nc);
2266 _hx509_path_free(&path);
2268 return ret;
2272 * Verify a signature made using the private key of an certificate.
2274 * @param context A hx509 context.
2275 * @param signer the certificate that made the signature.
2276 * @param alg algorthm that was used to sign the data.
2277 * @param data the data that was signed.
2278 * @param sig the sigature to verify.
2280 * @return An hx509 error code, see hx509_get_error_string().
2282 * @ingroup hx509_crypto
2286 hx509_verify_signature(hx509_context context,
2287 const hx509_cert signer,
2288 const AlgorithmIdentifier *alg,
2289 const heim_octet_string *data,
2290 const heim_octet_string *sig)
2292 return _hx509_verify_signature(context, signer->data, alg, data, sig);
2297 * Verify that the certificate is allowed to be used for the hostname
2298 * and address.
2300 * @param context A hx509 context.
2301 * @param cert the certificate to match with
2302 * @param flags Flags to modify the behavior:
2303 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2304 * @param type type of hostname:
2305 * - HX509_HN_HOSTNAME for plain hostname.
2306 * - HX509_HN_DNSSRV for DNS SRV names.
2307 * @param hostname the hostname to check
2308 * @param sa address of the host
2309 * @param sa_size length of address
2311 * @return An hx509 error code, see hx509_get_error_string().
2313 * @ingroup hx509_cert
2317 hx509_verify_hostname(hx509_context context,
2318 const hx509_cert cert,
2319 int flags,
2320 hx509_hostname_type type,
2321 const char *hostname,
2322 const struct sockaddr *sa,
2323 /* XXX krb5_socklen_t */ int sa_size)
2325 GeneralNames san;
2326 int ret, i, j;
2328 if (sa && sa_size <= 0)
2329 return EINVAL;
2331 memset(&san, 0, sizeof(san));
2333 i = 0;
2334 do {
2335 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2336 if (ret == HX509_EXTENSION_NOT_FOUND) {
2337 ret = 0;
2338 break;
2339 } else if (ret != 0)
2340 break;
2342 for (j = 0; j < san.len; j++) {
2343 switch (san.val[j].element) {
2344 case choice_GeneralName_dNSName:
2345 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2346 free_GeneralNames(&san);
2347 return 0;
2349 break;
2350 default:
2351 break;
2354 free_GeneralNames(&san);
2355 } while (1);
2358 const Name *name = &cert->data->tbsCertificate.subject;
2360 /* match if first component is a CN= */
2361 if (name->u.rdnSequence.len > 0
2362 && name->u.rdnSequence.val[0].len == 1
2363 && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
2364 oid_id_at_commonName()) == 0)
2366 DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
2368 switch (ds->element) {
2369 case choice_DirectoryString_printableString:
2370 if (strcasecmp(ds->u.printableString, hostname) == 0)
2371 return 0;
2372 break;
2373 case choice_DirectoryString_ia5String:
2374 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2375 return 0;
2376 break;
2377 case choice_DirectoryString_utf8String:
2378 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2379 return 0;
2380 default:
2381 break;
2386 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2387 ret = HX509_NAME_CONSTRAINT_ERROR;
2389 return ret;
2393 _hx509_set_cert_attribute(hx509_context context,
2394 hx509_cert cert,
2395 const heim_oid *oid,
2396 const heim_octet_string *attr)
2398 hx509_cert_attribute a;
2399 void *d;
2401 if (hx509_cert_get_attribute(cert, oid) != NULL)
2402 return 0;
2404 d = realloc(cert->attrs.val,
2405 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2406 if (d == NULL) {
2407 hx509_clear_error_string(context);
2408 return ENOMEM;
2410 cert->attrs.val = d;
2412 a = malloc(sizeof(*a));
2413 if (a == NULL)
2414 return ENOMEM;
2416 der_copy_octet_string(attr, &a->data);
2417 der_copy_oid(oid, &a->oid);
2419 cert->attrs.val[cert->attrs.len] = a;
2420 cert->attrs.len++;
2422 return 0;
2426 * Get an external attribute for the certificate, examples are
2427 * friendly name and id.
2429 * @param cert hx509 certificate object to search
2430 * @param oid an oid to search for.
2432 * @return an hx509_cert_attribute, only valid as long as the
2433 * certificate is referenced.
2435 * @ingroup hx509_cert
2438 hx509_cert_attribute
2439 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2441 int i;
2442 for (i = 0; i < cert->attrs.len; i++)
2443 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2444 return cert->attrs.val[i];
2445 return NULL;
2449 * Set the friendly name on the certificate.
2451 * @param cert The certificate to set the friendly name on
2452 * @param name Friendly name.
2454 * @return An hx509 error code, see hx509_get_error_string().
2456 * @ingroup hx509_cert
2460 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2462 if (cert->friendlyname)
2463 free(cert->friendlyname);
2464 cert->friendlyname = strdup(name);
2465 if (cert->friendlyname == NULL)
2466 return ENOMEM;
2467 return 0;
2471 * Get friendly name of the certificate.
2473 * @param cert cert to get the friendly name from.
2475 * @return an friendly name or NULL if there is. The friendly name is
2476 * only valid as long as the certificate is referenced.
2478 * @ingroup hx509_cert
2481 const char *
2482 hx509_cert_get_friendly_name(hx509_cert cert)
2484 hx509_cert_attribute a;
2485 PKCS9_friendlyName n;
2486 size_t sz;
2487 int ret, i;
2489 if (cert->friendlyname)
2490 return cert->friendlyname;
2492 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
2493 if (a == NULL) {
2494 hx509_name name;
2496 ret = hx509_cert_get_subject(cert, &name);
2497 if (ret)
2498 return NULL;
2499 ret = hx509_name_to_string(name, &cert->friendlyname);
2500 hx509_name_free(&name);
2501 if (ret)
2502 return NULL;
2503 return cert->friendlyname;
2506 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2507 if (ret)
2508 return NULL;
2510 if (n.len != 1) {
2511 free_PKCS9_friendlyName(&n);
2512 return NULL;
2515 cert->friendlyname = malloc(n.val[0].length + 1);
2516 if (cert->friendlyname == NULL) {
2517 free_PKCS9_friendlyName(&n);
2518 return NULL;
2521 for (i = 0; i < n.val[0].length; i++) {
2522 if (n.val[0].data[i] <= 0xff)
2523 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2524 else
2525 cert->friendlyname[i] = 'X';
2527 cert->friendlyname[i] = '\0';
2528 free_PKCS9_friendlyName(&n);
2530 return cert->friendlyname;
2533 void
2534 _hx509_query_clear(hx509_query *q)
2536 memset(q, 0, sizeof(*q));
2540 * Allocate an query controller. Free using hx509_query_free().
2542 * @param context A hx509 context.
2543 * @param q return pointer to a hx509_query.
2545 * @return An hx509 error code, see hx509_get_error_string().
2547 * @ingroup hx509_cert
2551 hx509_query_alloc(hx509_context context, hx509_query **q)
2553 *q = calloc(1, sizeof(**q));
2554 if (*q == NULL)
2555 return ENOMEM;
2556 return 0;
2561 * Set match options for the hx509 query controller.
2563 * @param q query controller.
2564 * @param option options to control the query controller.
2566 * @return An hx509 error code, see hx509_get_error_string().
2568 * @ingroup hx509_cert
2571 void
2572 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2574 switch(option) {
2575 case HX509_QUERY_OPTION_PRIVATE_KEY:
2576 q->match |= HX509_QUERY_PRIVATE_KEY;
2577 break;
2578 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2579 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2580 break;
2581 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2582 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2583 break;
2584 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2585 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2586 break;
2587 case HX509_QUERY_OPTION_END:
2588 default:
2589 break;
2594 * Set the issuer and serial number of match in the query
2595 * controller. The function make copies of the isser and serial number.
2597 * @param q a hx509 query controller
2598 * @param issuer issuer to search for
2599 * @param serialNumber the serialNumber of the issuer.
2601 * @return An hx509 error code, see hx509_get_error_string().
2603 * @ingroup hx509_cert
2607 hx509_query_match_issuer_serial(hx509_query *q,
2608 const Name *issuer,
2609 const heim_integer *serialNumber)
2611 int ret;
2612 if (q->serial) {
2613 der_free_heim_integer(q->serial);
2614 free(q->serial);
2616 q->serial = malloc(sizeof(*q->serial));
2617 if (q->serial == NULL)
2618 return ENOMEM;
2619 ret = der_copy_heim_integer(serialNumber, q->serial);
2620 if (ret) {
2621 free(q->serial);
2622 q->serial = NULL;
2623 return ret;
2625 if (q->issuer_name) {
2626 free_Name(q->issuer_name);
2627 free(q->issuer_name);
2629 q->issuer_name = malloc(sizeof(*q->issuer_name));
2630 if (q->issuer_name == NULL)
2631 return ENOMEM;
2632 ret = copy_Name(issuer, q->issuer_name);
2633 if (ret) {
2634 free(q->issuer_name);
2635 q->issuer_name = NULL;
2636 return ret;
2638 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2639 return 0;
2643 * Set the query controller to match on a friendly name
2645 * @param q a hx509 query controller.
2646 * @param name a friendly name to match on
2648 * @return An hx509 error code, see hx509_get_error_string().
2650 * @ingroup hx509_cert
2654 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2656 if (q->friendlyname)
2657 free(q->friendlyname);
2658 q->friendlyname = strdup(name);
2659 if (q->friendlyname == NULL)
2660 return ENOMEM;
2661 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2662 return 0;
2666 * Set the query controller to require an one specific EKU (extended
2667 * key usage). Any previous EKU matching is overwitten. If NULL is
2668 * passed in as the eku, the EKU requirement is reset.
2670 * @param q a hx509 query controller.
2671 * @param eku an EKU to match on.
2673 * @return An hx509 error code, see hx509_get_error_string().
2675 * @ingroup hx509_cert
2679 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2681 int ret;
2683 if (eku == NULL) {
2684 if (q->eku) {
2685 der_free_oid(q->eku);
2686 free(q->eku);
2687 q->eku = NULL;
2689 q->match &= ~HX509_QUERY_MATCH_EKU;
2690 } else {
2691 if (q->eku) {
2692 der_free_oid(q->eku);
2693 } else {
2694 q->eku = calloc(1, sizeof(*q->eku));
2695 if (q->eku == NULL)
2696 return ENOMEM;
2698 ret = der_copy_oid(eku, q->eku);
2699 if (ret) {
2700 free(q->eku);
2701 q->eku = NULL;
2702 return ret;
2704 q->match |= HX509_QUERY_MATCH_EKU;
2706 return 0;
2710 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2712 if (q->expr) {
2713 _hx509_expr_free(q->expr);
2714 q->expr = NULL;
2717 if (expr == NULL) {
2718 q->match &= ~HX509_QUERY_MATCH_EXPR;
2719 } else {
2720 q->expr = _hx509_expr_parse(expr);
2721 if (q->expr)
2722 q->match |= HX509_QUERY_MATCH_EXPR;
2725 return 0;
2729 * Set the query controller to match using a specific match function.
2731 * @param q a hx509 query controller.
2732 * @param func function to use for matching, if the argument is NULL,
2733 * the match function is removed.
2734 * @param ctx context passed to the function.
2736 * @return An hx509 error code, see hx509_get_error_string().
2738 * @ingroup hx509_cert
2742 hx509_query_match_cmp_func(hx509_query *q,
2743 int (*func)(void *, hx509_cert),
2744 void *ctx)
2746 if (func)
2747 q->match |= HX509_QUERY_MATCH_FUNCTION;
2748 else
2749 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2750 q->cmp_func = func;
2751 q->cmp_func_ctx = ctx;
2752 return 0;
2756 * Free the query controller.
2758 * @param context A hx509 context.
2759 * @param q a pointer to the query controller.
2761 * @ingroup hx509_cert
2764 void
2765 hx509_query_free(hx509_context context, hx509_query *q)
2767 if (q == NULL)
2768 return;
2770 if (q->serial) {
2771 der_free_heim_integer(q->serial);
2772 free(q->serial);
2774 if (q->issuer_name) {
2775 free_Name(q->issuer_name);
2776 free(q->issuer_name);
2778 if (q->eku) {
2779 der_free_oid(q->eku);
2780 free(q->eku);
2782 if (q->friendlyname)
2783 free(q->friendlyname);
2784 if (q->expr)
2785 _hx509_expr_free(q->expr);
2787 memset(q, 0, sizeof(*q));
2788 free(q);
2792 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2794 Certificate *c = _hx509_get_cert(cert);
2795 int ret, diff;
2797 _hx509_query_statistic(context, 1, q);
2799 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2800 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2801 return 0;
2803 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2804 _hx509_Certificate_cmp(q->certificate, c) != 0)
2805 return 0;
2807 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2808 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2809 return 0;
2811 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2812 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2813 if (ret || diff)
2814 return 0;
2817 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2818 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2819 if (ret || diff)
2820 return 0;
2823 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2824 SubjectKeyIdentifier si;
2826 ret = _hx509_find_extension_subject_key_id(c, &si);
2827 if (ret == 0) {
2828 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2829 ret = 1;
2830 free_SubjectKeyIdentifier(&si);
2832 if (ret)
2833 return 0;
2835 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2836 return 0;
2837 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2838 _hx509_cert_private_key(cert) == NULL)
2839 return 0;
2842 unsigned ku = 0;
2843 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2844 ku |= (1 << 0);
2845 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2846 ku |= (1 << 1);
2847 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2848 ku |= (1 << 2);
2849 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2850 ku |= (1 << 3);
2851 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2852 ku |= (1 << 4);
2853 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2854 ku |= (1 << 5);
2855 if (q->match & HX509_QUERY_KU_CRLSIGN)
2856 ku |= (1 << 6);
2857 if (ku && check_key_usage(context, c, ku, TRUE))
2858 return 0;
2860 if ((q->match & HX509_QUERY_ANCHOR))
2861 return 0;
2863 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2864 hx509_cert_attribute a;
2866 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2867 if (a == NULL)
2868 return 0;
2869 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2870 return 0;
2873 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2874 size_t i;
2876 for (i = 0; i < q->path->len; i++)
2877 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2878 return 0;
2880 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2881 const char *name = hx509_cert_get_friendly_name(cert);
2882 if (name == NULL)
2883 return 0;
2884 if (strcasecmp(q->friendlyname, name) != 0)
2885 return 0;
2887 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2888 ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2889 if (ret != 0)
2890 return 0;
2893 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2894 heim_octet_string os;
2896 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2897 os.length =
2898 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2900 ret = _hx509_verify_signature(context,
2901 NULL,
2902 hx509_signature_sha1(),
2903 &os,
2904 q->keyhash_sha1);
2905 if (ret != 0)
2906 return 0;
2909 if (q->match & HX509_QUERY_MATCH_TIME) {
2910 time_t t;
2911 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2912 if (t > q->timenow)
2913 return 0;
2914 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2915 if (t < q->timenow)
2916 return 0;
2919 /* If an EKU is required, check the cert for it. */
2920 if ((q->match & HX509_QUERY_MATCH_EKU) &&
2921 hx509_cert_check_eku(context, cert, q->eku, 0))
2922 return 0;
2924 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
2925 hx509_env env = NULL;
2927 ret = _hx509_cert_to_env(context, cert, &env);
2928 if (ret)
2929 return 0;
2931 ret = _hx509_expr_eval(context, env, q->expr);
2932 hx509_env_free(&env);
2933 if (ret == 0)
2934 return 0;
2937 if (q->match & ~HX509_QUERY_MASK)
2938 return 0;
2940 return 1;
2944 * Set a statistic file for the query statistics.
2946 * @param context A hx509 context.
2947 * @param fn statistics file name
2949 * @ingroup hx509_cert
2952 void
2953 hx509_query_statistic_file(hx509_context context, const char *fn)
2955 if (context->querystat)
2956 free(context->querystat);
2957 context->querystat = strdup(fn);
2960 void
2961 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2963 FILE *f;
2964 if (context->querystat == NULL)
2965 return;
2966 f = fopen(context->querystat, "a");
2967 if (f == NULL)
2968 return;
2969 fprintf(f, "%d %d\n", type, q->match);
2970 fclose(f);
2973 static const char *statname[] = {
2974 "find issuer cert",
2975 "match serialnumber",
2976 "match issuer name",
2977 "match subject name",
2978 "match subject key id",
2979 "match issuer id",
2980 "private key",
2981 "ku encipherment",
2982 "ku digitalsignature",
2983 "ku keycertsign",
2984 "ku crlsign",
2985 "ku nonrepudiation",
2986 "ku keyagreement",
2987 "ku dataencipherment",
2988 "anchor",
2989 "match certificate",
2990 "match local key id",
2991 "no match path",
2992 "match friendly name",
2993 "match function",
2994 "match key hash sha1",
2995 "match time"
2998 struct stat_el {
2999 unsigned long stats;
3000 unsigned int index;
3004 static int
3005 stat_sort(const void *a, const void *b)
3007 const struct stat_el *ae = a;
3008 const struct stat_el *be = b;
3009 return be->stats - ae->stats;
3013 * Unparse the statistics file and print the result on a FILE descriptor.
3015 * @param context A hx509 context.
3016 * @param printtype tyep to print
3017 * @param out the FILE to write the data on.
3019 * @ingroup hx509_cert
3022 void
3023 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3025 rtbl_t t;
3026 FILE *f;
3027 int type, mask, i, num;
3028 unsigned long multiqueries = 0, totalqueries = 0;
3029 struct stat_el stats[32];
3031 if (context->querystat == NULL)
3032 return;
3033 f = fopen(context->querystat, "r");
3034 if (f == NULL) {
3035 fprintf(out, "No statistic file %s: %s.\n",
3036 context->querystat, strerror(errno));
3037 return;
3040 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3041 stats[i].index = i;
3042 stats[i].stats = 0;
3045 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3046 if (type != printtype)
3047 continue;
3048 num = i = 0;
3049 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3050 if (mask & 1) {
3051 stats[i].stats++;
3052 num++;
3054 mask = mask >>1 ;
3055 i++;
3057 if (num > 1)
3058 multiqueries++;
3059 totalqueries++;
3061 fclose(f);
3063 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3065 t = rtbl_create();
3066 if (t == NULL)
3067 errx(1, "out of memory");
3069 rtbl_set_separator (t, " ");
3071 rtbl_add_column_by_id (t, 0, "Name", 0);
3072 rtbl_add_column_by_id (t, 1, "Counter", 0);
3075 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3076 char str[10];
3078 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3079 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3080 else {
3081 snprintf(str, sizeof(str), "%d", stats[i].index);
3082 rtbl_add_column_entry_by_id (t, 0, str);
3084 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3085 rtbl_add_column_entry_by_id (t, 1, str);
3088 rtbl_format(t, out);
3089 rtbl_destroy(t);
3091 fprintf(out, "\nQueries: multi %lu total %lu\n",
3092 multiqueries, totalqueries);
3096 * Check the extended key usage on the hx509 certificate.
3098 * @param context A hx509 context.
3099 * @param cert A hx509 context.
3100 * @param eku the EKU to check for
3101 * @param allow_any_eku if the any EKU is set, allow that to be a
3102 * substitute.
3104 * @return An hx509 error code, see hx509_get_error_string().
3106 * @ingroup hx509_cert
3110 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3111 const heim_oid *eku, int allow_any_eku)
3113 ExtKeyUsage e;
3114 int ret, i;
3116 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3117 if (ret) {
3118 hx509_clear_error_string(context);
3119 return ret;
3122 for (i = 0; i < e.len; i++) {
3123 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3124 free_ExtKeyUsage(&e);
3125 return 0;
3127 if (allow_any_eku) {
3128 #if 0
3129 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3130 free_ExtKeyUsage(&e);
3131 return 0;
3133 #endif
3136 free_ExtKeyUsage(&e);
3137 hx509_clear_error_string(context);
3138 return HX509_CERTIFICATE_MISSING_EKU;
3142 _hx509_cert_get_keyusage(hx509_context context,
3143 hx509_cert c,
3144 KeyUsage *ku)
3146 Certificate *cert;
3147 const Extension *e;
3148 size_t size;
3149 int ret, i = 0;
3151 memset(ku, 0, sizeof(*ku));
3153 cert = _hx509_get_cert(c);
3155 if (_hx509_cert_get_version(cert) < 3)
3156 return 0;
3158 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
3159 if (e == NULL)
3160 return HX509_KU_CERT_MISSING;
3162 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3163 if (ret)
3164 return ret;
3165 return 0;
3169 _hx509_cert_get_eku(hx509_context context,
3170 hx509_cert cert,
3171 ExtKeyUsage *e)
3173 int ret;
3175 memset(e, 0, sizeof(*e));
3177 ret = find_extension_eku(_hx509_get_cert(cert), e);
3178 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3179 hx509_clear_error_string(context);
3180 return ret;
3182 return 0;
3186 * Encodes the hx509 certificate as a DER encode binary.
3188 * @param context A hx509 context.
3189 * @param c the certificate to encode.
3190 * @param os the encode certificate, set to NULL, 0 on case of
3191 * error. Free the returned structure with hx509_xfree().
3193 * @return An hx509 error code, see hx509_get_error_string().
3195 * @ingroup hx509_cert
3199 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3201 size_t size;
3202 int ret;
3204 os->data = NULL;
3205 os->length = 0;
3207 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3208 _hx509_get_cert(c), &size, ret);
3209 if (ret) {
3210 os->data = NULL;
3211 os->length = 0;
3212 return ret;
3214 if (os->length != size)
3215 _hx509_abort("internal ASN.1 encoder error");
3217 return ret;
3221 * Last to avoid lost __attribute__s due to #undef.
3224 #undef __attribute__
3225 #define __attribute__(X)
3227 void
3228 _hx509_abort(const char *fmt, ...)
3229 __attribute__ ((noreturn, format (printf, 1, 2)))
3231 va_list ap;
3232 va_start(ap, fmt);
3233 vprintf(fmt, ap);
3234 va_end(ap);
3235 printf("\n");
3236 fflush(stdout);
3237 abort();
3241 * Free a data element allocated in the library.
3243 * @param ptr data to be freed.
3245 * @ingroup hx509_misc
3248 void
3249 hx509_xfree(void *ptr)
3251 free(ptr);
3259 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3261 ExtKeyUsage eku;
3262 hx509_name name;
3263 char *buf;
3264 int ret;
3265 hx509_env envcert = NULL;
3267 *env = NULL;
3269 /* version */
3270 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3271 ret = hx509_env_add(context, &envcert, "version", buf);
3272 free(buf);
3273 if (ret)
3274 goto out;
3276 /* subject */
3277 ret = hx509_cert_get_subject(cert, &name);
3278 if (ret)
3279 goto out;
3281 ret = hx509_name_to_string(name, &buf);
3282 if (ret) {
3283 hx509_name_free(&name);
3284 goto out;
3287 ret = hx509_env_add(context, &envcert, "subject", buf);
3288 hx509_name_free(&name);
3289 if (ret)
3290 goto out;
3292 /* issuer */
3293 ret = hx509_cert_get_issuer(cert, &name);
3294 if (ret)
3295 goto out;
3297 ret = hx509_name_to_string(name, &buf);
3298 hx509_name_free(&name);
3299 if (ret)
3300 goto out;
3302 ret = hx509_env_add(context, &envcert, "issuer", buf);
3303 hx509_xfree(buf);
3304 if (ret)
3305 goto out;
3307 /* eku */
3309 ret = _hx509_cert_get_eku(context, cert, &eku);
3310 if (ret == HX509_EXTENSION_NOT_FOUND)
3312 else if (ret != 0)
3313 goto out;
3314 else {
3315 int i;
3316 hx509_env enveku = NULL;
3318 for (i = 0; i < eku.len; i++) {
3320 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3321 if (ret) {
3322 free_ExtKeyUsage(&eku);
3323 hx509_env_free(&enveku);
3324 goto out;
3326 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3327 free(buf);
3328 if (ret) {
3329 free_ExtKeyUsage(&eku);
3330 hx509_env_free(&enveku);
3331 goto out;
3334 free_ExtKeyUsage(&eku);
3336 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3337 if (ret) {
3338 hx509_env_free(&enveku);
3339 goto out;
3343 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3344 if (ret)
3345 goto out;
3347 return 0;
3349 out:
3350 hx509_env_free(&envcert);
3351 return ret;