misc functions.
[heimdal.git] / lib / hx509 / cert.c
blobd0db7af23e788994639aa513077756b630ffad69
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 /* XXX use subject name ? */
2495 return NULL;
2498 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2499 if (ret)
2500 return NULL;
2502 if (n.len != 1) {
2503 free_PKCS9_friendlyName(&n);
2504 return NULL;
2507 cert->friendlyname = malloc(n.val[0].length + 1);
2508 if (cert->friendlyname == NULL) {
2509 free_PKCS9_friendlyName(&n);
2510 return NULL;
2513 for (i = 0; i < n.val[0].length; i++) {
2514 if (n.val[0].data[i] <= 0xff)
2515 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2516 else
2517 cert->friendlyname[i] = 'X';
2519 cert->friendlyname[i] = '\0';
2520 free_PKCS9_friendlyName(&n);
2522 return cert->friendlyname;
2525 void
2526 _hx509_query_clear(hx509_query *q)
2528 memset(q, 0, sizeof(*q));
2532 * Allocate an query controller. Free using hx509_query_free().
2534 * @param context A hx509 context.
2535 * @param q return pointer to a hx509_query.
2537 * @return An hx509 error code, see hx509_get_error_string().
2539 * @ingroup hx509_cert
2543 hx509_query_alloc(hx509_context context, hx509_query **q)
2545 *q = calloc(1, sizeof(**q));
2546 if (*q == NULL)
2547 return ENOMEM;
2548 return 0;
2553 * Set match options for the hx509 query controller.
2555 * @param q query controller.
2556 * @param option options to control the query controller.
2558 * @return An hx509 error code, see hx509_get_error_string().
2560 * @ingroup hx509_cert
2563 void
2564 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2566 switch(option) {
2567 case HX509_QUERY_OPTION_PRIVATE_KEY:
2568 q->match |= HX509_QUERY_PRIVATE_KEY;
2569 break;
2570 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2571 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2572 break;
2573 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2574 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2575 break;
2576 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2577 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2578 break;
2579 case HX509_QUERY_OPTION_END:
2580 default:
2581 break;
2586 * Set the issuer and serial number of match in the query
2587 * controller. The function make copies of the isser and serial number.
2589 * @param q a hx509 query controller
2590 * @param issuer issuer to search for
2591 * @param serialNumber the serialNumber of the issuer.
2593 * @return An hx509 error code, see hx509_get_error_string().
2595 * @ingroup hx509_cert
2599 hx509_query_match_issuer_serial(hx509_query *q,
2600 const Name *issuer,
2601 const heim_integer *serialNumber)
2603 int ret;
2604 if (q->serial) {
2605 der_free_heim_integer(q->serial);
2606 free(q->serial);
2608 q->serial = malloc(sizeof(*q->serial));
2609 if (q->serial == NULL)
2610 return ENOMEM;
2611 ret = der_copy_heim_integer(serialNumber, q->serial);
2612 if (ret) {
2613 free(q->serial);
2614 q->serial = NULL;
2615 return ret;
2617 if (q->issuer_name) {
2618 free_Name(q->issuer_name);
2619 free(q->issuer_name);
2621 q->issuer_name = malloc(sizeof(*q->issuer_name));
2622 if (q->issuer_name == NULL)
2623 return ENOMEM;
2624 ret = copy_Name(issuer, q->issuer_name);
2625 if (ret) {
2626 free(q->issuer_name);
2627 q->issuer_name = NULL;
2628 return ret;
2630 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2631 return 0;
2635 * Set the query controller to match on a friendly name
2637 * @param q a hx509 query controller.
2638 * @param name a friendly name to match on
2640 * @return An hx509 error code, see hx509_get_error_string().
2642 * @ingroup hx509_cert
2646 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2648 if (q->friendlyname)
2649 free(q->friendlyname);
2650 q->friendlyname = strdup(name);
2651 if (q->friendlyname == NULL)
2652 return ENOMEM;
2653 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2654 return 0;
2658 * Set the query controller to require an one specific EKU (extended
2659 * key usage). Any previous EKU matching is overwitten. If NULL is
2660 * passed in as the eku, the EKU requirement is reset.
2662 * @param q a hx509 query controller.
2663 * @param eku an EKU to match on.
2665 * @return An hx509 error code, see hx509_get_error_string().
2667 * @ingroup hx509_cert
2671 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2673 int ret;
2675 if (eku == NULL) {
2676 if (q->eku) {
2677 der_free_oid(q->eku);
2678 free(q->eku);
2679 q->eku = NULL;
2681 q->match &= ~HX509_QUERY_MATCH_EKU;
2682 } else {
2683 if (q->eku) {
2684 der_free_oid(q->eku);
2685 } else {
2686 q->eku = calloc(1, sizeof(*q->eku));
2687 if (q->eku == NULL)
2688 return ENOMEM;
2690 ret = der_copy_oid(eku, q->eku);
2691 if (ret) {
2692 free(q->eku);
2693 q->eku = NULL;
2694 return ret;
2696 q->match |= HX509_QUERY_MATCH_EKU;
2698 return 0;
2702 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2704 if (q->expr) {
2705 _hx509_expr_free(q->expr);
2706 q->expr = NULL;
2709 if (expr == NULL) {
2710 q->match &= ~HX509_QUERY_MATCH_EXPR;
2711 } else {
2712 q->expr = _hx509_expr_parse(expr);
2713 if (q->expr)
2714 q->match |= HX509_QUERY_MATCH_EXPR;
2717 return 0;
2721 * Set the query controller to match using a specific match function.
2723 * @param q a hx509 query controller.
2724 * @param func function to use for matching, if the argument is NULL,
2725 * the match function is removed.
2726 * @param ctx context passed to the function.
2728 * @return An hx509 error code, see hx509_get_error_string().
2730 * @ingroup hx509_cert
2734 hx509_query_match_cmp_func(hx509_query *q,
2735 int (*func)(void *, hx509_cert),
2736 void *ctx)
2738 if (func)
2739 q->match |= HX509_QUERY_MATCH_FUNCTION;
2740 else
2741 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2742 q->cmp_func = func;
2743 q->cmp_func_ctx = ctx;
2744 return 0;
2748 * Free the query controller.
2750 * @param context A hx509 context.
2751 * @param q a pointer to the query controller.
2753 * @ingroup hx509_cert
2756 void
2757 hx509_query_free(hx509_context context, hx509_query *q)
2759 if (q == NULL)
2760 return;
2762 if (q->serial) {
2763 der_free_heim_integer(q->serial);
2764 free(q->serial);
2766 if (q->issuer_name) {
2767 free_Name(q->issuer_name);
2768 free(q->issuer_name);
2770 if (q->eku) {
2771 der_free_oid(q->eku);
2772 free(q->eku);
2774 if (q->friendlyname)
2775 free(q->friendlyname);
2776 if (q->expr)
2777 _hx509_expr_free(q->expr);
2779 memset(q, 0, sizeof(*q));
2780 free(q);
2784 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2786 Certificate *c = _hx509_get_cert(cert);
2787 int ret, diff;
2789 _hx509_query_statistic(context, 1, q);
2791 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2792 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2793 return 0;
2795 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2796 _hx509_Certificate_cmp(q->certificate, c) != 0)
2797 return 0;
2799 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2800 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2801 return 0;
2803 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2804 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2805 if (ret || diff)
2806 return 0;
2809 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2810 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2811 if (ret || diff)
2812 return 0;
2815 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2816 SubjectKeyIdentifier si;
2818 ret = _hx509_find_extension_subject_key_id(c, &si);
2819 if (ret == 0) {
2820 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2821 ret = 1;
2822 free_SubjectKeyIdentifier(&si);
2824 if (ret)
2825 return 0;
2827 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2828 return 0;
2829 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2830 _hx509_cert_private_key(cert) == NULL)
2831 return 0;
2834 unsigned ku = 0;
2835 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2836 ku |= (1 << 0);
2837 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2838 ku |= (1 << 1);
2839 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2840 ku |= (1 << 2);
2841 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2842 ku |= (1 << 3);
2843 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2844 ku |= (1 << 4);
2845 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2846 ku |= (1 << 5);
2847 if (q->match & HX509_QUERY_KU_CRLSIGN)
2848 ku |= (1 << 6);
2849 if (ku && check_key_usage(context, c, ku, TRUE))
2850 return 0;
2852 if ((q->match & HX509_QUERY_ANCHOR))
2853 return 0;
2855 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2856 hx509_cert_attribute a;
2858 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2859 if (a == NULL)
2860 return 0;
2861 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2862 return 0;
2865 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2866 size_t i;
2868 for (i = 0; i < q->path->len; i++)
2869 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2870 return 0;
2872 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2873 const char *name = hx509_cert_get_friendly_name(cert);
2874 if (name == NULL)
2875 return 0;
2876 if (strcasecmp(q->friendlyname, name) != 0)
2877 return 0;
2879 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2880 ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2881 if (ret != 0)
2882 return 0;
2885 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2886 heim_octet_string os;
2888 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2889 os.length =
2890 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2892 ret = _hx509_verify_signature(context,
2893 NULL,
2894 hx509_signature_sha1(),
2895 &os,
2896 q->keyhash_sha1);
2897 if (ret != 0)
2898 return 0;
2901 if (q->match & HX509_QUERY_MATCH_TIME) {
2902 time_t t;
2903 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2904 if (t > q->timenow)
2905 return 0;
2906 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2907 if (t < q->timenow)
2908 return 0;
2911 /* If an EKU is required, check the cert for it. */
2912 if ((q->match & HX509_QUERY_MATCH_EKU) &&
2913 hx509_cert_check_eku(context, cert, q->eku, 0))
2914 return 0;
2916 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
2917 hx509_env env = NULL;
2919 ret = _hx509_cert_to_env(context, cert, &env);
2920 if (ret)
2921 return 0;
2923 ret = _hx509_expr_eval(context, env, q->expr);
2924 hx509_env_free(&env);
2925 if (ret == 0)
2926 return 0;
2929 if (q->match & ~HX509_QUERY_MASK)
2930 return 0;
2932 return 1;
2936 * Set a statistic file for the query statistics.
2938 * @param context A hx509 context.
2939 * @param fn statistics file name
2941 * @ingroup hx509_cert
2944 void
2945 hx509_query_statistic_file(hx509_context context, const char *fn)
2947 if (context->querystat)
2948 free(context->querystat);
2949 context->querystat = strdup(fn);
2952 void
2953 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2955 FILE *f;
2956 if (context->querystat == NULL)
2957 return;
2958 f = fopen(context->querystat, "a");
2959 if (f == NULL)
2960 return;
2961 fprintf(f, "%d %d\n", type, q->match);
2962 fclose(f);
2965 static const char *statname[] = {
2966 "find issuer cert",
2967 "match serialnumber",
2968 "match issuer name",
2969 "match subject name",
2970 "match subject key id",
2971 "match issuer id",
2972 "private key",
2973 "ku encipherment",
2974 "ku digitalsignature",
2975 "ku keycertsign",
2976 "ku crlsign",
2977 "ku nonrepudiation",
2978 "ku keyagreement",
2979 "ku dataencipherment",
2980 "anchor",
2981 "match certificate",
2982 "match local key id",
2983 "no match path",
2984 "match friendly name",
2985 "match function",
2986 "match key hash sha1",
2987 "match time"
2990 struct stat_el {
2991 unsigned long stats;
2992 unsigned int index;
2996 static int
2997 stat_sort(const void *a, const void *b)
2999 const struct stat_el *ae = a;
3000 const struct stat_el *be = b;
3001 return be->stats - ae->stats;
3005 * Unparse the statistics file and print the result on a FILE descriptor.
3007 * @param context A hx509 context.
3008 * @param printtype tyep to print
3009 * @param out the FILE to write the data on.
3011 * @ingroup hx509_cert
3014 void
3015 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3017 rtbl_t t;
3018 FILE *f;
3019 int type, mask, i, num;
3020 unsigned long multiqueries = 0, totalqueries = 0;
3021 struct stat_el stats[32];
3023 if (context->querystat == NULL)
3024 return;
3025 f = fopen(context->querystat, "r");
3026 if (f == NULL) {
3027 fprintf(out, "No statistic file %s: %s.\n",
3028 context->querystat, strerror(errno));
3029 return;
3032 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3033 stats[i].index = i;
3034 stats[i].stats = 0;
3037 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3038 if (type != printtype)
3039 continue;
3040 num = i = 0;
3041 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3042 if (mask & 1) {
3043 stats[i].stats++;
3044 num++;
3046 mask = mask >>1 ;
3047 i++;
3049 if (num > 1)
3050 multiqueries++;
3051 totalqueries++;
3053 fclose(f);
3055 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3057 t = rtbl_create();
3058 if (t == NULL)
3059 errx(1, "out of memory");
3061 rtbl_set_separator (t, " ");
3063 rtbl_add_column_by_id (t, 0, "Name", 0);
3064 rtbl_add_column_by_id (t, 1, "Counter", 0);
3067 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3068 char str[10];
3070 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3071 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3072 else {
3073 snprintf(str, sizeof(str), "%d", stats[i].index);
3074 rtbl_add_column_entry_by_id (t, 0, str);
3076 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3077 rtbl_add_column_entry_by_id (t, 1, str);
3080 rtbl_format(t, out);
3081 rtbl_destroy(t);
3083 fprintf(out, "\nQueries: multi %lu total %lu\n",
3084 multiqueries, totalqueries);
3088 * Check the extended key usage on the hx509 certificate.
3090 * @param context A hx509 context.
3091 * @param cert A hx509 context.
3092 * @param eku the EKU to check for
3093 * @param allow_any_eku if the any EKU is set, allow that to be a
3094 * substitute.
3096 * @return An hx509 error code, see hx509_get_error_string().
3098 * @ingroup hx509_cert
3102 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3103 const heim_oid *eku, int allow_any_eku)
3105 ExtKeyUsage e;
3106 int ret, i;
3108 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3109 if (ret) {
3110 hx509_clear_error_string(context);
3111 return ret;
3114 for (i = 0; i < e.len; i++) {
3115 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3116 free_ExtKeyUsage(&e);
3117 return 0;
3119 if (allow_any_eku) {
3120 #if 0
3121 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3122 free_ExtKeyUsage(&e);
3123 return 0;
3125 #endif
3128 free_ExtKeyUsage(&e);
3129 hx509_clear_error_string(context);
3130 return HX509_CERTIFICATE_MISSING_EKU;
3134 _hx509_cert_get_keyusage(hx509_context context,
3135 hx509_cert c,
3136 KeyUsage *ku)
3138 Certificate *cert;
3139 const Extension *e;
3140 size_t size;
3141 int ret, i = 0;
3143 memset(ku, 0, sizeof(*ku));
3145 cert = _hx509_get_cert(c);
3147 if (_hx509_cert_get_version(cert) < 3)
3148 return 0;
3150 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
3151 if (e == NULL)
3152 return HX509_KU_CERT_MISSING;
3154 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3155 if (ret)
3156 return ret;
3157 return 0;
3161 _hx509_cert_get_eku(hx509_context context,
3162 hx509_cert cert,
3163 ExtKeyUsage *e)
3165 int ret;
3167 memset(e, 0, sizeof(*e));
3169 ret = find_extension_eku(_hx509_get_cert(cert), e);
3170 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3171 hx509_clear_error_string(context);
3172 return ret;
3174 return 0;
3178 * Encodes the hx509 certificate as a DER encode binary.
3180 * @param context A hx509 context.
3181 * @param c the certificate to encode.
3182 * @param os the encode certificate, set to NULL, 0 on case of
3183 * error. Free the returned structure with hx509_xfree().
3185 * @return An hx509 error code, see hx509_get_error_string().
3187 * @ingroup hx509_cert
3191 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3193 size_t size;
3194 int ret;
3196 os->data = NULL;
3197 os->length = 0;
3199 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3200 _hx509_get_cert(c), &size, ret);
3201 if (ret) {
3202 os->data = NULL;
3203 os->length = 0;
3204 return ret;
3206 if (os->length != size)
3207 _hx509_abort("internal ASN.1 encoder error");
3209 return ret;
3213 * Last to avoid lost __attribute__s due to #undef.
3216 #undef __attribute__
3217 #define __attribute__(X)
3219 void
3220 _hx509_abort(const char *fmt, ...)
3221 __attribute__ ((noreturn, format (printf, 1, 2)))
3223 va_list ap;
3224 va_start(ap, fmt);
3225 vprintf(fmt, ap);
3226 va_end(ap);
3227 printf("\n");
3228 fflush(stdout);
3229 abort();
3233 * Free a data element allocated in the library.
3235 * @param ptr data to be freed.
3237 * @ingroup hx509_misc
3240 void
3241 hx509_xfree(void *ptr)
3243 free(ptr);
3251 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3253 ExtKeyUsage eku;
3254 hx509_name name;
3255 char *buf;
3256 int ret;
3257 hx509_env envcert = NULL;
3259 *env = NULL;
3261 /* version */
3262 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3263 ret = hx509_env_add(context, &envcert, "version", buf);
3264 free(buf);
3265 if (ret)
3266 goto out;
3268 /* subject */
3269 ret = hx509_cert_get_subject(cert, &name);
3270 if (ret)
3271 goto out;
3273 ret = hx509_name_to_string(name, &buf);
3274 if (ret) {
3275 hx509_name_free(&name);
3276 goto out;
3279 ret = hx509_env_add(context, &envcert, "subject", buf);
3280 hx509_name_free(&name);
3281 if (ret)
3282 goto out;
3284 /* issuer */
3285 ret = hx509_cert_get_issuer(cert, &name);
3286 if (ret)
3287 goto out;
3289 ret = hx509_name_to_string(name, &buf);
3290 hx509_name_free(&name);
3291 if (ret)
3292 goto out;
3294 ret = hx509_env_add(context, &envcert, "issuer", buf);
3295 hx509_xfree(buf);
3296 if (ret)
3297 goto out;
3299 /* eku */
3301 ret = _hx509_cert_get_eku(context, cert, &eku);
3302 if (ret == HX509_EXTENSION_NOT_FOUND)
3304 else if (ret != 0)
3305 goto out;
3306 else {
3307 int i;
3308 hx509_env enveku = NULL;
3310 for (i = 0; i < eku.len; i++) {
3312 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3313 if (ret) {
3314 free_ExtKeyUsage(&eku);
3315 hx509_env_free(&enveku);
3316 goto out;
3318 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3319 free(buf);
3320 if (ret) {
3321 free_ExtKeyUsage(&eku);
3322 hx509_env_free(&enveku);
3323 goto out;
3326 free_ExtKeyUsage(&eku);
3328 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3329 if (ret) {
3330 hx509_env_free(&enveku);
3331 goto out;
3335 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3336 if (ret)
3337 goto out;
3339 return 0;
3341 out:
3342 hx509_env_free(&envcert);
3343 return ret;