Sync usage with man page.
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / hx509 / cert.c
blob35bb302ad44895ee87902ca44ffde6750304bbfe
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("$Heimdal: cert.c 22450 2008-01-15 19:39:14Z lha $"
36 "$NetBSD$");
37 #include "crypto-headers.h"
38 #include <rtbl.h>
40 /**
41 * @page page_cert The basic certificate
43 * The basic hx509 cerificate object in hx509 is hx509_cert. The
44 * hx509_cert object is representing one X509/PKIX certificate and
45 * associated attributes; like private key, friendly name, etc.
47 * A hx509_cert object is usully found via the keyset interfaces (@ref
48 * page_keyset), but its also possible to create a certificate
49 * directly from a parsed object with hx509_cert_init() and
50 * hx509_cert_init_data().
52 * See the library functions here: @ref hx509_cert
55 struct hx509_verify_ctx_data {
56 hx509_certs trust_anchors;
57 int flags;
58 #define HX509_VERIFY_CTX_F_TIME_SET 1
59 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
60 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
61 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
62 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
63 time_t time_now;
64 unsigned int max_depth;
65 #define HX509_VERIFY_MAX_DEPTH 30
66 hx509_revoke_ctx revoke_ctx;
69 #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
70 #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
71 #define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
73 struct _hx509_cert_attrs {
74 size_t len;
75 hx509_cert_attribute *val;
78 struct hx509_cert_data {
79 unsigned int ref;
80 char *friendlyname;
81 Certificate *data;
82 hx509_private_key private_key;
83 struct _hx509_cert_attrs attrs;
84 hx509_name basename;
85 _hx509_cert_release_func release;
86 void *ctx;
89 typedef struct hx509_name_constraints {
90 NameConstraints *val;
91 size_t len;
92 } hx509_name_constraints;
94 #define GeneralSubtrees_SET(g,var) \
95 (g)->len = (var)->len, (g)->val = (var)->val;
97 /**
98 * Creates a hx509 context that most functions in the library
99 * uses. The context is only allowed to be used by one thread at each
100 * moment. Free the context with hx509_context_free().
102 * @param context Returns a pointer to new hx509 context.
104 * @return Returns an hx509 error code.
106 * @ingroup hx509
110 hx509_context_init(hx509_context *context)
112 *context = calloc(1, sizeof(**context));
113 if (*context == NULL)
114 return ENOMEM;
116 _hx509_ks_null_register(*context);
117 _hx509_ks_mem_register(*context);
118 _hx509_ks_file_register(*context);
119 _hx509_ks_pkcs12_register(*context);
120 _hx509_ks_pkcs11_register(*context);
121 _hx509_ks_dir_register(*context);
122 _hx509_ks_keychain_register(*context);
124 ENGINE_add_conf_module();
125 OpenSSL_add_all_algorithms();
127 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
129 initialize_hx_error_table_r(&(*context)->et_list);
130 initialize_asn1_error_table_r(&(*context)->et_list);
132 #ifdef HX509_DEFAULT_ANCHORS
133 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
134 NULL, &(*context)->default_trust_anchors);
135 #endif
137 return 0;
141 * Selects if the hx509_revoke_verify() function is going to require
142 * the existans of a revokation method (OSCP, CRL) or not. Note that
143 * hx509_verify_path(), hx509_cms_verify_signed(), and other function
144 * call hx509_revoke_verify().
146 * @param context hx509 context to change the flag for.
147 * @param flag zero, revokation method required, non zero missing
148 * revokation method ok
150 * @ingroup hx509_verify
153 void
154 hx509_context_set_missing_revoke(hx509_context context, int flag)
156 if (flag)
157 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
158 else
159 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
163 * Free the context allocated by hx509_context_init().
165 * @param context context to be freed.
167 * @ingroup hx509
170 void
171 hx509_context_free(hx509_context *context)
173 hx509_clear_error_string(*context);
174 if ((*context)->ks_ops) {
175 free((*context)->ks_ops);
176 (*context)->ks_ops = NULL;
178 (*context)->ks_num_ops = 0;
179 free_error_table ((*context)->et_list);
180 if ((*context)->querystat)
181 free((*context)->querystat);
182 memset(*context, 0, sizeof(**context));
183 free(*context);
184 *context = NULL;
191 Certificate *
192 _hx509_get_cert(hx509_cert cert)
194 return cert->data;
202 _hx509_cert_get_version(const Certificate *t)
204 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
208 * Allocate and init an hx509 certificate object from the decoded
209 * certificate `c´.
211 * @param context A hx509 context.
212 * @param c
213 * @param cert
215 * @return Returns an hx509 error code.
217 * @ingroup hx509_cert
221 hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
223 int ret;
225 *cert = malloc(sizeof(**cert));
226 if (*cert == NULL)
227 return ENOMEM;
228 (*cert)->ref = 1;
229 (*cert)->friendlyname = NULL;
230 (*cert)->attrs.len = 0;
231 (*cert)->attrs.val = NULL;
232 (*cert)->private_key = NULL;
233 (*cert)->basename = NULL;
234 (*cert)->release = NULL;
235 (*cert)->ctx = NULL;
237 (*cert)->data = calloc(1, sizeof(*(*cert)->data));
238 if ((*cert)->data == NULL) {
239 free(*cert);
240 return ENOMEM;
242 ret = copy_Certificate(c, (*cert)->data);
243 if (ret) {
244 free((*cert)->data);
245 free(*cert);
246 *cert = NULL;
248 return ret;
252 * Just like hx509_cert_init(), but instead of a decode certificate
253 * takes an pointer and length to a memory region that contains a
254 * DER/BER encoded certificate.
256 * If the memory region doesn't contain just the certificate and
257 * nothing more the function will fail with
258 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
260 * @param context A hx509 context.
261 * @param ptr pointer to memory region containing encoded certificate.
262 * @param len length of memory region.
263 * @param cert a return pointer to a hx509 certificate object, will
264 * contain NULL on error.
266 * @return An hx509 error code, see hx509_get_error_string().
268 * @ingroup hx509_cert
272 hx509_cert_init_data(hx509_context context,
273 const void *ptr,
274 size_t len,
275 hx509_cert *cert)
277 Certificate t;
278 size_t size;
279 int ret;
281 ret = decode_Certificate(ptr, len, &t, &size);
282 if (ret) {
283 hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
284 return ret;
286 if (size != len) {
287 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
288 "Extra data after certificate");
289 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
292 ret = hx509_cert_init(context, &t, cert);
293 free_Certificate(&t);
294 return ret;
297 void
298 _hx509_cert_set_release(hx509_cert cert,
299 _hx509_cert_release_func release,
300 void *ctx)
302 cert->release = release;
303 cert->ctx = ctx;
307 /* Doesn't make a copy of `private_key'. */
310 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
312 if (cert->private_key)
313 _hx509_private_key_free(&cert->private_key);
314 cert->private_key = _hx509_private_key_ref(private_key);
315 return 0;
319 * Free reference to the hx509 certificate object, if the refcounter
320 * reaches 0, the object if freed. Its allowed to pass in NULL.
322 * @param cert the cert to free.
324 * @ingroup hx509_cert
327 void
328 hx509_cert_free(hx509_cert cert)
330 int i;
332 if (cert == NULL)
333 return;
335 if (cert->ref <= 0)
336 _hx509_abort("cert refcount <= 0 on free");
337 if (--cert->ref > 0)
338 return;
340 if (cert->release)
341 (cert->release)(cert, cert->ctx);
343 if (cert->private_key)
344 _hx509_private_key_free(&cert->private_key);
346 free_Certificate(cert->data);
347 free(cert->data);
349 for (i = 0; i < cert->attrs.len; i++) {
350 der_free_octet_string(&cert->attrs.val[i]->data);
351 der_free_oid(&cert->attrs.val[i]->oid);
352 free(cert->attrs.val[i]);
354 free(cert->attrs.val);
355 free(cert->friendlyname);
356 if (cert->basename)
357 hx509_name_free(&cert->basename);
358 memset(cert, 0, sizeof(cert));
359 free(cert);
363 * Add a reference to a hx509 certificate object.
365 * @param cert a pointer to an hx509 certificate object.
367 * @return the same object as is passed in.
369 * @ingroup hx509_cert
372 hx509_cert
373 hx509_cert_ref(hx509_cert cert)
375 if (cert == NULL)
376 return NULL;
377 if (cert->ref <= 0)
378 _hx509_abort("cert refcount <= 0");
379 cert->ref++;
380 if (cert->ref == 0)
381 _hx509_abort("cert refcount == 0");
382 return cert;
386 * Allocate an verification context that is used fo control the
387 * verification process.
389 * @param context A hx509 context.
390 * @param ctx returns a pointer to a hx509_verify_ctx object.
392 * @return An hx509 error code, see hx509_get_error_string().
394 * @ingroup hx509_verify
398 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
400 hx509_verify_ctx c;
402 c = calloc(1, sizeof(*c));
403 if (c == NULL)
404 return ENOMEM;
406 c->max_depth = HX509_VERIFY_MAX_DEPTH;
408 *ctx = c;
410 return 0;
414 * Free an hx509 verification context.
416 * @param ctx the context to be freed.
418 * @ingroup hx509_verify
421 void
422 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
424 if (ctx) {
425 hx509_certs_free(&ctx->trust_anchors);
426 hx509_revoke_free(&ctx->revoke_ctx);
427 memset(ctx, 0, sizeof(*ctx));
429 free(ctx);
433 * Set the trust anchors in the verification context, makes an
434 * reference to the keyset, so the consumer can free the keyset
435 * independent of the destruction of the verification context (ctx).
437 * @param ctx a verification context
438 * @param set a keyset containing the trust anchors.
440 * @ingroup hx509_verify
443 void
444 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
446 ctx->trust_anchors = _hx509_certs_ref(set);
450 * Attach an revocation context to the verfication context, , makes an
451 * reference to the revoke context, so the consumer can free the
452 * revoke context independent of the destruction of the verification
453 * context. If there is no revoke context, the verification process is
454 * NOT going to check any verification status.
456 * @param ctx a verification context.
457 * @param revoke_ctx a revoke context.
459 * @ingroup hx509_verify
462 void
463 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
465 if (ctx->revoke_ctx)
466 hx509_revoke_free(&ctx->revoke_ctx);
467 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
471 * Set the clock time the the verification process is going to
472 * use. Used to check certificate in the past and future time. If not
473 * set the current time will be used.
475 * @param ctx a verification context.
476 * @param t the time the verifiation is using.
479 * @ingroup hx509_verify
482 void
483 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
485 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
486 ctx->time_now = t;
490 * Set the maximum depth of the certificate chain that the path
491 * builder is going to try.
493 * @param ctx a verification context
494 * @param max_depth maxium depth of the certificate chain, include
495 * trust anchor.
497 * @ingroup hx509_verify
500 void
501 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
503 ctx->max_depth = max_depth;
507 * Allow or deny the use of proxy certificates
509 * @param ctx a verification context
510 * @param boolean if non zero, allow proxy certificates.
512 * @ingroup hx509_verify
515 void
516 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
518 if (boolean)
519 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
520 else
521 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
525 * Select strict RFC3280 verification of certificiates. This means
526 * checking key usage on CA certificates, this will make version 1
527 * certificiates unuseable.
529 * @param ctx a verification context
530 * @param boolean if non zero, use strict verification.
532 * @ingroup hx509_verify
535 void
536 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
538 if (boolean)
539 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
540 else
541 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
545 * Allow using the operating system builtin trust anchors if no other
546 * trust anchors are configured.
548 * @param ctx a verification context
549 * @param boolean if non zero, useing the operating systems builtin
550 * trust anchors.
553 * @return An hx509 error code, see hx509_get_error_string().
555 * @ingroup hx509_cert
558 void
559 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
561 if (boolean)
562 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
563 else
564 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
567 static const Extension *
568 find_extension(const Certificate *cert, const heim_oid *oid, int *idx)
570 const TBSCertificate *c = &cert->tbsCertificate;
572 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
573 return NULL;
575 for (;*idx < c->extensions->len; (*idx)++) {
576 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
577 return &c->extensions->val[(*idx)++];
579 return NULL;
582 static int
583 find_extension_auth_key_id(const Certificate *subject,
584 AuthorityKeyIdentifier *ai)
586 const Extension *e;
587 size_t size;
588 int i = 0;
590 memset(ai, 0, sizeof(*ai));
592 e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i);
593 if (e == NULL)
594 return HX509_EXTENSION_NOT_FOUND;
596 return decode_AuthorityKeyIdentifier(e->extnValue.data,
597 e->extnValue.length,
598 ai, &size);
602 _hx509_find_extension_subject_key_id(const Certificate *issuer,
603 SubjectKeyIdentifier *si)
605 const Extension *e;
606 size_t size;
607 int i = 0;
609 memset(si, 0, sizeof(*si));
611 e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i);
612 if (e == NULL)
613 return HX509_EXTENSION_NOT_FOUND;
615 return decode_SubjectKeyIdentifier(e->extnValue.data,
616 e->extnValue.length,
617 si, &size);
620 static int
621 find_extension_name_constraints(const Certificate *subject,
622 NameConstraints *nc)
624 const Extension *e;
625 size_t size;
626 int i = 0;
628 memset(nc, 0, sizeof(*nc));
630 e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i);
631 if (e == NULL)
632 return HX509_EXTENSION_NOT_FOUND;
634 return decode_NameConstraints(e->extnValue.data,
635 e->extnValue.length,
636 nc, &size);
639 static int
640 find_extension_subject_alt_name(const Certificate *cert, int *i,
641 GeneralNames *sa)
643 const Extension *e;
644 size_t size;
646 memset(sa, 0, sizeof(*sa));
648 e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i);
649 if (e == NULL)
650 return HX509_EXTENSION_NOT_FOUND;
652 return decode_GeneralNames(e->extnValue.data,
653 e->extnValue.length,
654 sa, &size);
657 static int
658 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
660 const Extension *e;
661 size_t size;
662 int i = 0;
664 memset(eku, 0, sizeof(*eku));
666 e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i);
667 if (e == NULL)
668 return HX509_EXTENSION_NOT_FOUND;
670 return decode_ExtKeyUsage(e->extnValue.data,
671 e->extnValue.length,
672 eku, &size);
675 static int
676 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
678 void *p;
679 int ret;
681 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
682 if (p == NULL)
683 return ENOMEM;
684 list->val = p;
685 ret = der_copy_octet_string(entry, &list->val[list->len]);
686 if (ret)
687 return ret;
688 list->len++;
689 return 0;
693 * Free a list of octet strings returned by another hx509 library
694 * function.
696 * @param list list to be freed.
698 * @ingroup hx509_misc
701 void
702 hx509_free_octet_string_list(hx509_octet_string_list *list)
704 int i;
705 for (i = 0; i < list->len; i++)
706 der_free_octet_string(&list->val[i]);
707 free(list->val);
708 list->val = NULL;
709 list->len = 0;
713 * Return a list of subjectAltNames specified by oid in the
714 * certificate. On error the
716 * The returned list of octet string should be freed with
717 * hx509_free_octet_string_list().
719 * @param context A hx509 context.
720 * @param cert a hx509 certificate object.
721 * @param oid an oid to for SubjectAltName.
722 * @param list list of matching SubjectAltName.
724 * @return An hx509 error code, see hx509_get_error_string().
726 * @ingroup hx509_cert
730 hx509_cert_find_subjectAltName_otherName(hx509_context context,
731 hx509_cert cert,
732 const heim_oid *oid,
733 hx509_octet_string_list *list)
735 GeneralNames sa;
736 int ret, i, j;
738 list->val = NULL;
739 list->len = 0;
741 i = 0;
742 while (1) {
743 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
744 i++;
745 if (ret == HX509_EXTENSION_NOT_FOUND) {
746 ret = 0;
747 break;
748 } else if (ret != 0) {
749 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
750 hx509_free_octet_string_list(list);
751 return ret;
754 for (j = 0; j < sa.len; j++) {
755 if (sa.val[j].element == choice_GeneralName_otherName &&
756 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
758 ret = add_to_list(list, &sa.val[j].u.otherName.value);
759 if (ret) {
760 hx509_set_error_string(context, 0, ret,
761 "Error adding an exra SAN to "
762 "return list");
763 hx509_free_octet_string_list(list);
764 free_GeneralNames(&sa);
765 return ret;
769 free_GeneralNames(&sa);
771 return 0;
775 static int
776 check_key_usage(hx509_context context, const Certificate *cert,
777 unsigned flags, int req_present)
779 const Extension *e;
780 KeyUsage ku;
781 size_t size;
782 int ret, i = 0;
783 unsigned ku_flags;
785 if (_hx509_cert_get_version(cert) < 3)
786 return 0;
788 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
789 if (e == NULL) {
790 if (req_present) {
791 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
792 "Required extension key "
793 "usage missing from certifiate");
794 return HX509_KU_CERT_MISSING;
796 return 0;
799 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
800 if (ret)
801 return ret;
802 ku_flags = KeyUsage2int(ku);
803 if ((ku_flags & flags) != flags) {
804 unsigned missing = (~ku_flags) & flags;
805 char buf[256], *name;
807 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
808 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
809 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
810 "Key usage %s required but missing "
811 "from certifiate %s", buf, name);
812 free(name);
813 return HX509_KU_CERT_MISSING;
815 return 0;
819 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
820 * an error code. If 'req_present' the existance is required of the
821 * KeyUsage extension.
825 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
826 unsigned flags, int req_present)
828 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
831 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
833 static int
834 check_basic_constraints(hx509_context context, const Certificate *cert,
835 enum certtype type, int depth)
837 BasicConstraints bc;
838 const Extension *e;
839 size_t size;
840 int ret, i = 0;
842 if (_hx509_cert_get_version(cert) < 3)
843 return 0;
845 e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i);
846 if (e == NULL) {
847 switch(type) {
848 case PROXY_CERT:
849 case EE_CERT:
850 return 0;
851 case CA_CERT: {
852 char *name;
853 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
854 assert(ret == 0);
855 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
856 "basicConstraints missing from "
857 "CA certifiacte %s", name);
858 free(name);
859 return HX509_EXTENSION_NOT_FOUND;
864 ret = decode_BasicConstraints(e->extnValue.data,
865 e->extnValue.length, &bc,
866 &size);
867 if (ret)
868 return ret;
869 switch(type) {
870 case PROXY_CERT:
871 if (bc.cA != NULL && *bc.cA)
872 ret = HX509_PARENT_IS_CA;
873 break;
874 case EE_CERT:
875 ret = 0;
876 break;
877 case CA_CERT:
878 if (bc.cA == NULL || !*bc.cA)
879 ret = HX509_PARENT_NOT_CA;
880 else if (bc.pathLenConstraint)
881 if (depth - 1 > *bc.pathLenConstraint)
882 ret = HX509_CA_PATH_TOO_DEEP;
883 break;
885 free_BasicConstraints(&bc);
886 return ret;
890 _hx509_cert_is_parent_cmp(const Certificate *subject,
891 const Certificate *issuer,
892 int allow_self_signed)
894 int diff;
895 AuthorityKeyIdentifier ai;
896 SubjectKeyIdentifier si;
897 int ret_ai, ret_si;
899 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
900 &subject->tbsCertificate.issuer);
901 if (diff)
902 return diff;
904 memset(&ai, 0, sizeof(ai));
905 memset(&si, 0, sizeof(si));
908 * Try to find AuthorityKeyIdentifier, if it's not present in the
909 * subject certificate nor the parent.
912 ret_ai = find_extension_auth_key_id(subject, &ai);
913 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
914 return 1;
915 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
916 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
917 return -1;
919 if (ret_si && ret_ai)
920 goto out;
921 if (ret_ai)
922 goto out;
923 if (ret_si) {
924 if (allow_self_signed) {
925 diff = 0;
926 goto out;
927 } else if (ai.keyIdentifier) {
928 diff = -1;
929 goto out;
933 if (ai.keyIdentifier == NULL) {
934 Name name;
936 if (ai.authorityCertIssuer == NULL)
937 return -1;
938 if (ai.authorityCertSerialNumber == NULL)
939 return -1;
941 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
942 &issuer->tbsCertificate.serialNumber);
943 if (diff)
944 return diff;
945 if (ai.authorityCertIssuer->len != 1)
946 return -1;
947 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
948 return -1;
950 name.element =
951 ai.authorityCertIssuer->val[0].u.directoryName.element;
952 name.u.rdnSequence =
953 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
955 diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
956 &name);
957 if (diff)
958 return diff;
959 diff = 0;
960 } else
961 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
962 if (diff)
963 goto out;
965 out:
966 free_AuthorityKeyIdentifier(&ai);
967 free_SubjectKeyIdentifier(&si);
968 return diff;
971 static int
972 certificate_is_anchor(hx509_context context,
973 hx509_certs trust_anchors,
974 const hx509_cert cert)
976 hx509_query q;
977 hx509_cert c;
978 int ret;
980 if (trust_anchors == NULL)
981 return 0;
983 _hx509_query_clear(&q);
985 q.match = HX509_QUERY_MATCH_CERTIFICATE;
986 q.certificate = _hx509_get_cert(cert);
988 ret = hx509_certs_find(context, trust_anchors, &q, &c);
989 if (ret == 0)
990 hx509_cert_free(c);
991 return ret == 0;
994 static int
995 certificate_is_self_signed(const Certificate *cert)
997 return _hx509_name_cmp(&cert->tbsCertificate.subject,
998 &cert->tbsCertificate.issuer) == 0;
1002 * The subjectName is "null" when it's empty set of relative DBs.
1005 static int
1006 subject_null_p(const Certificate *c)
1008 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1012 static int
1013 find_parent(hx509_context context,
1014 time_t time_now,
1015 hx509_certs trust_anchors,
1016 hx509_path *path,
1017 hx509_certs pool,
1018 hx509_cert current,
1019 hx509_cert *parent)
1021 AuthorityKeyIdentifier ai;
1022 hx509_query q;
1023 int ret;
1025 *parent = NULL;
1026 memset(&ai, 0, sizeof(ai));
1028 _hx509_query_clear(&q);
1030 if (!subject_null_p(current->data)) {
1031 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1032 q.subject = _hx509_get_cert(current);
1033 } else {
1034 ret = find_extension_auth_key_id(current->data, &ai);
1035 if (ret) {
1036 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1037 "Subjectless certificate missing AuthKeyID");
1038 return HX509_CERTIFICATE_MALFORMED;
1041 if (ai.keyIdentifier == NULL) {
1042 free_AuthorityKeyIdentifier(&ai);
1043 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1044 "Subjectless certificate missing keyIdentifier "
1045 "inside AuthKeyID");
1046 return HX509_CERTIFICATE_MALFORMED;
1049 q.subject_id = ai.keyIdentifier;
1050 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1053 q.path = path;
1054 q.match |= HX509_QUERY_NO_MATCH_PATH;
1056 if (pool) {
1057 q.timenow = time_now;
1058 q.match |= HX509_QUERY_MATCH_TIME;
1060 ret = hx509_certs_find(context, pool, &q, parent);
1061 if (ret == 0) {
1062 free_AuthorityKeyIdentifier(&ai);
1063 return 0;
1065 q.match &= ~HX509_QUERY_MATCH_TIME;
1068 if (trust_anchors) {
1069 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1070 if (ret == 0) {
1071 free_AuthorityKeyIdentifier(&ai);
1072 return ret;
1075 free_AuthorityKeyIdentifier(&ai);
1078 hx509_name name;
1079 char *str;
1081 ret = hx509_cert_get_subject(current, &name);
1082 if (ret) {
1083 hx509_clear_error_string(context);
1084 return HX509_ISSUER_NOT_FOUND;
1086 ret = hx509_name_to_string(name, &str);
1087 hx509_name_free(&name);
1088 if (ret) {
1089 hx509_clear_error_string(context);
1090 return HX509_ISSUER_NOT_FOUND;
1093 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1094 "Failed to find issuer for "
1095 "certificate with subject: '%s'", str);
1096 free(str);
1098 return HX509_ISSUER_NOT_FOUND;
1105 static int
1106 is_proxy_cert(hx509_context context,
1107 const Certificate *cert,
1108 ProxyCertInfo *rinfo)
1110 ProxyCertInfo info;
1111 const Extension *e;
1112 size_t size;
1113 int ret, i = 0;
1115 if (rinfo)
1116 memset(rinfo, 0, sizeof(*rinfo));
1118 e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i);
1119 if (e == NULL) {
1120 hx509_clear_error_string(context);
1121 return HX509_EXTENSION_NOT_FOUND;
1124 ret = decode_ProxyCertInfo(e->extnValue.data,
1125 e->extnValue.length,
1126 &info,
1127 &size);
1128 if (ret) {
1129 hx509_clear_error_string(context);
1130 return ret;
1132 if (size != e->extnValue.length) {
1133 free_ProxyCertInfo(&info);
1134 hx509_clear_error_string(context);
1135 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1137 if (rinfo == NULL)
1138 free_ProxyCertInfo(&info);
1139 else
1140 *rinfo = info;
1142 return 0;
1146 * Path operations are like MEMORY based keyset, but with exposed
1147 * internal so we can do easy searches.
1151 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1153 hx509_cert *val;
1154 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1155 if (val == NULL) {
1156 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1157 return ENOMEM;
1160 path->val = val;
1161 path->val[path->len] = hx509_cert_ref(cert);
1162 path->len++;
1164 return 0;
1167 void
1168 _hx509_path_free(hx509_path *path)
1170 unsigned i;
1172 for (i = 0; i < path->len; i++)
1173 hx509_cert_free(path->val[i]);
1174 free(path->val);
1175 path->val = NULL;
1176 path->len = 0;
1180 * Find path by looking up issuer for the top certificate and continue
1181 * until an anchor certificate is found or max limit is found. A
1182 * certificate never included twice in the path.
1184 * If the trust anchors are not given, calculate optimistic path, just
1185 * follow the chain upward until we no longer find a parent or we hit
1186 * the max path limit. In this case, a failure will always be returned
1187 * depending on what error condition is hit first.
1189 * The path includes a path from the top certificate to the anchor
1190 * certificate.
1192 * The caller needs to free `path´ both on successful built path and
1193 * failure.
1197 _hx509_calculate_path(hx509_context context,
1198 int flags,
1199 time_t time_now,
1200 hx509_certs anchors,
1201 unsigned int max_depth,
1202 hx509_cert cert,
1203 hx509_certs pool,
1204 hx509_path *path)
1206 hx509_cert parent, current;
1207 int ret;
1209 if (max_depth == 0)
1210 max_depth = HX509_VERIFY_MAX_DEPTH;
1212 ret = _hx509_path_append(context, path, cert);
1213 if (ret)
1214 return ret;
1216 current = hx509_cert_ref(cert);
1218 while (!certificate_is_anchor(context, anchors, current)) {
1220 ret = find_parent(context, time_now, anchors, path,
1221 pool, current, &parent);
1222 hx509_cert_free(current);
1223 if (ret)
1224 return ret;
1226 ret = _hx509_path_append(context, path, parent);
1227 if (ret)
1228 return ret;
1229 current = parent;
1231 if (path->len > max_depth) {
1232 hx509_cert_free(current);
1233 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1234 "Path too long while bulding "
1235 "certificate chain");
1236 return HX509_PATH_TOO_LONG;
1240 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1241 path->len > 0 &&
1242 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1244 hx509_cert_free(path->val[path->len - 1]);
1245 path->len--;
1248 hx509_cert_free(current);
1249 return 0;
1253 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1254 const AlgorithmIdentifier *q)
1256 int diff;
1257 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1258 if (diff)
1259 return diff;
1260 if (p->parameters) {
1261 if (q->parameters)
1262 return heim_any_cmp(p->parameters,
1263 q->parameters);
1264 else
1265 return 1;
1266 } else {
1267 if (q->parameters)
1268 return -1;
1269 else
1270 return 0;
1275 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1277 int diff;
1278 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1279 if (diff)
1280 return diff;
1281 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1282 &q->signatureAlgorithm);
1283 if (diff)
1284 return diff;
1285 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1286 &q->tbsCertificate._save);
1287 return diff;
1291 * Compare to hx509 certificate object, useful for sorting.
1293 * @param p a hx509 certificate object.
1294 * @param q a hx509 certificate object.
1296 * @return 0 the objects are the same, returns > 0 is p is "larger"
1297 * then q, < 0 if p is "smaller" then q.
1299 * @ingroup hx509_cert
1303 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1305 return _hx509_Certificate_cmp(p->data, q->data);
1309 * Return the name of the issuer of the hx509 certificate.
1311 * @param p a hx509 certificate object.
1312 * @param name a pointer to a hx509 name, should be freed by
1313 * hx509_name_free().
1315 * @return An hx509 error code, see hx509_get_error_string().
1317 * @ingroup hx509_cert
1321 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1323 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1327 * Return the name of the subject of the hx509 certificate.
1329 * @param p a hx509 certificate object.
1330 * @param name a pointer to a hx509 name, should be freed by
1331 * hx509_name_free(). See also hx509_cert_get_base_subject().
1333 * @return An hx509 error code, see hx509_get_error_string().
1335 * @ingroup hx509_cert
1339 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1341 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1345 * Return the name of the base subject of the hx509 certificate. If
1346 * the certiicate is a verified proxy certificate, the this function
1347 * return the base certificate (root of the proxy chain). If the proxy
1348 * certificate is not verified with the base certificate
1349 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1351 * @param context a hx509 context.
1352 * @param c a hx509 certificate object.
1353 * @param name a pointer to a hx509 name, should be freed by
1354 * hx509_name_free(). See also hx509_cert_get_subject().
1356 * @return An hx509 error code, see hx509_get_error_string().
1358 * @ingroup hx509_cert
1362 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1363 hx509_name *name)
1365 if (c->basename)
1366 return hx509_name_copy(context, c->basename, name);
1367 if (is_proxy_cert(context, c->data, NULL) == 0) {
1368 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1369 hx509_set_error_string(context, 0, ret,
1370 "Proxy certificate have not been "
1371 "canonicalize yet, no base name");
1372 return ret;
1374 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1378 * Get serial number of the certificate.
1380 * @param p a hx509 certificate object.
1381 * @param i serial number, should be freed ith der_free_heim_integer().
1383 * @return An hx509 error code, see hx509_get_error_string().
1385 * @ingroup hx509_cert
1389 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1391 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1395 * Get notBefore time of the certificate.
1397 * @param p a hx509 certificate object.
1399 * @return return not before time
1401 * @ingroup hx509_cert
1404 time_t
1405 hx509_cert_get_notBefore(hx509_cert p)
1407 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1411 * Get notAfter time of the certificate.
1413 * @param p a hx509 certificate object.
1415 * @return return not after time.
1417 * @ingroup hx509_cert
1420 time_t
1421 hx509_cert_get_notAfter(hx509_cert p)
1423 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1427 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1429 * @param context a hx509 context.
1430 * @param p a hx509 certificate object.
1431 * @param spki SubjectPublicKeyInfo, should be freed with
1432 * free_SubjectPublicKeyInfo().
1434 * @return An hx509 error code, see hx509_get_error_string().
1436 * @ingroup hx509_cert
1440 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1442 int ret;
1444 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1445 if (ret)
1446 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1447 return ret;
1451 * Get the AlgorithmIdentifier from the hx509 certificate.
1453 * @param context a hx509 context.
1454 * @param p a hx509 certificate object.
1455 * @param alg AlgorithmIdentifier, should be freed with
1456 * free_AlgorithmIdentifier().
1458 * @return An hx509 error code, see hx509_get_error_string().
1460 * @ingroup hx509_cert
1464 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1465 hx509_cert p,
1466 AlgorithmIdentifier *alg)
1468 int ret;
1470 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1471 if (ret)
1472 hx509_set_error_string(context, 0, ret,
1473 "Failed to copy SPKI AlgorithmIdentifier");
1474 return ret;
1478 hx509_private_key
1479 _hx509_cert_private_key(hx509_cert p)
1481 return p->private_key;
1485 hx509_cert_have_private_key(hx509_cert p)
1487 return p->private_key ? 1 : 0;
1492 _hx509_cert_private_key_exportable(hx509_cert p)
1494 if (p->private_key == NULL)
1495 return 0;
1496 return _hx509_private_key_exportable(p->private_key);
1500 _hx509_cert_private_decrypt(hx509_context context,
1501 const heim_octet_string *ciphertext,
1502 const heim_oid *encryption_oid,
1503 hx509_cert p,
1504 heim_octet_string *cleartext)
1506 cleartext->data = NULL;
1507 cleartext->length = 0;
1509 if (p->private_key == NULL) {
1510 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1511 "Private key missing");
1512 return HX509_PRIVATE_KEY_MISSING;
1515 return _hx509_private_key_private_decrypt(context,
1516 ciphertext,
1517 encryption_oid,
1518 p->private_key,
1519 cleartext);
1523 _hx509_cert_public_encrypt(hx509_context context,
1524 const heim_octet_string *cleartext,
1525 const hx509_cert p,
1526 heim_oid *encryption_oid,
1527 heim_octet_string *ciphertext)
1529 return _hx509_public_encrypt(context,
1530 cleartext, p->data,
1531 encryption_oid, ciphertext);
1538 time_t
1539 _hx509_Time2time_t(const Time *t)
1541 switch(t->element) {
1542 case choice_Time_utcTime:
1543 return t->u.utcTime;
1544 case choice_Time_generalTime:
1545 return t->u.generalTime;
1547 return 0;
1554 static int
1555 init_name_constraints(hx509_name_constraints *nc)
1557 memset(nc, 0, sizeof(*nc));
1558 return 0;
1561 static int
1562 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1563 hx509_name_constraints *nc)
1565 NameConstraints tnc;
1566 int ret;
1568 ret = find_extension_name_constraints(c, &tnc);
1569 if (ret == HX509_EXTENSION_NOT_FOUND)
1570 return 0;
1571 else if (ret) {
1572 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1573 return ret;
1574 } else if (not_ca) {
1575 ret = HX509_VERIFY_CONSTRAINTS;
1576 hx509_set_error_string(context, 0, ret, "Not a CA and "
1577 "have NameConstraints");
1578 } else {
1579 NameConstraints *val;
1580 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1581 if (val == NULL) {
1582 hx509_clear_error_string(context);
1583 ret = ENOMEM;
1584 goto out;
1586 nc->val = val;
1587 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1588 if (ret) {
1589 hx509_clear_error_string(context);
1590 goto out;
1592 nc->len += 1;
1594 out:
1595 free_NameConstraints(&tnc);
1596 return ret;
1599 static int
1600 match_RDN(const RelativeDistinguishedName *c,
1601 const RelativeDistinguishedName *n)
1603 int i;
1605 if (c->len != n->len)
1606 return HX509_NAME_CONSTRAINT_ERROR;
1608 for (i = 0; i < n->len; i++) {
1609 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1610 return HX509_NAME_CONSTRAINT_ERROR;
1611 if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0)
1612 return HX509_NAME_CONSTRAINT_ERROR;
1614 return 0;
1617 static int
1618 match_X501Name(const Name *c, const Name *n)
1620 int i, ret;
1622 if (c->element != choice_Name_rdnSequence
1623 || n->element != choice_Name_rdnSequence)
1624 return 0;
1625 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1626 return HX509_NAME_CONSTRAINT_ERROR;
1627 for (i = 0; i < c->u.rdnSequence.len; i++) {
1628 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1629 if (ret)
1630 return ret;
1632 return 0;
1636 static int
1637 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
1640 * Name constraints only apply to the same name type, see RFC3280,
1641 * 4.2.1.11.
1643 assert(c->element == n->element);
1645 switch(c->element) {
1646 case choice_GeneralName_otherName:
1647 if (der_heim_oid_cmp(&c->u.otherName.type_id,
1648 &n->u.otherName.type_id) != 0)
1649 return HX509_NAME_CONSTRAINT_ERROR;
1650 if (heim_any_cmp(&c->u.otherName.value,
1651 &n->u.otherName.value) != 0)
1652 return HX509_NAME_CONSTRAINT_ERROR;
1653 *match = 1;
1654 return 0;
1655 case choice_GeneralName_rfc822Name: {
1656 const char *s;
1657 size_t len1, len2;
1658 s = strchr(c->u.rfc822Name, '@');
1659 if (s) {
1660 if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1661 return HX509_NAME_CONSTRAINT_ERROR;
1662 } else {
1663 s = strchr(n->u.rfc822Name, '@');
1664 if (s == NULL)
1665 return HX509_NAME_CONSTRAINT_ERROR;
1666 len1 = strlen(c->u.rfc822Name);
1667 len2 = strlen(s + 1);
1668 if (len1 > len2)
1669 return HX509_NAME_CONSTRAINT_ERROR;
1670 if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1671 return HX509_NAME_CONSTRAINT_ERROR;
1672 if (len1 < len2 && s[len2 - len1 + 1] != '.')
1673 return HX509_NAME_CONSTRAINT_ERROR;
1675 *match = 1;
1676 return 0;
1678 case choice_GeneralName_dNSName: {
1679 size_t lenc, lenn;
1681 lenc = strlen(c->u.dNSName);
1682 lenn = strlen(n->u.dNSName);
1683 if (lenc > lenn)
1684 return HX509_NAME_CONSTRAINT_ERROR;
1685 if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1686 return HX509_NAME_CONSTRAINT_ERROR;
1687 if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1688 return HX509_NAME_CONSTRAINT_ERROR;
1689 *match = 1;
1690 return 0;
1692 case choice_GeneralName_directoryName: {
1693 Name c_name, n_name;
1694 int ret;
1696 c_name._save.data = NULL;
1697 c_name._save.length = 0;
1698 c_name.element = c->u.directoryName.element;
1699 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1701 n_name._save.data = NULL;
1702 n_name._save.length = 0;
1703 n_name.element = n->u.directoryName.element;
1704 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1706 ret = match_X501Name(&c_name, &n_name);
1707 if (ret == 0)
1708 *match = 1;
1709 return ret;
1711 case choice_GeneralName_uniformResourceIdentifier:
1712 case choice_GeneralName_iPAddress:
1713 case choice_GeneralName_registeredID:
1714 default:
1715 return HX509_NAME_CONSTRAINT_ERROR;
1719 static int
1720 match_alt_name(const GeneralName *n, const Certificate *c,
1721 int *same, int *match)
1723 GeneralNames sa;
1724 int ret, i, j;
1726 i = 0;
1727 do {
1728 ret = find_extension_subject_alt_name(c, &i, &sa);
1729 if (ret == HX509_EXTENSION_NOT_FOUND) {
1730 ret = 0;
1731 break;
1732 } else if (ret != 0)
1733 break;
1735 for (j = 0; j < sa.len; j++) {
1736 if (n->element == sa.val[j].element) {
1737 *same = 1;
1738 ret = match_general_name(n, &sa.val[j], match);
1741 free_GeneralNames(&sa);
1742 } while (1);
1743 return ret;
1747 static int
1748 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1750 int name, alt_name, same;
1751 unsigned int i;
1752 int ret = 0;
1754 name = alt_name = same = *match = 0;
1755 for (i = 0; i < t->len; i++) {
1756 if (t->val[i].minimum && t->val[i].maximum)
1757 return HX509_RANGE;
1760 * If the constraint apply to directoryNames, test is with
1761 * subjectName of the certificate if the certificate have a
1762 * non-null (empty) subjectName.
1765 if (t->val[i].base.element == choice_GeneralName_directoryName
1766 && !subject_null_p(c))
1768 GeneralName certname;
1770 memset(&certname, 0, sizeof(certname));
1771 certname.element = choice_GeneralName_directoryName;
1772 certname.u.directoryName.element =
1773 c->tbsCertificate.subject.element;
1774 certname.u.directoryName.u.rdnSequence =
1775 c->tbsCertificate.subject.u.rdnSequence;
1777 ret = match_general_name(&t->val[i].base, &certname, &name);
1780 /* Handle subjectAltNames, this is icky since they
1781 * restrictions only apply if the subjectAltName is of the
1782 * same type. So if there have been a match of type, require
1783 * altname to be set.
1785 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1787 if (name && (!same || alt_name))
1788 *match = 1;
1789 return ret;
1792 static int
1793 check_name_constraints(hx509_context context,
1794 const hx509_name_constraints *nc,
1795 const Certificate *c)
1797 int match, ret;
1798 int i;
1800 for (i = 0 ; i < nc->len; i++) {
1801 GeneralSubtrees gs;
1803 if (nc->val[i].permittedSubtrees) {
1804 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1805 ret = match_tree(&gs, c, &match);
1806 if (ret) {
1807 hx509_clear_error_string(context);
1808 return ret;
1810 /* allow null subjectNames, they wont matches anything */
1811 if (match == 0 && !subject_null_p(c)) {
1812 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1813 "Error verify constraints, "
1814 "certificate didn't match any "
1815 "permitted subtree");
1816 return HX509_VERIFY_CONSTRAINTS;
1819 if (nc->val[i].excludedSubtrees) {
1820 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1821 ret = match_tree(&gs, c, &match);
1822 if (ret) {
1823 hx509_clear_error_string(context);
1824 return ret;
1826 if (match) {
1827 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1828 "Error verify constraints, "
1829 "certificate included in excluded "
1830 "subtree");
1831 return HX509_VERIFY_CONSTRAINTS;
1835 return 0;
1838 static void
1839 free_name_constraints(hx509_name_constraints *nc)
1841 int i;
1843 for (i = 0 ; i < nc->len; i++)
1844 free_NameConstraints(&nc->val[i]);
1845 free(nc->val);
1849 * Build and verify the path for the certificate to the trust anchor
1850 * specified in the verify context. The path is constructed from the
1851 * certificate, the pool and the trust anchors.
1853 * @param context A hx509 context.
1854 * @param ctx A hx509 verification context.
1855 * @param cert the certificate to build the path from.
1856 * @param pool A keyset of certificates to build the chain from.
1858 * @return An hx509 error code, see hx509_get_error_string().
1860 * @ingroup hx509_verify
1864 hx509_verify_path(hx509_context context,
1865 hx509_verify_ctx ctx,
1866 hx509_cert cert,
1867 hx509_certs pool)
1869 hx509_name_constraints nc;
1870 hx509_path path;
1871 #if 0
1872 const AlgorithmIdentifier *alg_id;
1873 #endif
1874 int ret, i, proxy_cert_depth, selfsigned_depth;
1875 enum certtype type;
1876 Name proxy_issuer;
1877 hx509_certs anchors = NULL;
1879 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1881 ret = init_name_constraints(&nc);
1882 if (ret)
1883 return ret;
1885 path.val = NULL;
1886 path.len = 0;
1888 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1889 ctx->time_now = time(NULL);
1894 if (ctx->trust_anchors)
1895 anchors = _hx509_certs_ref(ctx->trust_anchors);
1896 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1897 anchors = _hx509_certs_ref(context->default_trust_anchors);
1898 else {
1899 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1900 if (ret)
1901 goto out;
1905 * Calculate the path from the certificate user presented to the
1906 * to an anchor.
1908 ret = _hx509_calculate_path(context, 0, ctx->time_now,
1909 anchors, ctx->max_depth,
1910 cert, pool, &path);
1911 if (ret)
1912 goto out;
1914 #if 0
1915 alg_id = path.val[path->len - 1]->data->tbsCertificate.signature;
1916 #endif
1919 * Check CA and proxy certificate chain from the top of the
1920 * certificate chain. Also check certificate is valid with respect
1921 * to the current time.
1925 proxy_cert_depth = 0;
1926 selfsigned_depth = 0;
1928 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1929 type = PROXY_CERT;
1930 else
1931 type = EE_CERT;
1933 for (i = 0; i < path.len; i++) {
1934 Certificate *c;
1935 time_t t;
1937 c = _hx509_get_cert(path.val[i]);
1940 * Lets do some basic check on issuer like
1941 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1942 * on what type of certificate this is.
1945 switch (type) {
1946 case CA_CERT:
1947 /* XXX make constants for keyusage */
1948 ret = check_key_usage(context, c, 1 << 5,
1949 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1950 if (ret) {
1951 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1952 "Key usage missing from CA certificate");
1953 goto out;
1956 if (i + 1 != path.len && certificate_is_self_signed(c))
1957 selfsigned_depth++;
1959 break;
1960 case PROXY_CERT: {
1961 ProxyCertInfo info;
1963 if (is_proxy_cert(context, c, &info) == 0) {
1964 int j;
1966 if (info.pCPathLenConstraint != NULL &&
1967 *info.pCPathLenConstraint < i)
1969 free_ProxyCertInfo(&info);
1970 ret = HX509_PATH_TOO_LONG;
1971 hx509_set_error_string(context, 0, ret,
1972 "Proxy certificate chain "
1973 "longer then allowed");
1974 goto out;
1976 /* XXX MUST check info.proxyPolicy */
1977 free_ProxyCertInfo(&info);
1979 j = 0;
1980 if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
1981 ret = HX509_PROXY_CERT_INVALID;
1982 hx509_set_error_string(context, 0, ret,
1983 "Proxy certificate have explicity "
1984 "forbidden subjectAltName");
1985 goto out;
1988 j = 0;
1989 if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
1990 ret = HX509_PROXY_CERT_INVALID;
1991 hx509_set_error_string(context, 0, ret,
1992 "Proxy certificate have explicity "
1993 "forbidden issuerAltName");
1994 goto out;
1998 * The subject name of the proxy certificate should be
1999 * CN=XXX,<proxy issuer>, prune of CN and check if its
2000 * the same over the whole chain of proxy certs and
2001 * then check with the EE cert when we get to it.
2004 if (proxy_cert_depth) {
2005 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject);
2006 if (ret) {
2007 ret = HX509_PROXY_CERT_NAME_WRONG;
2008 hx509_set_error_string(context, 0, ret,
2009 "Base proxy name not right");
2010 goto out;
2014 free_Name(&proxy_issuer);
2016 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2017 if (ret) {
2018 hx509_clear_error_string(context);
2019 goto out;
2022 j = proxy_issuer.u.rdnSequence.len;
2023 if (proxy_issuer.u.rdnSequence.len < 2
2024 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2025 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2026 oid_id_at_commonName()))
2028 ret = HX509_PROXY_CERT_NAME_WRONG;
2029 hx509_set_error_string(context, 0, ret,
2030 "Proxy name too short or "
2031 "does not have Common name "
2032 "at the top");
2033 goto out;
2036 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2037 proxy_issuer.u.rdnSequence.len -= 1;
2039 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer);
2040 if (ret != 0) {
2041 ret = HX509_PROXY_CERT_NAME_WRONG;
2042 hx509_set_error_string(context, 0, ret,
2043 "Proxy issuer name not as expected");
2044 goto out;
2047 break;
2048 } else {
2050 * Now we are done with the proxy certificates, this
2051 * cert was an EE cert and we we will fall though to
2052 * EE checking below.
2054 type = EE_CERT;
2055 /* FALLTHOUGH */
2058 case EE_CERT:
2060 * If there where any proxy certificates in the chain
2061 * (proxy_cert_depth > 0), check that the proxy issuer
2062 * matched proxy certificates "base" subject.
2064 if (proxy_cert_depth) {
2066 ret = _hx509_name_cmp(&proxy_issuer,
2067 &c->tbsCertificate.subject);
2068 if (ret) {
2069 ret = HX509_PROXY_CERT_NAME_WRONG;
2070 hx509_clear_error_string(context);
2071 goto out;
2073 if (cert->basename)
2074 hx509_name_free(&cert->basename);
2076 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2077 if (ret) {
2078 hx509_clear_error_string(context);
2079 goto out;
2083 break;
2086 ret = check_basic_constraints(context, c, type,
2087 i - proxy_cert_depth - selfsigned_depth);
2088 if (ret)
2089 goto out;
2092 * Don't check the trust anchors expiration time since they
2093 * are transported out of band, from RFC3820.
2095 if (i + 1 != path.len || CHECK_TA(ctx)) {
2097 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2098 if (t > ctx->time_now) {
2099 ret = HX509_CERT_USED_BEFORE_TIME;
2100 hx509_clear_error_string(context);
2101 goto out;
2103 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2104 if (t < ctx->time_now) {
2105 ret = HX509_CERT_USED_AFTER_TIME;
2106 hx509_clear_error_string(context);
2107 goto out;
2111 if (type == EE_CERT)
2112 type = CA_CERT;
2113 else if (type == PROXY_CERT)
2114 proxy_cert_depth++;
2118 * Verify constraints, do this backward so path constraints are
2119 * checked in the right order.
2122 for (ret = 0, i = path.len - 1; i >= 0; i--) {
2123 Certificate *c;
2125 c = _hx509_get_cert(path.val[i]);
2127 /* verify name constraints, not for selfsigned and anchor */
2128 if (!certificate_is_self_signed(c) || i + 1 != path.len) {
2129 ret = check_name_constraints(context, &nc, c);
2130 if (ret) {
2131 goto out;
2134 ret = add_name_constraints(context, c, i == 0, &nc);
2135 if (ret)
2136 goto out;
2138 /* XXX verify all other silly constraints */
2143 * Verify that no certificates has been revoked.
2146 if (ctx->revoke_ctx) {
2147 hx509_certs certs;
2149 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2150 NULL, &certs);
2151 if (ret)
2152 goto out;
2154 for (i = 0; i < path.len; i++) {
2155 ret = hx509_certs_add(context, certs, path.val[i]);
2156 if (ret) {
2157 hx509_certs_free(&certs);
2158 goto out;
2161 ret = hx509_certs_merge(context, certs, pool);
2162 if (ret) {
2163 hx509_certs_free(&certs);
2164 goto out;
2167 for (i = 0; i < path.len - 1; i++) {
2168 int parent = (i < path.len - 1) ? i + 1 : i;
2170 ret = hx509_revoke_verify(context,
2171 ctx->revoke_ctx,
2172 certs,
2173 ctx->time_now,
2174 path.val[i],
2175 path.val[parent]);
2176 if (ret) {
2177 hx509_certs_free(&certs);
2178 goto out;
2181 hx509_certs_free(&certs);
2185 * Verify signatures, do this backward so public key working
2186 * parameter is passed up from the anchor up though the chain.
2189 for (i = path.len - 1; i >= 0; i--) {
2190 Certificate *signer, *c;
2192 c = _hx509_get_cert(path.val[i]);
2194 /* is last in chain (trust anchor) */
2195 if (i + 1 == path.len) {
2196 signer = path.val[i]->data;
2198 /* if trust anchor is not self signed, don't check sig */
2199 if (!certificate_is_self_signed(signer))
2200 continue;
2201 } else {
2202 /* take next certificate in chain */
2203 signer = path.val[i + 1]->data;
2206 /* verify signatureValue */
2207 ret = _hx509_verify_signature_bitstring(context,
2208 signer,
2209 &c->signatureAlgorithm,
2210 &c->tbsCertificate._save,
2211 &c->signatureValue);
2212 if (ret) {
2213 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2214 "Failed to verify signature of certificate");
2215 goto out;
2219 out:
2220 hx509_certs_free(&anchors);
2221 free_Name(&proxy_issuer);
2222 free_name_constraints(&nc);
2223 _hx509_path_free(&path);
2225 return ret;
2229 * Verify a signature made using the private key of an certificate.
2231 * @param context A hx509 context.
2232 * @param signer the certificate that made the signature.
2233 * @param alg algorthm that was used to sign the data.
2234 * @param data the data that was signed.
2235 * @param sig the sigature to verify.
2237 * @return An hx509 error code, see hx509_get_error_string().
2239 * @ingroup hx509_crypto
2243 hx509_verify_signature(hx509_context context,
2244 const hx509_cert signer,
2245 const AlgorithmIdentifier *alg,
2246 const heim_octet_string *data,
2247 const heim_octet_string *sig)
2249 return _hx509_verify_signature(context, signer->data, alg, data, sig);
2254 * Verify that the certificate is allowed to be used for the hostname
2255 * and address.
2257 * @param context A hx509 context.
2258 * @param cert the certificate to match with
2259 * @param flags Flags to modify the behavior:
2260 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2261 * @param type type of hostname:
2262 * - HX509_HN_HOSTNAME for plain hostname.
2263 * - HX509_HN_DNSSRV for DNS SRV names.
2264 * @param hostname the hostname to check
2265 * @param sa address of the host
2266 * @param sa_size length of address
2268 * @return An hx509 error code, see hx509_get_error_string().
2270 * @ingroup hx509_cert
2274 hx509_verify_hostname(hx509_context context,
2275 const hx509_cert cert,
2276 int flags,
2277 hx509_hostname_type type,
2278 const char *hostname,
2279 const struct sockaddr *sa,
2280 /* XXX krb5_socklen_t */ int sa_size)
2282 GeneralNames san;
2283 int ret, i, j;
2285 if (sa && sa_size <= 0)
2286 return EINVAL;
2288 memset(&san, 0, sizeof(san));
2290 i = 0;
2291 do {
2292 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2293 if (ret == HX509_EXTENSION_NOT_FOUND) {
2294 ret = 0;
2295 break;
2296 } else if (ret != 0)
2297 break;
2299 for (j = 0; j < san.len; j++) {
2300 switch (san.val[j].element) {
2301 case choice_GeneralName_dNSName:
2302 if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2303 free_GeneralNames(&san);
2304 return 0;
2306 break;
2307 default:
2308 break;
2311 free_GeneralNames(&san);
2312 } while (1);
2315 Name *name = &cert->data->tbsCertificate.subject;
2317 /* match if first component is a CN= */
2318 if (name->u.rdnSequence.len > 0
2319 && name->u.rdnSequence.val[0].len == 1
2320 && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
2321 oid_id_at_commonName()) == 0)
2323 DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
2325 switch (ds->element) {
2326 case choice_DirectoryString_printableString:
2327 if (strcasecmp(ds->u.printableString, hostname) == 0)
2328 return 0;
2329 break;
2330 case choice_DirectoryString_ia5String:
2331 if (strcasecmp(ds->u.ia5String, hostname) == 0)
2332 return 0;
2333 break;
2334 case choice_DirectoryString_utf8String:
2335 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2336 return 0;
2337 default:
2338 break;
2343 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2344 ret = HX509_NAME_CONSTRAINT_ERROR;
2346 return ret;
2350 _hx509_set_cert_attribute(hx509_context context,
2351 hx509_cert cert,
2352 const heim_oid *oid,
2353 const heim_octet_string *attr)
2355 hx509_cert_attribute a;
2356 void *d;
2358 if (hx509_cert_get_attribute(cert, oid) != NULL)
2359 return 0;
2361 d = realloc(cert->attrs.val,
2362 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2363 if (d == NULL) {
2364 hx509_clear_error_string(context);
2365 return ENOMEM;
2367 cert->attrs.val = d;
2369 a = malloc(sizeof(*a));
2370 if (a == NULL)
2371 return ENOMEM;
2373 der_copy_octet_string(attr, &a->data);
2374 der_copy_oid(oid, &a->oid);
2376 cert->attrs.val[cert->attrs.len] = a;
2377 cert->attrs.len++;
2379 return 0;
2383 * Get an external attribute for the certificate, examples are
2384 * friendly name and id.
2386 * @param cert hx509 certificate object to search
2387 * @param oid an oid to search for.
2389 * @return an hx509_cert_attribute, only valid as long as the
2390 * certificate is referenced.
2392 * @ingroup hx509_cert
2395 hx509_cert_attribute
2396 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2398 int i;
2399 for (i = 0; i < cert->attrs.len; i++)
2400 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2401 return cert->attrs.val[i];
2402 return NULL;
2406 * Set the friendly name on the certificate.
2408 * @param cert The certificate to set the friendly name on
2409 * @param name Friendly name.
2411 * @return An hx509 error code, see hx509_get_error_string().
2413 * @ingroup hx509_cert
2417 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2419 if (cert->friendlyname)
2420 free(cert->friendlyname);
2421 cert->friendlyname = strdup(name);
2422 if (cert->friendlyname == NULL)
2423 return ENOMEM;
2424 return 0;
2428 * Get friendly name of the certificate.
2430 * @param cert cert to get the friendly name from.
2432 * @return an friendly name or NULL if there is. The friendly name is
2433 * only valid as long as the certificate is referenced.
2435 * @ingroup hx509_cert
2438 const char *
2439 hx509_cert_get_friendly_name(hx509_cert cert)
2441 hx509_cert_attribute a;
2442 PKCS9_friendlyName n;
2443 size_t sz;
2444 int ret, i;
2446 if (cert->friendlyname)
2447 return cert->friendlyname;
2449 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
2450 if (a == NULL) {
2451 /* XXX use subject name ? */
2452 return NULL;
2455 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2456 if (ret)
2457 return NULL;
2459 if (n.len != 1) {
2460 free_PKCS9_friendlyName(&n);
2461 return NULL;
2464 cert->friendlyname = malloc(n.val[0].length + 1);
2465 if (cert->friendlyname == NULL) {
2466 free_PKCS9_friendlyName(&n);
2467 return NULL;
2470 for (i = 0; i < n.val[0].length; i++) {
2471 if (n.val[0].data[i] <= 0xff)
2472 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2473 else
2474 cert->friendlyname[i] = 'X';
2476 cert->friendlyname[i] = '\0';
2477 free_PKCS9_friendlyName(&n);
2479 return cert->friendlyname;
2482 void
2483 _hx509_query_clear(hx509_query *q)
2485 memset(q, 0, sizeof(*q));
2489 * Allocate an query controller. Free using hx509_query_free().
2491 * @param context A hx509 context.
2492 * @param q return pointer to a hx509_query.
2494 * @return An hx509 error code, see hx509_get_error_string().
2496 * @ingroup hx509_cert
2500 hx509_query_alloc(hx509_context context, hx509_query **q)
2502 *q = calloc(1, sizeof(**q));
2503 if (*q == NULL)
2504 return ENOMEM;
2505 return 0;
2509 * Set match options for the hx509 query controller.
2511 * @param q query controller.
2512 * @param option options to control the query controller.
2514 * @return An hx509 error code, see hx509_get_error_string().
2516 * @ingroup hx509_cert
2519 void
2520 hx509_query_match_option(hx509_query *q, hx509_query_option option)
2522 switch(option) {
2523 case HX509_QUERY_OPTION_PRIVATE_KEY:
2524 q->match |= HX509_QUERY_PRIVATE_KEY;
2525 break;
2526 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2527 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2528 break;
2529 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2530 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2531 break;
2532 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2533 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2534 break;
2535 case HX509_QUERY_OPTION_END:
2536 default:
2537 break;
2542 * Set the issuer and serial number of match in the query
2543 * controller. The function make copies of the isser and serial number.
2545 * @param q a hx509 query controller
2546 * @param issuer issuer to search for
2547 * @param serialNumber the serialNumber of the issuer.
2549 * @return An hx509 error code, see hx509_get_error_string().
2551 * @ingroup hx509_cert
2555 hx509_query_match_issuer_serial(hx509_query *q,
2556 const Name *issuer,
2557 const heim_integer *serialNumber)
2559 int ret;
2560 if (q->serial) {
2561 der_free_heim_integer(q->serial);
2562 free(q->serial);
2564 q->serial = malloc(sizeof(*q->serial));
2565 if (q->serial == NULL)
2566 return ENOMEM;
2567 ret = der_copy_heim_integer(serialNumber, q->serial);
2568 if (ret) {
2569 free(q->serial);
2570 q->serial = NULL;
2571 return ret;
2573 if (q->issuer_name) {
2574 free_Name(q->issuer_name);
2575 free(q->issuer_name);
2577 q->issuer_name = malloc(sizeof(*q->issuer_name));
2578 if (q->issuer_name == NULL)
2579 return ENOMEM;
2580 ret = copy_Name(issuer, q->issuer_name);
2581 if (ret) {
2582 free(q->issuer_name);
2583 q->issuer_name = NULL;
2584 return ret;
2586 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2587 return 0;
2591 * Set the query controller to match on a friendly name
2593 * @param q a hx509 query controller.
2594 * @param name a friendly name to match on
2596 * @return An hx509 error code, see hx509_get_error_string().
2598 * @ingroup hx509_cert
2602 hx509_query_match_friendly_name(hx509_query *q, const char *name)
2604 if (q->friendlyname)
2605 free(q->friendlyname);
2606 q->friendlyname = strdup(name);
2607 if (q->friendlyname == NULL)
2608 return ENOMEM;
2609 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2610 return 0;
2614 * Set the query controller to match using a specific match function.
2616 * @param q a hx509 query controller.
2617 * @param func function to use for matching, if the argument is NULL,
2618 * the match function is removed.
2619 * @param ctx context passed to the function.
2621 * @return An hx509 error code, see hx509_get_error_string().
2623 * @ingroup hx509_cert
2627 hx509_query_match_cmp_func(hx509_query *q,
2628 int (*func)(void *, hx509_cert),
2629 void *ctx)
2631 if (func)
2632 q->match |= HX509_QUERY_MATCH_FUNCTION;
2633 else
2634 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2635 q->cmp_func = func;
2636 q->cmp_func_ctx = ctx;
2637 return 0;
2641 * Free the query controller.
2643 * @param context A hx509 context.
2644 * @param q a pointer to the query controller.
2646 * @ingroup hx509_cert
2649 void
2650 hx509_query_free(hx509_context context, hx509_query *q)
2652 if (q->serial) {
2653 der_free_heim_integer(q->serial);
2654 free(q->serial);
2655 q->serial = NULL;
2657 if (q->issuer_name) {
2658 free_Name(q->issuer_name);
2659 free(q->issuer_name);
2660 q->issuer_name = NULL;
2662 if (q) {
2663 free(q->friendlyname);
2664 memset(q, 0, sizeof(*q));
2666 free(q);
2670 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2672 Certificate *c = _hx509_get_cert(cert);
2674 _hx509_query_statistic(context, 1, q);
2676 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2677 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2678 return 0;
2680 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2681 _hx509_Certificate_cmp(q->certificate, c) != 0)
2682 return 0;
2684 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2685 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2686 return 0;
2688 if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
2689 && _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
2690 return 0;
2692 if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
2693 && _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
2694 return 0;
2696 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2697 SubjectKeyIdentifier si;
2698 int ret;
2700 ret = _hx509_find_extension_subject_key_id(c, &si);
2701 if (ret == 0) {
2702 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2703 ret = 1;
2704 free_SubjectKeyIdentifier(&si);
2706 if (ret)
2707 return 0;
2709 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2710 return 0;
2711 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2712 _hx509_cert_private_key(cert) == NULL)
2713 return 0;
2716 unsigned ku = 0;
2717 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2718 ku |= (1 << 0);
2719 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2720 ku |= (1 << 1);
2721 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2722 ku |= (1 << 2);
2723 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2724 ku |= (1 << 3);
2725 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2726 ku |= (1 << 4);
2727 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2728 ku |= (1 << 5);
2729 if (q->match & HX509_QUERY_KU_CRLSIGN)
2730 ku |= (1 << 6);
2731 if (ku && check_key_usage(context, c, ku, TRUE))
2732 return 0;
2734 if ((q->match & HX509_QUERY_ANCHOR))
2735 return 0;
2737 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2738 hx509_cert_attribute a;
2740 a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2741 if (a == NULL)
2742 return 0;
2743 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2744 return 0;
2747 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2748 size_t i;
2750 for (i = 0; i < q->path->len; i++)
2751 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2752 return 0;
2754 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2755 const char *name = hx509_cert_get_friendly_name(cert);
2756 if (name == NULL)
2757 return 0;
2758 if (strcasecmp(q->friendlyname, name) != 0)
2759 return 0;
2761 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2762 int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2763 if (ret != 0)
2764 return 0;
2767 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2768 heim_octet_string os;
2769 int ret;
2771 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2772 os.length =
2773 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2775 ret = _hx509_verify_signature(context,
2776 NULL,
2777 hx509_signature_sha1(),
2778 &os,
2779 q->keyhash_sha1);
2780 if (ret != 0)
2781 return 0;
2784 if (q->match & HX509_QUERY_MATCH_TIME) {
2785 time_t t;
2786 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2787 if (t > q->timenow)
2788 return 0;
2789 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2790 if (t < q->timenow)
2791 return 0;
2794 if (q->match & ~HX509_QUERY_MASK)
2795 return 0;
2797 return 1;
2801 * Set a statistic file for the query statistics.
2803 * @param context A hx509 context.
2804 * @param fn statistics file name
2806 * @ingroup hx509_cert
2809 void
2810 hx509_query_statistic_file(hx509_context context, const char *fn)
2812 if (context->querystat)
2813 free(context->querystat);
2814 context->querystat = strdup(fn);
2817 void
2818 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2820 FILE *f;
2821 if (context->querystat == NULL)
2822 return;
2823 f = fopen(context->querystat, "a");
2824 if (f == NULL)
2825 return;
2826 fprintf(f, "%d %d\n", type, q->match);
2827 fclose(f);
2830 static const char *statname[] = {
2831 "find issuer cert",
2832 "match serialnumber",
2833 "match issuer name",
2834 "match subject name",
2835 "match subject key id",
2836 "match issuer id",
2837 "private key",
2838 "ku encipherment",
2839 "ku digitalsignature",
2840 "ku keycertsign",
2841 "ku crlsign",
2842 "ku nonrepudiation",
2843 "ku keyagreement",
2844 "ku dataencipherment",
2845 "anchor",
2846 "match certificate",
2847 "match local key id",
2848 "no match path",
2849 "match friendly name",
2850 "match function",
2851 "match key hash sha1",
2852 "match time"
2855 struct stat_el {
2856 unsigned long stats;
2857 unsigned int index;
2861 static int
2862 stat_sort(const void *a, const void *b)
2864 const struct stat_el *ae = a;
2865 const struct stat_el *be = b;
2866 return be->stats - ae->stats;
2870 * Unparse the statistics file and print the result on a FILE descriptor.
2872 * @param context A hx509 context.
2873 * @param printtype tyep to print
2874 * @param out the FILE to write the data on.
2876 * @ingroup hx509_cert
2879 void
2880 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
2882 rtbl_t t;
2883 FILE *f;
2884 int type, mask, i, num;
2885 unsigned long multiqueries = 0, totalqueries = 0;
2886 struct stat_el stats[32];
2888 if (context->querystat == NULL)
2889 return;
2890 f = fopen(context->querystat, "r");
2891 if (f == NULL) {
2892 fprintf(out, "No statistic file %s: %s.\n",
2893 context->querystat, strerror(errno));
2894 return;
2897 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2898 stats[i].index = i;
2899 stats[i].stats = 0;
2902 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
2903 if (type != printtype)
2904 continue;
2905 num = i = 0;
2906 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
2907 if (mask & 1) {
2908 stats[i].stats++;
2909 num++;
2911 mask = mask >>1 ;
2912 i++;
2914 if (num > 1)
2915 multiqueries++;
2916 totalqueries++;
2918 fclose(f);
2920 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
2922 t = rtbl_create();
2923 if (t == NULL)
2924 errx(1, "out of memory");
2926 rtbl_set_separator (t, " ");
2928 rtbl_add_column_by_id (t, 0, "Name", 0);
2929 rtbl_add_column_by_id (t, 1, "Counter", 0);
2932 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2933 char str[10];
2935 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
2936 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
2937 else {
2938 snprintf(str, sizeof(str), "%d", stats[i].index);
2939 rtbl_add_column_entry_by_id (t, 0, str);
2941 snprintf(str, sizeof(str), "%lu", stats[i].stats);
2942 rtbl_add_column_entry_by_id (t, 1, str);
2945 rtbl_format(t, out);
2946 rtbl_destroy(t);
2948 fprintf(out, "\nQueries: multi %lu total %lu\n",
2949 multiqueries, totalqueries);
2953 * Check the extended key usage on the hx509 certificate.
2955 * @param context A hx509 context.
2956 * @param cert A hx509 context.
2957 * @param eku the EKU to check for
2958 * @param allow_any_eku if the any EKU is set, allow that to be a
2959 * substitute.
2961 * @return An hx509 error code, see hx509_get_error_string().
2963 * @ingroup hx509_cert
2967 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
2968 const heim_oid *eku, int allow_any_eku)
2970 ExtKeyUsage e;
2971 int ret, i;
2973 ret = find_extension_eku(_hx509_get_cert(cert), &e);
2974 if (ret) {
2975 hx509_clear_error_string(context);
2976 return ret;
2979 for (i = 0; i < e.len; i++) {
2980 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
2981 free_ExtKeyUsage(&e);
2982 return 0;
2984 if (allow_any_eku) {
2985 #if 0
2986 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
2987 free_ExtKeyUsage(&e);
2988 return 0;
2990 #endif
2993 free_ExtKeyUsage(&e);
2994 hx509_clear_error_string(context);
2995 return HX509_CERTIFICATE_MISSING_EKU;
2999 _hx509_cert_get_keyusage(hx509_context context,
3000 hx509_cert c,
3001 KeyUsage *ku)
3003 Certificate *cert;
3004 const Extension *e;
3005 size_t size;
3006 int ret, i = 0;
3008 memset(ku, 0, sizeof(*ku));
3010 cert = _hx509_get_cert(c);
3012 if (_hx509_cert_get_version(cert) < 3)
3013 return 0;
3015 e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
3016 if (e == NULL)
3017 return HX509_KU_CERT_MISSING;
3019 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3020 if (ret)
3021 return ret;
3022 return 0;
3026 _hx509_cert_get_eku(hx509_context context,
3027 hx509_cert cert,
3028 ExtKeyUsage *e)
3030 int ret;
3032 memset(e, 0, sizeof(*e));
3034 ret = find_extension_eku(_hx509_get_cert(cert), e);
3035 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3036 hx509_clear_error_string(context);
3037 return ret;
3039 return 0;
3043 * Encodes the hx509 certificate as a DER encode binary.
3045 * @param context A hx509 context.
3046 * @param c the certificate to encode.
3047 * @param os the encode certificate, set to NULL, 0 on case of
3048 * error. Free the returned structure with hx509_xfree().
3050 * @return An hx509 error code, see hx509_get_error_string().
3052 * @ingroup hx509_cert
3056 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3058 size_t size;
3059 int ret;
3061 os->data = NULL;
3062 os->length = 0;
3064 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3065 _hx509_get_cert(c), &size, ret);
3066 if (ret) {
3067 os->data = NULL;
3068 os->length = 0;
3069 return ret;
3071 if (os->length != size)
3072 _hx509_abort("internal ASN.1 encoder error");
3074 return ret;
3078 * Last to avoid lost __attribute__s due to #undef.
3081 #undef __attribute__
3082 #define __attribute__(X)
3084 void
3085 _hx509_abort(const char *fmt, ...)
3086 __attribute__ ((noreturn, format (printf, 1, 2)))
3088 va_list ap;
3089 va_start(ap, fmt);
3090 vprintf(fmt, ap);
3091 va_end(ap);
3092 printf("\n");
3093 fflush(stdout);
3094 abort();
3098 * Free a data element allocated in the library.
3100 * @param ptr data to be freed.
3102 * @ingroup hx509_misc
3105 void
3106 hx509_xfree(void *ptr)
3108 free(ptr);