Add hx509_cert_get_SPKI_AlgorithmIdentifier, remove unused stuff, add hx509_context...
[heimdal.git] / lib / hx509 / cert.c
blob1e4ad6f389625da087774be685a377236564dea2
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;
898 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
899 &subject->tbsCertificate.issuer);
900 if (diff)
901 return diff;
903 memset(&ai, 0, sizeof(ai));
904 memset(&si, 0, sizeof(si));
907 * Try to find AuthorityKeyIdentifier, if it's not present in the
908 * subject certificate nor the parent.
911 ret_ai = find_extension_auth_key_id(subject, &ai);
912 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
913 return 1;
914 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
915 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
916 return -1;
918 if (ret_si && ret_ai)
919 goto out;
920 if (ret_ai)
921 goto out;
922 if (ret_si) {
923 if (allow_self_signed) {
924 diff = 0;
925 goto out;
926 } else if (ai.keyIdentifier) {
927 diff = -1;
928 goto out;
932 if (ai.keyIdentifier == NULL) {
933 Name name;
935 if (ai.authorityCertIssuer == NULL)
936 return -1;
937 if (ai.authorityCertSerialNumber == NULL)
938 return -1;
940 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
941 &issuer->tbsCertificate.serialNumber);
942 if (diff)
943 return diff;
944 if (ai.authorityCertIssuer->len != 1)
945 return -1;
946 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
947 return -1;
949 name.element =
950 ai.authorityCertIssuer->val[0].u.directoryName.element;
951 name.u.rdnSequence =
952 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
954 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
955 &name);
956 if (diff)
957 return diff;
958 diff = 0;
959 } else
960 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
961 if (diff)
962 goto out;
964 out:
965 free_AuthorityKeyIdentifier(&ai);
966 free_SubjectKeyIdentifier(&si);
967 return diff;
970 static int
971 certificate_is_anchor(hx509_context context,
972 hx509_certs trust_anchors,
973 const hx509_cert cert)
975 hx509_query q;
976 hx509_cert c;
977 int ret;
979 if (trust_anchors == NULL)
980 return 0;
982 _hx509_query_clear(&q);
984 q.match = HX509_QUERY_MATCH_CERTIFICATE;
985 q.certificate = _hx509_get_cert(cert);
987 ret = hx509_certs_find(context, trust_anchors, &q, &c);
988 if (ret == 0)
989 hx509_cert_free(c);
990 return ret == 0;
993 static int
994 certificate_is_self_signed(const Certificate *cert)
996 return _hx509_name_cmp(&cert->tbsCertificate.subject,
997 &cert->tbsCertificate.issuer) == 0;
1001 * The subjectName is "null" when it's empty set of relative DBs.
1004 static int
1005 subject_null_p(const Certificate *c)
1007 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1011 static int
1012 find_parent(hx509_context context,
1013 time_t time_now,
1014 hx509_certs trust_anchors,
1015 hx509_path *path,
1016 hx509_certs pool,
1017 hx509_cert current,
1018 hx509_cert *parent)
1020 AuthorityKeyIdentifier ai;
1021 hx509_query q;
1022 int ret;
1024 *parent = NULL;
1025 memset(&ai, 0, sizeof(ai));
1027 _hx509_query_clear(&q);
1029 if (!subject_null_p(current->data)) {
1030 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1031 q.subject = _hx509_get_cert(current);
1032 } else {
1033 ret = find_extension_auth_key_id(current->data, &ai);
1034 if (ret) {
1035 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1036 "Subjectless certificate missing AuthKeyID");
1037 return HX509_CERTIFICATE_MALFORMED;
1040 if (ai.keyIdentifier == NULL) {
1041 free_AuthorityKeyIdentifier(&ai);
1042 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1043 "Subjectless certificate missing keyIdentifier "
1044 "inside AuthKeyID");
1045 return HX509_CERTIFICATE_MALFORMED;
1048 q.subject_id = ai.keyIdentifier;
1049 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1052 q.path = path;
1053 q.match |= HX509_QUERY_NO_MATCH_PATH;
1055 if (pool) {
1056 q.timenow = time_now;
1057 q.match |= HX509_QUERY_MATCH_TIME;
1059 ret = hx509_certs_find(context, pool, &q, parent);
1060 if (ret == 0) {
1061 free_AuthorityKeyIdentifier(&ai);
1062 return 0;
1064 q.match &= ~HX509_QUERY_MATCH_TIME;
1067 if (trust_anchors) {
1068 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1069 if (ret == 0) {
1070 free_AuthorityKeyIdentifier(&ai);
1071 return ret;
1074 free_AuthorityKeyIdentifier(&ai);
1077 hx509_name name;
1078 char *str;
1080 ret = hx509_cert_get_subject(current, &name);
1081 if (ret) {
1082 hx509_clear_error_string(context);
1083 return HX509_ISSUER_NOT_FOUND;
1085 ret = hx509_name_to_string(name, &str);
1086 hx509_name_free(&name);
1087 if (ret) {
1088 hx509_clear_error_string(context);
1089 return HX509_ISSUER_NOT_FOUND;
1092 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1093 "Failed to find issuer for "
1094 "certificate with subject: '%s'", str);
1095 free(str);
1097 return HX509_ISSUER_NOT_FOUND;
1104 static int
1105 is_proxy_cert(hx509_context context,
1106 const Certificate *cert,
1107 ProxyCertInfo *rinfo)
1109 ProxyCertInfo info;
1110 const Extension *e;
1111 size_t size;
1112 int ret, i = 0;
1114 if (rinfo)
1115 memset(rinfo, 0, sizeof(*rinfo));
1117 e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i);
1118 if (e == NULL) {
1119 hx509_clear_error_string(context);
1120 return HX509_EXTENSION_NOT_FOUND;
1123 ret = decode_ProxyCertInfo(e->extnValue.data,
1124 e->extnValue.length,
1125 &info,
1126 &size);
1127 if (ret) {
1128 hx509_clear_error_string(context);
1129 return ret;
1131 if (size != e->extnValue.length) {
1132 free_ProxyCertInfo(&info);
1133 hx509_clear_error_string(context);
1134 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1136 if (rinfo == NULL)
1137 free_ProxyCertInfo(&info);
1138 else
1139 *rinfo = info;
1141 return 0;
1145 * Path operations are like MEMORY based keyset, but with exposed
1146 * internal so we can do easy searches.
1150 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1152 hx509_cert *val;
1153 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1154 if (val == NULL) {
1155 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1156 return ENOMEM;
1159 path->val = val;
1160 path->val[path->len] = hx509_cert_ref(cert);
1161 path->len++;
1163 return 0;
1166 void
1167 _hx509_path_free(hx509_path *path)
1169 unsigned i;
1171 for (i = 0; i < path->len; i++)
1172 hx509_cert_free(path->val[i]);
1173 free(path->val);
1174 path->val = NULL;
1175 path->len = 0;
1179 * Find path by looking up issuer for the top certificate and continue
1180 * until an anchor certificate is found or max limit is found. A
1181 * certificate never included twice in the path.
1183 * If the trust anchors are not given, calculate optimistic path, just
1184 * follow the chain upward until we no longer find a parent or we hit
1185 * the max path limit. In this case, a failure will always be returned
1186 * depending on what error condition is hit first.
1188 * The path includes a path from the top certificate to the anchor
1189 * certificate.
1191 * The caller needs to free `path´ both on successful built path and
1192 * failure.
1196 _hx509_calculate_path(hx509_context context,
1197 int flags,
1198 time_t time_now,
1199 hx509_certs anchors,
1200 unsigned int max_depth,
1201 hx509_cert cert,
1202 hx509_certs pool,
1203 hx509_path *path)
1205 hx509_cert parent, current;
1206 int ret;
1208 if (max_depth == 0)
1209 max_depth = HX509_VERIFY_MAX_DEPTH;
1211 ret = _hx509_path_append(context, path, cert);
1212 if (ret)
1213 return ret;
1215 current = hx509_cert_ref(cert);
1217 while (!certificate_is_anchor(context, anchors, current)) {
1219 ret = find_parent(context, time_now, anchors, path,
1220 pool, current, &parent);
1221 hx509_cert_free(current);
1222 if (ret)
1223 return ret;
1225 ret = _hx509_path_append(context, path, parent);
1226 if (ret)
1227 return ret;
1228 current = parent;
1230 if (path->len > max_depth) {
1231 hx509_cert_free(current);
1232 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1233 "Path too long while bulding "
1234 "certificate chain");
1235 return HX509_PATH_TOO_LONG;
1239 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1240 path->len > 0 &&
1241 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1243 hx509_cert_free(path->val[path->len - 1]);
1244 path->len--;
1247 hx509_cert_free(current);
1248 return 0;
1252 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1253 const AlgorithmIdentifier *q)
1255 int diff;
1256 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1257 if (diff)
1258 return diff;
1259 if (p->parameters) {
1260 if (q->parameters)
1261 return heim_any_cmp(p->parameters,
1262 q->parameters);
1263 else
1264 return 1;
1265 } else {
1266 if (q->parameters)
1267 return -1;
1268 else
1269 return 0;
1274 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1276 int diff;
1277 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1278 if (diff)
1279 return diff;
1280 diff = _hx509_aAlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1281 &q->signatureAlgorithm);
1282 if (diff)
1283 return diff;
1284 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1285 &q->tbsCertificate._save);
1286 return diff;
1290 * Compare to hx509 certificate object, useful for sorting.
1292 * @param p a hx509 certificate object.
1293 * @param q a hx509 certificate object.
1295 * @return 0 the objects are the same, returns > 0 is p is "larger"
1296 * then q, < 0 if p is "smaller" then q.
1298 * @ingroup hx509_cert
1302 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1304 return _hx509_Certificate_cmp(p->data, q->data);
1308 * Return the name of the issuer of the hx509 certificate.
1310 * @param p a hx509 certificate object.
1311 * @param name a pointer to a hx509 name, should be freed by
1312 * hx509_name_free().
1314 * @return An hx509 error code, see hx509_get_error_string().
1316 * @ingroup hx509_cert
1320 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1322 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1326 * Return the name of the subject of the hx509 certificate.
1328 * @param p a hx509 certificate object.
1329 * @param name a pointer to a hx509 name, should be freed by
1330 * hx509_name_free(). See also hx509_cert_get_base_subject().
1332 * @return An hx509 error code, see hx509_get_error_string().
1334 * @ingroup hx509_cert
1338 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1340 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1344 * Return the name of the base subject of the hx509 certificate. If
1345 * the certiicate is a verified proxy certificate, the this function
1346 * return the base certificate (root of the proxy chain). If the proxy
1347 * certificate is not verified with the base certificate
1348 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1350 * @param context a hx509 context.
1351 * @param c a hx509 certificate object.
1352 * @param name a pointer to a hx509 name, should be freed by
1353 * hx509_name_free(). See also hx509_cert_get_subject().
1355 * @return An hx509 error code, see hx509_get_error_string().
1357 * @ingroup hx509_cert
1361 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1362 hx509_name *name)
1364 if (c->basename)
1365 return hx509_name_copy(context, c->basename, name);
1366 if (is_proxy_cert(context, c->data, NULL) == 0) {
1367 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1368 hx509_set_error_string(context, 0, ret,
1369 "Proxy certificate have not been "
1370 "canonicalize yet, no base name");
1371 return ret;
1373 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1377 * Get serial number of the certificate.
1379 * @param p a hx509 certificate object.
1380 * @param i serial number, should be freed ith der_free_heim_integer().
1382 * @return An hx509 error code, see hx509_get_error_string().
1384 * @ingroup hx509_cert
1388 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1390 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1394 * Get notBefore time of the certificate.
1396 * @param p a hx509 certificate object.
1398 * @return return not before time
1400 * @ingroup hx509_cert
1403 time_t
1404 hx509_cert_get_notBefore(hx509_cert p)
1406 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1410 * Get notAfter time of the certificate.
1412 * @param p a hx509 certificate object.
1414 * @return return not after time.
1416 * @ingroup hx509_cert
1419 time_t
1420 hx509_cert_get_notAfter(hx509_cert p)
1422 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1426 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1428 * @param context a hx509 context.
1429 * @param p a hx509 certificate object.
1430 * @param spki SubjectPublicKeyInfo, should be freed with
1431 * free_SubjectPublicKeyInfo().
1433 * @return An hx509 error code, see hx509_get_error_string().
1435 * @ingroup hx509_cert
1439 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1441 int ret;
1443 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1444 if (ret)
1445 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1446 return ret;
1450 * Get the AlgorithmIdentifier from the hx509 certificate.
1452 * @param context a hx509 context.
1453 * @param p a hx509 certificate object.
1454 * @param alg AlgorithmIdentifier, should be freed with
1455 * free_AlgorithmIdentifier().
1457 * @return An hx509 error code, see hx509_get_error_string().
1459 * @ingroup hx509_cert
1463 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1464 hx509_cert p,
1465 AlgorithmIdentifier *alg)
1467 int ret;
1469 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1470 if (ret)
1471 hx509_set_error_string(context, 0, ret,
1472 "Failed to copy SPKI AlgorithmIdentifier");
1473 return ret;
1477 hx509_private_key
1478 _hx509_cert_private_key(hx509_cert p)
1480 return p->private_key;
1484 hx509_cert_have_private_key(hx509_cert p)
1486 return p->private_key ? 1 : 0;
1491 _hx509_cert_private_key_exportable(hx509_cert p)
1493 if (p->private_key == NULL)
1494 return 0;
1495 return _hx509_private_key_exportable(p->private_key);
1499 _hx509_cert_private_decrypt(hx509_context context,
1500 const heim_octet_string *ciphertext,
1501 const heim_oid *encryption_oid,
1502 hx509_cert p,
1503 heim_octet_string *cleartext)
1505 cleartext->data = NULL;
1506 cleartext->length = 0;
1508 if (p->private_key == NULL) {
1509 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1510 "Private key missing");
1511 return HX509_PRIVATE_KEY_MISSING;
1514 return _hx509_private_key_private_decrypt(context,
1515 ciphertext,
1516 encryption_oid,
1517 p->private_key,
1518 cleartext);
1522 _hx509_cert_public_encrypt(hx509_context context,
1523 const heim_octet_string *cleartext,
1524 const hx509_cert p,
1525 heim_oid *encryption_oid,
1526 heim_octet_string *ciphertext)
1528 return _hx509_public_encrypt(context,
1529 cleartext, p->data,
1530 encryption_oid, ciphertext);
1537 time_t
1538 _hx509_Time2time_t(const Time *t)
1540 switch(t->element) {
1541 case choice_Time_utcTime:
1542 return t->u.utcTime;
1543 case choice_Time_generalTime:
1544 return t->u.generalTime;
1546 return 0;
1553 static int
1554 init_name_constraints(hx509_name_constraints *nc)
1556 memset(nc, 0, sizeof(*nc));
1557 return 0;
1560 static int
1561 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1562 hx509_name_constraints *nc)
1564 NameConstraints tnc;
1565 int ret;
1567 ret = find_extension_name_constraints(c, &tnc);
1568 if (ret == HX509_EXTENSION_NOT_FOUND)
1569 return 0;
1570 else if (ret) {
1571 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1572 return ret;
1573 } else if (not_ca) {
1574 ret = HX509_VERIFY_CONSTRAINTS;
1575 hx509_set_error_string(context, 0, ret, "Not a CA and "
1576 "have NameConstraints");
1577 } else {
1578 NameConstraints *val;
1579 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1580 if (val == NULL) {
1581 hx509_clear_error_string(context);
1582 ret = ENOMEM;
1583 goto out;
1585 nc->val = val;
1586 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1587 if (ret) {
1588 hx509_clear_error_string(context);
1589 goto out;
1591 nc->len += 1;
1593 out:
1594 free_NameConstraints(&tnc);
1595 return ret;
1598 static int
1599 match_RDN(const RelativeDistinguishedName *c,
1600 const RelativeDistinguishedName *n)
1602 int i;
1604 if (c->len != n->len)
1605 return HX509_NAME_CONSTRAINT_ERROR;
1607 for (i = 0; i < n->len; i++) {
1608 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1609 return HX509_NAME_CONSTRAINT_ERROR;
1610 if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0)
1611 return HX509_NAME_CONSTRAINT_ERROR;
1613 return 0;
1616 static int
1617 match_X501Name(const Name *c, const Name *n)
1619 int i, ret;
1621 if (c->element != choice_Name_rdnSequence
1622 || n->element != choice_Name_rdnSequence)
1623 return 0;
1624 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1625 return HX509_NAME_CONSTRAINT_ERROR;
1626 for (i = 0; i < c->u.rdnSequence.len; i++) {
1627 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1628 if (ret)
1629 return ret;
1631 return 0;
1635 static int
1636 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1639 * Name constraints only apply to the same name type, see RFC3280,
1640 * 4.2.1.11.
1642 assert(c->element == n->element);
1644 switch(c->element) {
1645 case choice_GeneralName_otherName:
1646 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1647 &n->u.otherName.type_id) != 0)
1648 return HX509_NAME_CONSTRAINT_ERROR;
1649 if (heim_any_cmp(&c->u.otherName.value,
1650 &n->u.otherName.value) != 0)
1651 return HX509_NAME_CONSTRAINT_ERROR;
1652 *match = 1;
1653 return 0;
1654 case choice_GeneralName_rfc822Name: {
1655 const char *s;
1656 size_t len1, len2;
1657 s = strchr(c->u.rfc822Name, '@');
1658 if (s) {
1659 if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1660 return HX509_NAME_CONSTRAINT_ERROR;
1661 } else {
1662 s = strchr(n->u.rfc822Name, '@');
1663 if (s == NULL)
1664 return HX509_NAME_CONSTRAINT_ERROR;
1665 len1 = strlen(c->u.rfc822Name);
1666 len2 = strlen(s + 1);
1667 if (len1 > len2)
1668 return HX509_NAME_CONSTRAINT_ERROR;
1669 if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1670 return HX509_NAME_CONSTRAINT_ERROR;
1671 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1672 return HX509_NAME_CONSTRAINT_ERROR;
1674 *match = 1;
1675 return 0;
1677 case choice_GeneralName_dNSName: {
1678 size_t lenc, lenn;
1680 lenc = strlen(c->u.dNSName);
1681 lenn = strlen(n->u.dNSName);
1682 if (lenc > lenn)
1683 return HX509_NAME_CONSTRAINT_ERROR;
1684 if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1685 return HX509_NAME_CONSTRAINT_ERROR;
1686 if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1687 return HX509_NAME_CONSTRAINT_ERROR;
1688 *match = 1;
1689 return 0;
1691 case choice_GeneralName_directoryName: {
1692 Name c_name, n_name;
1693 int ret;
1695 c_name._save.data = NULL;
1696 c_name._save.length = 0;
1697 c_name.element = c->u.directoryName.element;
1698 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1700 n_name._save.data = NULL;
1701 n_name._save.length = 0;
1702 n_name.element = n->u.directoryName.element;
1703 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1705 ret = match_X501Name(&c_name, &n_name);
1706 if (ret == 0)
1707 *match = 1;
1708 return ret;
1710 case choice_GeneralName_uniformResourceIdentifier:
1711 case choice_GeneralName_iPAddress:
1712 case choice_GeneralName_registeredID:
1713 default:
1714 return HX509_NAME_CONSTRAINT_ERROR;
1718 static int
1719 match_alt_name(const GeneralName *n, const Certificate *c,
1720 int *same, int *match)
1722 GeneralNames sa;
1723 int ret, i, j;
1725 i = 0;
1726 do {
1727 ret = find_extension_subject_alt_name(c, &i, &sa);
1728 if (ret == HX509_EXTENSION_NOT_FOUND) {
1729 ret = 0;
1730 break;
1731 } else if (ret != 0)
1732 break;
1734 for (j = 0; j < sa.len; j++) {
1735 if (n->element == sa.val[j].element) {
1736 *same = 1;
1737 ret = match_general_name(n, &sa.val[j], match);
1740 free_GeneralNames(&sa);
1741 } while (1);
1742 return ret;
1746 static int
1747 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1749 int name, alt_name, same;
1750 unsigned int i;
1751 int ret = 0;
1753 name = alt_name = same = *match = 0;
1754 for (i = 0; i < t->len; i++) {
1755 if (t->val[i].minimum && t->val[i].maximum)
1756 return HX509_RANGE;
1759 * If the constraint apply to directoryNames, test is with
1760 * subjectName of the certificate if the certificate have a
1761 * non-null (empty) subjectName.
1764 if (t->val[i].base.element == choice_GeneralName_directoryName
1765 && !subject_null_p(c))
1767 GeneralName certname;
1769 memset(&certname, 0, sizeof(certname));
1770 certname.element = choice_GeneralName_directoryName;
1771 certname.u.directoryName.element =
1772 c->tbsCertificate.subject.element;
1773 certname.u.directoryName.u.rdnSequence =
1774 c->tbsCertificate.subject.u.rdnSequence;
1776 ret = match_general_name(&t->val[i].base, &certname, &name);
1779 /* Handle subjectAltNames, this is icky since they
1780 * restrictions only apply if the subjectAltName is of the
1781 * same type. So if there have been a match of type, require
1782 * altname to be set.
1784 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1786 if (name && (!same || alt_name))
1787 *match = 1;
1788 return ret;
1791 static int
1792 check_name_constraints(hx509_context context,
1793 const hx509_name_constraints *nc,
1794 const Certificate *c)
1796 int match, ret;
1797 int i;
1799 for (i = 0 ; i < nc->len; i++) {
1800 GeneralSubtrees gs;
1802 if (nc->val[i].permittedSubtrees) {
1803 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1804 ret = match_tree(&gs, c, &match);
1805 if (ret) {
1806 hx509_clear_error_string(context);
1807 return ret;
1809 /* allow null subjectNames, they wont matches anything */
1810 if (match == 0 && !subject_null_p(c)) {
1811 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1812 "Error verify constraints, "
1813 "certificate didn't match any "
1814 "permitted subtree");
1815 return HX509_VERIFY_CONSTRAINTS;
1818 if (nc->val[i].excludedSubtrees) {
1819 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1820 ret = match_tree(&gs, c, &match);
1821 if (ret) {
1822 hx509_clear_error_string(context);
1823 return ret;
1825 if (match) {
1826 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1827 "Error verify constraints, "
1828 "certificate included in excluded "
1829 "subtree");
1830 return HX509_VERIFY_CONSTRAINTS;
1834 return 0;
1837 static void
1838 free_name_constraints(hx509_name_constraints *nc)
1840 int i;
1842 for (i = 0 ; i < nc->len; i++)
1843 free_NameConstraints(&nc->val[i]);
1844 free(nc->val);
1848 * Build and verify the path for the certificate to the trust anchor
1849 * specified in the verify context. The path is constructed from the
1850 * certificate, the pool and the trust anchors.
1852 * @param context A hx509 context.
1853 * @param ctx A hx509 verification context.
1854 * @param cert the certificate to build the path from.
1855 * @param pool A keyset of certificates to build the chain from.
1857 * @return An hx509 error code, see hx509_get_error_string().
1859 * @ingroup hx509_verify
1863 hx509_verify_path(hx509_context context,
1864 hx509_verify_ctx ctx,
1865 hx509_cert cert,
1866 hx509_certs pool)
1868 hx509_name_constraints nc;
1869 hx509_path path;
1870 #if 0
1871 const AlgorithmIdentifier *alg_id;
1872 #endif
1873 int ret, i, proxy_cert_depth, selfsigned_depth;
1874 enum certtype type;
1875 Name proxy_issuer;
1876 hx509_certs anchors = NULL;
1878 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1880 ret = init_name_constraints(&nc);
1881 if (ret)
1882 return ret;
1884 path.val = NULL;
1885 path.len = 0;
1887 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1888 ctx->time_now = time(NULL);
1893 if (ctx->trust_anchors)
1894 anchors = _hx509_certs_ref(ctx->trust_anchors);
1895 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1896 anchors = _hx509_certs_ref(context->default_trust_anchors);
1897 else {
1898 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1899 if (ret)
1900 goto out;
1904 * Calculate the path from the certificate user presented to the
1905 * to an anchor.
1907 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1908 anchors, ctx->max_depth,
1909 cert, pool, &path);
1910 if (ret)
1911 goto out;
1913 #if 0
1914 alg_id = path.val[path->len - 1]->data->tbsCertificate.signature;
1915 #endif
1918 * Check CA and proxy certificate chain from the top of the
1919 * certificate chain. Also check certificate is valid with respect
1920 * to the current time.
1924 proxy_cert_depth = 0;
1925 selfsigned_depth = 0;
1927 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1928 type = PROXY_CERT;
1929 else
1930 type = EE_CERT;
1932 for (i = 0; i < path.len; i++) {
1933 Certificate *c;
1934 time_t t;
1936 c = _hx509_get_cert(path.val[i]);
1939 * Lets do some basic check on issuer like
1940 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1941 * on what type of certificate this is.
1944 switch (type) {
1945 case CA_CERT:
1946 /* XXX make constants for keyusage */
1947 ret = check_key_usage(context, c, 1 << 5,
1948 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1949 if (ret) {
1950 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1951 "Key usage missing from CA certificate");
1952 goto out;
1955 if (i + 1 != path.len && certificate_is_self_signed(c))
1956 selfsigned_depth++;
1958 break;
1959 case PROXY_CERT: {
1960 ProxyCertInfo info;
1962 if (is_proxy_cert(context, c, &info) == 0) {
1963 int j;
1965 if (info.pCPathLenConstraint != NULL &&
1966 *info.pCPathLenConstraint < i)
1968 free_ProxyCertInfo(&info);
1969 ret = HX509_PATH_TOO_LONG;
1970 hx509_set_error_string(context, 0, ret,
1971 "Proxy certificate chain "
1972 "longer then allowed");
1973 goto out;
1975 /* XXX MUST check info.proxyPolicy */
1976 free_ProxyCertInfo(&info);
1978 j = 0;
1979 if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
1980 ret = HX509_PROXY_CERT_INVALID;
1981 hx509_set_error_string(context, 0, ret,
1982 "Proxy certificate have explicity "
1983 "forbidden subjectAltName");
1984 goto out;
1987 j = 0;
1988 if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
1989 ret = HX509_PROXY_CERT_INVALID;
1990 hx509_set_error_string(context, 0, ret,
1991 "Proxy certificate have explicity "
1992 "forbidden issuerAltName");
1993 goto out;
1997 * The subject name of the proxy certificate should be
1998 * CN=XXX,<proxy issuer>, prune of CN and check if its
1999 * the same over the whole chain of proxy certs and
2000 * then check with the EE cert when we get to it.
2003 if (proxy_cert_depth) {
2004 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject);
2005 if (ret) {
2006 ret = HX509_PROXY_CERT_NAME_WRONG;
2007 hx509_set_error_string(context, 0, ret,
2008 "Base proxy name not right");
2009 goto out;
2013 free_Name(&proxy_issuer);
2015 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2016 if (ret) {
2017 hx509_clear_error_string(context);
2018 goto out;
2021 j = proxy_issuer.u.rdnSequence.len;
2022 if (proxy_issuer.u.rdnSequence.len < 2
2023 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2024 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2025 oid_id_at_commonName()))
2027 ret = HX509_PROXY_CERT_NAME_WRONG;
2028 hx509_set_error_string(context, 0, ret,
2029 "Proxy name too short or "
2030 "does not have Common name "
2031 "at the top");
2032 goto out;
2035 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2036 proxy_issuer.u.rdnSequence.len -= 1;
2038 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer);
2039 if (ret != 0) {
2040 ret = HX509_PROXY_CERT_NAME_WRONG;
2041 hx509_set_error_string(context, 0, ret,
2042 "Proxy issuer name not as expected");
2043 goto out;
2046 break;
2047 } else {
2049 * Now we are done with the proxy certificates, this
2050 * cert was an EE cert and we we will fall though to
2051 * EE checking below.
2053 type = EE_CERT;
2054 /* FALLTHOUGH */
2057 case EE_CERT:
2059 * If there where any proxy certificates in the chain
2060 * (proxy_cert_depth > 0), check that the proxy issuer
2061 * matched proxy certificates "base" subject.
2063 if (proxy_cert_depth) {
2065 ret = _hx509_name_cmp(&proxy_issuer,
2066 &c->tbsCertificate.subject);
2067 if (ret) {
2068 ret = HX509_PROXY_CERT_NAME_WRONG;
2069 hx509_clear_error_string(context);
2070 goto out;
2072 if (cert->basename)
2073 hx509_name_free(&cert->basename);
2075 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2076 if (ret) {
2077 hx509_clear_error_string(context);
2078 goto out;
2082 break;
2085 ret = check_basic_constraints(context, c, type,
2086 i - proxy_cert_depth - selfsigned_depth);
2087 if (ret)
2088 goto out;
2091 * Don't check the trust anchors expiration time since they
2092 * are transported out of band, from RFC3820.
2094 if (i + 1 != path.len || CHECK_TA(ctx)) {
2096 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2097 if (t > ctx->time_now) {
2098 ret = HX509_CERT_USED_BEFORE_TIME;
2099 hx509_clear_error_string(context);
2100 goto out;
2102 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2103 if (t < ctx->time_now) {
2104 ret = HX509_CERT_USED_AFTER_TIME;
2105 hx509_clear_error_string(context);
2106 goto out;
2110 if (type == EE_CERT)
2111 type = CA_CERT;
2112 else if (type == PROXY_CERT)
2113 proxy_cert_depth++;
2117 * Verify constraints, do this backward so path constraints are
2118 * checked in the right order.
2121 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2122 Certificate *c;
2124 c = _hx509_get_cert(path.val[i]);
2126 /* verify name constraints, not for selfsigned and anchor */
2127 if (!certificate_is_self_signed(c) || i + 1 != path.len) {
2128 ret = check_name_constraints(context, &nc, c);
2129 if (ret) {
2130 goto out;
2133 ret = add_name_constraints(context, c, i == 0, &nc);
2134 if (ret)
2135 goto out;
2137 /* XXX verify all other silly constraints */
2142 * Verify that no certificates has been revoked.
2145 if (ctx->revoke_ctx) {
2146 hx509_certs certs;
2148 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2149 NULL, &certs);
2150 if (ret)
2151 goto out;
2153 for (i = 0; i < path.len; i++) {
2154 ret = hx509_certs_add(context, certs, path.val[i]);
2155 if (ret) {
2156 hx509_certs_free(&certs);
2157 goto out;
2160 ret = hx509_certs_merge(context, certs, pool);
2161 if (ret) {
2162 hx509_certs_free(&certs);
2163 goto out;
2166 for (i = 0; i < path.len - 1; i++) {
2167 int parent = (i < path.len - 1) ? i + 1 : i;
2169 ret = hx509_revoke_verify(context,
2170 ctx->revoke_ctx,
2171 certs,
2172 ctx->time_now,
2173 path.val[i],
2174 path.val[parent]);
2175 if (ret) {
2176 hx509_certs_free(&certs);
2177 goto out;
2180 hx509_certs_free(&certs);
2184 * Verify signatures, do this backward so public key working
2185 * parameter is passed up from the anchor up though the chain.
2188 for (i = path.len - 1; i >= 0; i--) {
2189 Certificate *signer, *c;
2191 c = _hx509_get_cert(path.val[i]);
2193 /* is last in chain (trust anchor) */
2194 if (i + 1 == path.len) {
2195 signer = path.val[i]->data;
2197 /* if trust anchor is not self signed, don't check sig */
2198 if (!certificate_is_self_signed(signer))
2199 continue;
2200 } else {
2201 /* take next certificate in chain */
2202 signer = path.val[i + 1]->data;
2205 /* verify signatureValue */
2206 ret = _hx509_verify_signature_bitstring(context,
2207 signer,
2208 &c->signatureAlgorithm,
2209 &c->tbsCertificate._save,
2210 &c->signatureValue);
2211 if (ret) {
2212 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2213 "Failed to verify signature of certificate");
2214 goto out;
2218 out:
2219 hx509_certs_free(&anchors);
2220 free_Name(&proxy_issuer);
2221 free_name_constraints(&nc);
2222 _hx509_path_free(&path);
2224 return ret;
2228 * Verify a signature made using the private key of an certificate.
2230 * @param context A hx509 context.
2231 * @param signer the certificate that made the signature.
2232 * @param alg algorthm that was used to sign the data.
2233 * @param data the data that was signed.
2234 * @param sig the sigature to verify.
2236 * @return An hx509 error code, see hx509_get_error_string().
2238 * @ingroup hx509_crypto
2242 hx509_verify_signature(hx509_context context,
2243 const hx509_cert signer,
2244 const AlgorithmIdentifier *alg,
2245 const heim_octet_string *data,
2246 const heim_octet_string *sig)
2248 return _hx509_verify_signature(context, signer->data, alg, data, sig);
2253 * Verify that the certificate is allowed to be used for the hostname
2254 * and address.
2256 * @param context A hx509 context.
2257 * @param cert the certificate to match with
2258 * @param flags Flags to modify the behavior:
2259 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2260 * @param type type of hostname:
2261 * - HX509_HN_HOSTNAME for plain hostname.
2262 * - HX509_HN_DNSSRV for DNS SRV names.
2263 * @param hostname the hostname to check
2264 * @param sa address of the host
2265 * @param sa_size length of address
2267 * @return An hx509 error code, see hx509_get_error_string().
2269 * @ingroup hx509_cert
2273 hx509_verify_hostname(hx509_context context,
2274 const hx509_cert cert,
2275 int flags,
2276 hx509_hostname_type type,
2277 const char *hostname,
2278 const struct sockaddr *sa,
2279 /* XXX krb5_socklen_t */ int sa_size)
2281 GeneralNames san;
2282 int ret, i, j;
2284 if (sa && sa_size <= 0)
2285 return EINVAL;
2287 memset(&san, 0, sizeof(san));
2289 i = 0;
2290 do {
2291 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2292 if (ret == HX509_EXTENSION_NOT_FOUND) {
2293 ret = 0;
2294 break;
2295 } else if (ret != 0)
2296 break;
2298 for (j = 0; j < san.len; j++) {
2299 switch (san.val[j].element) {
2300 case choice_GeneralName_dNSName:
2301 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2302 free_GeneralNames(&san);
2303 return 0;
2305 break;
2306 default:
2307 break;
2310 free_GeneralNames(&san);
2311 } while (1);
2314 Name *name = &cert->data->tbsCertificate.subject;
2316 /* match if first component is a CN= */
2317 if (name->u.rdnSequence.len > 0
2318 && name->u.rdnSequence.val[0].len == 1
2319 && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
2320 oid_id_at_commonName()) == 0)
2322 DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
2324 switch (ds->element) {
2325 case choice_DirectoryString_printableString:
2326 if (strcasecmp(ds->u.printableString, hostname) == 0)
2327 return 0;
2328 break;
2329 case choice_DirectoryString_ia5String:
2330 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2331 return 0;
2332 break;
2333 case choice_DirectoryString_utf8String:
2334 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2335 return 0;
2336 default:
2337 break;
2342 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2343 ret = HX509_NAME_CONSTRAINT_ERROR;
2345 return ret;
2349 _hx509_set_cert_attribute(hx509_context context,
2350 hx509_cert cert,
2351 const heim_oid *oid,
2352 const heim_octet_string *attr)
2354 hx509_cert_attribute a;
2355 void *d;
2357 if (hx509_cert_get_attribute(cert, oid) != NULL)
2358 return 0;
2360 d = realloc(cert->attrs.val,
2361 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2362 if (d == NULL) {
2363 hx509_clear_error_string(context);
2364 return ENOMEM;
2366 cert->attrs.val = d;
2368 a = malloc(sizeof(*a));
2369 if (a == NULL)
2370 return ENOMEM;
2372 der_copy_octet_string(attr, &a->data);
2373 der_copy_oid(oid, &a->oid);
2375 cert->attrs.val[cert->attrs.len] = a;
2376 cert->attrs.len++;
2378 return 0;
2382 * Get an external attribute for the certificate, examples are
2383 * friendly name and id.
2385 * @param cert hx509 certificate object to search
2386 * @param oid an oid to search for.
2388 * @return an hx509_cert_attribute, only valid as long as the
2389 * certificate is referenced.
2391 * @ingroup hx509_cert
2394 hx509_cert_attribute
2395 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2397 int i;
2398 for (i = 0; i < cert->attrs.len; i++)
2399 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2400 return cert->attrs.val[i];
2401 return NULL;
2405 * Set the friendly name on the certificate.
2407 * @param cert The certificate to set the friendly name on
2408 * @param name Friendly name.
2410 * @return An hx509 error code, see hx509_get_error_string().
2412 * @ingroup hx509_cert
2416 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2418 if (cert->friendlyname)
2419 free(cert->friendlyname);
2420 cert->friendlyname = strdup(name);
2421 if (cert->friendlyname == NULL)
2422 return ENOMEM;
2423 return 0;
2427 * Get friendly name of the certificate.
2429 * @param cert cert to get the friendly name from.
2431 * @return an friendly name or NULL if there is. The friendly name is
2432 * only valid as long as the certificate is referenced.
2434 * @ingroup hx509_cert
2437 const char *
2438 hx509_cert_get_friendly_name(hx509_cert cert)
2440 hx509_cert_attribute a;
2441 PKCS9_friendlyName n;
2442 size_t sz;
2443 int ret, i;
2445 if (cert->friendlyname)
2446 return cert->friendlyname;
2448 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
2449 if (a == NULL) {
2450 /* XXX use subject name ? */
2451 return NULL;
2454 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2455 if (ret)
2456 return NULL;
2458 if (n.len != 1) {
2459 free_PKCS9_friendlyName(&n);
2460 return NULL;
2463 cert->friendlyname = malloc(n.val[0].length + 1);
2464 if (cert->friendlyname == NULL) {
2465 free_PKCS9_friendlyName(&n);
2466 return NULL;
2469 for (i = 0; i < n.val[0].length; i++) {
2470 if (n.val[0].data[i] <= 0xff)
2471 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2472 else
2473 cert->friendlyname[i] = 'X';
2475 cert->friendlyname[i] = '\0';
2476 free_PKCS9_friendlyName(&n);
2478 return cert->friendlyname;
2481 void
2482 _hx509_query_clear(hx509_query *q)
2484 memset(q, 0, sizeof(*q));
2488 * Allocate an query controller. Free using hx509_query_free().
2490 * @param context A hx509 context.
2491 * @param q return pointer to a hx509_query.
2493 * @return An hx509 error code, see hx509_get_error_string().
2495 * @ingroup hx509_cert
2499 hx509_query_alloc(hx509_context context, hx509_query **q)
2501 *q = calloc(1, sizeof(**q));
2502 if (*q == NULL)
2503 return ENOMEM;
2504 return 0;
2508 * Set match options for the hx509 query controller.
2510 * @param q query controller.
2511 * @param option options to control the query controller.
2513 * @return An hx509 error code, see hx509_get_error_string().
2515 * @ingroup hx509_cert
2518 void
2519 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2521 switch(option) {
2522 case HX509_QUERY_OPTION_PRIVATE_KEY:
2523 q->match |= HX509_QUERY_PRIVATE_KEY;
2524 break;
2525 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2526 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2527 break;
2528 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2529 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2530 break;
2531 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2532 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2533 break;
2534 case HX509_QUERY_OPTION_END:
2535 default:
2536 break;
2541 * Set the issuer and serial number of match in the query
2542 * controller. The function make copies of the isser and serial number.
2544 * @param q a hx509 query controller
2545 * @param issuer issuer to search for
2546 * @param serialNumber the serialNumber of the issuer.
2548 * @return An hx509 error code, see hx509_get_error_string().
2550 * @ingroup hx509_cert
2554 hx509_query_match_issuer_serial(hx509_query *q,
2555 const Name *issuer,
2556 const heim_integer *serialNumber)
2558 int ret;
2559 if (q->serial) {
2560 der_free_heim_integer(q->serial);
2561 free(q->serial);
2563 q->serial = malloc(sizeof(*q->serial));
2564 if (q->serial == NULL)
2565 return ENOMEM;
2566 ret = der_copy_heim_integer(serialNumber, q->serial);
2567 if (ret) {
2568 free(q->serial);
2569 q->serial = NULL;
2570 return ret;
2572 if (q->issuer_name) {
2573 free_Name(q->issuer_name);
2574 free(q->issuer_name);
2576 q->issuer_name = malloc(sizeof(*q->issuer_name));
2577 if (q->issuer_name == NULL)
2578 return ENOMEM;
2579 ret = copy_Name(issuer, q->issuer_name);
2580 if (ret) {
2581 free(q->issuer_name);
2582 q->issuer_name = NULL;
2583 return ret;
2585 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2586 return 0;
2590 * Set the query controller to match on a friendly name
2592 * @param q a hx509 query controller.
2593 * @param name a friendly name to match on
2595 * @return An hx509 error code, see hx509_get_error_string().
2597 * @ingroup hx509_cert
2601 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2603 if (q->friendlyname)
2604 free(q->friendlyname);
2605 q->friendlyname = strdup(name);
2606 if (q->friendlyname == NULL)
2607 return ENOMEM;
2608 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2609 return 0;
2613 * Set the query controller to match using a specific match function.
2615 * @param q a hx509 query controller.
2616 * @param func function to use for matching, if the argument is NULL,
2617 * the match function is removed.
2618 * @param ctx context passed to the function.
2620 * @return An hx509 error code, see hx509_get_error_string().
2622 * @ingroup hx509_cert
2626 hx509_query_match_cmp_func(hx509_query *q,
2627 int (*func)(void *, hx509_cert),
2628 void *ctx)
2630 if (func)
2631 q->match |= HX509_QUERY_MATCH_FUNCTION;
2632 else
2633 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2634 q->cmp_func = func;
2635 q->cmp_func_ctx = ctx;
2636 return 0;
2640 * Free the query controller.
2642 * @param context A hx509 context.
2643 * @param q a pointer to the query controller.
2645 * @ingroup hx509_cert
2648 void
2649 hx509_query_free(hx509_context context, hx509_query *q)
2651 if (q->serial) {
2652 der_free_heim_integer(q->serial);
2653 free(q->serial);
2654 q->serial = NULL;
2656 if (q->issuer_name) {
2657 free_Name(q->issuer_name);
2658 free(q->issuer_name);
2659 q->issuer_name = NULL;
2661 if (q) {
2662 free(q->friendlyname);
2663 memset(q, 0, sizeof(*q));
2665 free(q);
2669 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2671 Certificate *c = _hx509_get_cert(cert);
2673 _hx509_query_statistic(context, 1, q);
2675 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2676 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2677 return 0;
2679 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2680 _hx509_Certificate_cmp(q->certificate, c) != 0)
2681 return 0;
2683 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2684 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2685 return 0;
2687 if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
2688 && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
2689 return 0;
2691 if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
2692 && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
2693 return 0;
2695 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2696 SubjectKeyIdentifier si;
2697 int ret;
2699 ret = _hx509_find_extension_subject_key_id(c, &si);
2700 if (ret == 0) {
2701 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2702 ret = 1;
2703 free_SubjectKeyIdentifier(&si);
2705 if (ret)
2706 return 0;
2708 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2709 return 0;
2710 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2711 _hx509_cert_private_key(cert) == NULL)
2712 return 0;
2715 unsigned ku = 0;
2716 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2717 ku |= (1 << 0);
2718 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2719 ku |= (1 << 1);
2720 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2721 ku |= (1 << 2);
2722 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2723 ku |= (1 << 3);
2724 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2725 ku |= (1 << 4);
2726 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2727 ku |= (1 << 5);
2728 if (q->match & HX509_QUERY_KU_CRLSIGN)
2729 ku |= (1 << 6);
2730 if (ku && check_key_usage(context, c, ku, TRUE))
2731 return 0;
2733 if ((q->match & HX509_QUERY_ANCHOR))
2734 return 0;
2736 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2737 hx509_cert_attribute a;
2739 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2740 if (a == NULL)
2741 return 0;
2742 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2743 return 0;
2746 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2747 size_t i;
2749 for (i = 0; i < q->path->len; i++)
2750 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2751 return 0;
2753 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2754 const char *name = hx509_cert_get_friendly_name(cert);
2755 if (name == NULL)
2756 return 0;
2757 if (strcasecmp(q->friendlyname, name) != 0)
2758 return 0;
2760 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2761 int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2762 if (ret != 0)
2763 return 0;
2766 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2767 heim_octet_string os;
2768 int ret;
2770 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2771 os.length =
2772 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2774 ret = _hx509_verify_signature(context,
2775 NULL,
2776 hx509_signature_sha1(),
2777 &os,
2778 q->keyhash_sha1);
2779 if (ret != 0)
2780 return 0;
2783 if (q->match & HX509_QUERY_MATCH_TIME) {
2784 time_t t;
2785 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2786 if (t > q->timenow)
2787 return 0;
2788 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2789 if (t < q->timenow)
2790 return 0;
2793 if (q->match & ~HX509_QUERY_MASK)
2794 return 0;
2796 return 1;
2800 * Set a statistic file for the query statistics.
2802 * @param context A hx509 context.
2803 * @param fn statistics file name
2805 * @ingroup hx509_cert
2808 void
2809 hx509_query_statistic_file(hx509_context context, const char *fn)
2811 if (context->querystat)
2812 free(context->querystat);
2813 context->querystat = strdup(fn);
2816 void
2817 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2819 FILE *f;
2820 if (context->querystat == NULL)
2821 return;
2822 f = fopen(context->querystat, "a");
2823 if (f == NULL)
2824 return;
2825 fprintf(f, "%d %d\n", type, q->match);
2826 fclose(f);
2829 static const char *statname[] = {
2830 "find issuer cert",
2831 "match serialnumber",
2832 "match issuer name",
2833 "match subject name",
2834 "match subject key id",
2835 "match issuer id",
2836 "private key",
2837 "ku encipherment",
2838 "ku digitalsignature",
2839 "ku keycertsign",
2840 "ku crlsign",
2841 "ku nonrepudiation",
2842 "ku keyagreement",
2843 "ku dataencipherment",
2844 "anchor",
2845 "match certificate",
2846 "match local key id",
2847 "no match path",
2848 "match friendly name",
2849 "match function",
2850 "match key hash sha1",
2851 "match time"
2854 struct stat_el {
2855 unsigned long stats;
2856 unsigned int index;
2860 static int
2861 stat_sort(const void *a, const void *b)
2863 const struct stat_el *ae = a;
2864 const struct stat_el *be = b;
2865 return be->stats - ae->stats;
2869 * Unparse the statistics file and print the result on a FILE descriptor.
2871 * @param context A hx509 context.
2872 * @param printtype tyep to print
2873 * @param out the FILE to write the data on.
2875 * @ingroup hx509_cert
2878 void
2879 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
2881 rtbl_t t;
2882 FILE *f;
2883 int type, mask, i, num;
2884 unsigned long multiqueries = 0, totalqueries = 0;
2885 struct stat_el stats[32];
2887 if (context->querystat == NULL)
2888 return;
2889 f = fopen(context->querystat, "r");
2890 if (f == NULL) {
2891 fprintf(out, "No statistic file %s: %s.\n",
2892 context->querystat, strerror(errno));
2893 return;
2896 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2897 stats[i].index = i;
2898 stats[i].stats = 0;
2901 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
2902 if (type != printtype)
2903 continue;
2904 num = i = 0;
2905 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
2906 if (mask & 1) {
2907 stats[i].stats++;
2908 num++;
2910 mask = mask >>1 ;
2911 i++;
2913 if (num > 1)
2914 multiqueries++;
2915 totalqueries++;
2917 fclose(f);
2919 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
2921 t = rtbl_create();
2922 if (t == NULL)
2923 errx(1, "out of memory");
2925 rtbl_set_separator (t, " ");
2927 rtbl_add_column_by_id (t, 0, "Name", 0);
2928 rtbl_add_column_by_id (t, 1, "Counter", 0);
2931 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2932 char str[10];
2934 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
2935 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
2936 else {
2937 snprintf(str, sizeof(str), "%d", stats[i].index);
2938 rtbl_add_column_entry_by_id (t, 0, str);
2940 snprintf(str, sizeof(str), "%lu", stats[i].stats);
2941 rtbl_add_column_entry_by_id (t, 1, str);
2944 rtbl_format(t, out);
2945 rtbl_destroy(t);
2947 fprintf(out, "\nQueries: multi %lu total %lu\n",
2948 multiqueries, totalqueries);
2952 * Check the extended key usage on the hx509 certificate.
2954 * @param context A hx509 context.
2955 * @param cert A hx509 context.
2956 * @param eku the EKU to check for
2957 * @param allow_any_eku if the any EKU is set, allow that to be a
2958 * substitute.
2960 * @return An hx509 error code, see hx509_get_error_string().
2962 * @ingroup hx509_cert
2966 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
2967 const heim_oid *eku, int allow_any_eku)
2969 ExtKeyUsage e;
2970 int ret, i;
2972 ret = find_extension_eku(_hx509_get_cert(cert), &e);
2973 if (ret) {
2974 hx509_clear_error_string(context);
2975 return ret;
2978 for (i = 0; i < e.len; i++) {
2979 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
2980 free_ExtKeyUsage(&e);
2981 return 0;
2983 if (allow_any_eku) {
2984 #if 0
2985 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
2986 free_ExtKeyUsage(&e);
2987 return 0;
2989 #endif
2992 free_ExtKeyUsage(&e);
2993 hx509_clear_error_string(context);
2994 return HX509_CERTIFICATE_MISSING_EKU;
2998 _hx509_cert_get_keyusage(hx509_context context,
2999 hx509_cert c,
3000 KeyUsage *ku)
3002 Certificate *cert;
3003 const Extension *e;
3004 size_t size;
3005 int ret, i = 0;
3007 memset(ku, 0, sizeof(*ku));
3009 cert = _hx509_get_cert(c);
3011 if (_hx509_cert_get_version(cert) < 3)
3012 return 0;
3014 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
3015 if (e == NULL)
3016 return HX509_KU_CERT_MISSING;
3018 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3019 if (ret)
3020 return ret;
3021 return 0;
3025 _hx509_cert_get_eku(hx509_context context,
3026 hx509_cert cert,
3027 ExtKeyUsage *e)
3029 int ret;
3031 memset(e, 0, sizeof(*e));
3033 ret = find_extension_eku(_hx509_get_cert(cert), e);
3034 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3035 hx509_clear_error_string(context);
3036 return ret;
3038 return 0;
3042 * Encodes the hx509 certificate as a DER encode binary.
3044 * @param context A hx509 context.
3045 * @param c the certificate to encode.
3046 * @param os the encode certificate, set to NULL, 0 on case of
3047 * error. Free the returned structure with hx509_xfree().
3049 * @return An hx509 error code, see hx509_get_error_string().
3051 * @ingroup hx509_cert
3055 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3057 size_t size;
3058 int ret;
3060 os->data = NULL;
3061 os->length = 0;
3063 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3064 _hx509_get_cert(c), &size, ret);
3065 if (ret) {
3066 os->data = NULL;
3067 os->length = 0;
3068 return ret;
3070 if (os->length != size)
3071 _hx509_abort("internal ASN.1 encoder error");
3073 return ret;
3077 * Last to avoid lost __attribute__s due to #undef.
3080 #undef __attribute__
3081 #define __attribute__(X)
3083 void
3084 _hx509_abort(const char *fmt, ...)
3085 __attribute__ ((noreturn, format (printf, 1, 2)))
3087 va_list ap;
3088 va_start(ap, fmt);
3089 vprintf(fmt, ap);
3090 va_end(ap);
3091 printf("\n");
3092 fflush(stdout);
3093 abort();
3097 * Free a data element allocated in the library.
3099 * @param ptr data to be freed.
3101 * @ingroup hx509_misc
3104 void
3105 hx509_xfree(void *ptr)
3107 free(ptr);