cf/largefile.m4: Fix build with autoconf-2.72
[heimdal.git] / lib / hx509 / cert.c
blob9c7997dc46e4923d98c91ee10f4df97e5e00485c
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 #include "crypto-headers.h"
36 #include <rtbl.h>
38 /**
39 * @page page_cert The basic certificate
41 * The basic hx509 cerificate object in hx509 is hx509_cert. The
42 * hx509_cert object is representing one X509/PKIX certificate and
43 * associated attributes; like private key, friendly name, etc.
45 * A hx509_cert object is usully found via the keyset interfaces (@ref
46 * page_keyset), but its also possible to create a certificate
47 * directly from a parsed object with hx509_cert_init() and
48 * hx509_cert_init_data().
50 * See the library functions here: @ref hx509_cert
53 struct hx509_verify_ctx_data {
54 hx509_certs trust_anchors;
55 int flags;
56 #define HX509_VERIFY_CTX_F_TIME_SET 1
57 #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2
58 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4
59 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8
60 #define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16
61 #define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32
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 static void
97 init_context_once(void *ignored)
100 ENGINE_add_conf_module();
101 OpenSSL_add_all_algorithms();
105 * Return a cookie identifying this instance of a library.
107 * Inputs:
109 * @context A krb5_context
110 * @module Our library name or a library we depend on
112 * Outputs: The instance cookie
114 * @ingroup krb5_support
117 HX509_LIB_FUNCTION uintptr_t HX509_LIB_CALL
118 hx509_get_instance(const char *libname)
120 static const char *instance = "libhx509";
122 if (strcmp(libname, "hx509") == 0)
123 return (uintptr_t)instance;
125 return 0;
128 #ifndef PATH_SEP
129 # define PATH_SEP ":"
130 #endif
131 static const char *hx509_config_file =
132 "~/.hx509/config" PATH_SEP
133 SYSCONFDIR "/hx509.conf" PATH_SEP
134 #ifdef _WIN32
135 "%{COMMON_APPDATA}/Heimdal/hx509.conf" PATH_SEP
136 "%{WINDOWS}/hx509.ini"
137 #else /* _WIN32 */
138 "/etc/hx509.conf"
139 #endif /* _WIN32 */
143 * Creates a hx509 context that most functions in the library
144 * uses. The context is only allowed to be used by one thread at each
145 * moment. Free the context with hx509_context_free().
147 * @param context Returns a pointer to new hx509 context.
149 * @return Returns an hx509 error code.
151 * @ingroup hx509
154 HX509_LIB_FUNCTION int HX509_LIB_CALL
155 hx509_context_init(hx509_context *contextp)
157 static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT;
158 heim_error_code ret;
159 hx509_context context;
160 const char *anchors;
161 char **files = NULL;
163 *contextp = NULL;
164 context = calloc(1, sizeof(*context));
165 if (context == NULL)
166 return ENOMEM;
168 heim_base_once_f(&init_context, NULL, init_context_once);
170 if ((context->hcontext = heim_context_init()) == NULL) {
171 free(context);
172 return ENOMEM;
175 if ((ret = heim_get_default_config_files(hx509_config_file,
176 "HX509_CONFIG",
177 &files))) {
178 heim_context_free(&context->hcontext);
179 free(context);
180 return ret;
183 /* If there's no hx509 config, we continue, as we never needed it before */
184 if (files)
185 (void) heim_set_config_files(context->hcontext, files, &context->cf);
186 heim_free_config_files(files);
188 _hx509_ks_null_register(context);
189 _hx509_ks_mem_register(context);
190 _hx509_ks_file_register(context);
191 _hx509_ks_pkcs12_register(context);
192 _hx509_ks_pkcs11_register(context);
193 _hx509_ks_dir_register(context);
194 _hx509_ks_keychain_register(context);
196 context->ocsp_time_diff =
197 heim_config_get_time_default(context->hcontext, context->cf,
198 HX509_DEFAULT_OCSP_TIME_DIFF,
199 "libdefaults", "ocsp_time_dif", NULL);
201 initialize_hx_error_table_r(&context->et_list);
202 initialize_asn1_error_table_r(&context->et_list);
204 #ifdef HX509_DEFAULT_ANCHORS
205 anchors = heim_config_get_string_default(context->hcontext, context->cf,
206 HX509_DEFAULT_ANCHORS,
207 "libdefaults", "anchors", NULL);
208 #else
209 anchors = heim_config_get_string(context->hcontext, context->cf,
210 "libdefaults", "anchors", NULL);
211 #endif
212 if (anchors)
213 (void)hx509_certs_init(context, anchors, 0, NULL,
214 &context->default_trust_anchors);
216 *contextp = context;
217 return 0;
220 HX509_LIB_FUNCTION int HX509_LIB_CALL
221 hx509_set_log_dest(hx509_context context, heim_log_facility *fac)
223 return heim_set_log_dest(context->hcontext, fac);
226 HX509_LIB_FUNCTION int HX509_LIB_CALL
227 hx509_set_debug_dest(hx509_context context, heim_log_facility *fac)
229 return heim_set_debug_dest(context->hcontext, fac);
232 HX509_LIB_FUNCTION int HX509_LIB_CALL
233 hx509_set_warn_dest(hx509_context context, heim_log_facility *fac)
235 return heim_set_warn_dest(context->hcontext, fac);
239 * Selects if the hx509_revoke_verify() function is going to require
240 * the existence of a revocation method (OCSP, CRL) or not. Note that
241 * hx509_verify_path(), hx509_cms_verify_signed(), and other functions
242 * call hx509_revoke_verify().
244 * @param context hx509 context to change the flag for.
245 * @param flag zero, revocation method required, non zero missing
246 * revocation method ok
248 * @ingroup hx509_verify
251 HX509_LIB_FUNCTION void HX509_LIB_CALL
252 hx509_context_set_missing_revoke(hx509_context context, int flag)
254 if (flag)
255 context->flags |= HX509_CTX_VERIFY_MISSING_OK;
256 else
257 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
261 * Free the context allocated by hx509_context_init().
263 * @param context context to be freed.
265 * @ingroup hx509
268 HX509_LIB_FUNCTION void HX509_LIB_CALL
269 hx509_context_free(hx509_context *context)
271 if (!*context)
272 return;
274 hx509_clear_error_string(*context);
275 if ((*context)->ks_ops) {
276 free((*context)->ks_ops);
277 (*context)->ks_ops = NULL;
279 (*context)->ks_num_ops = 0;
280 free_error_table ((*context)->et_list);
281 if ((*context)->querystat)
282 free((*context)->querystat);
283 hx509_certs_free(&(*context)->default_trust_anchors);
284 heim_config_file_free((*context)->hcontext, (*context)->cf);
285 heim_context_free(&(*context)->hcontext);
286 memset(*context, 0, sizeof(**context));
287 free(*context);
288 *context = NULL;
295 HX509_LIB_FUNCTION Certificate * HX509_LIB_CALL
296 _hx509_get_cert(hx509_cert cert)
298 return cert->data;
305 HX509_LIB_FUNCTION int HX509_LIB_CALL
306 _hx509_cert_get_version(const Certificate *t)
308 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
311 static hx509_cert
312 cert_init(hx509_context context, heim_error_t *error)
314 hx509_cert cert;
316 cert = malloc(sizeof(*cert));
317 if (cert == NULL) {
318 if (error)
319 *error = heim_error_create_enomem();
320 return NULL;
322 cert->ref = 1;
323 cert->friendlyname = NULL;
324 cert->attrs.len = 0;
325 cert->attrs.val = NULL;
326 cert->private_key = NULL;
327 cert->basename = NULL;
328 cert->release = NULL;
329 cert->ctx = NULL;
330 cert->data= NULL;
331 return cert;
335 * Allocate and init an hx509 certificate object from the decoded
336 * certificate `c´.
338 * @param context A hx509 context.
339 * @param c
340 * @param error
342 * @return Returns an hx509 certificate
344 * @ingroup hx509_cert
347 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
348 hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error)
350 hx509_cert cert;
351 int ret;
353 if ((cert = cert_init(context, error)) == NULL)
354 return NULL;
356 cert->data = calloc(1, sizeof(*(cert->data)));
357 if (cert->data == NULL) {
358 free(cert);
359 if (error)
360 *error = heim_error_create_enomem();
361 return NULL;
363 ret = copy_Certificate(c, cert->data);
364 if (ret) {
365 free(cert->data);
366 free(cert);
367 cert = NULL;
369 return cert;
373 * Copy a certificate object, but drop any private key assignment.
375 * @param context A hx509 context.
376 * @param src Certificate object
377 * @param error
379 * @return Returns an hx509 certificate
381 * @ingroup hx509_cert
384 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
385 hx509_cert_copy_no_private_key(hx509_context context,
386 hx509_cert src,
387 heim_error_t *error)
389 return hx509_cert_init(context, src->data, error);
393 * Allocate and init an hx509 certificate object containing only a private key
394 * (but no Certificate).
396 * @param context A hx509 context.
397 * @param key
398 * @param error
400 * @return Returns an hx509 certificate
402 * @ingroup hx509_cert
405 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
406 hx509_cert_init_private_key(hx509_context context,
407 hx509_private_key key,
408 heim_error_t *error)
410 hx509_cert cert;
412 if ((cert = cert_init(context, error)))
413 (void) _hx509_cert_assign_key(cert, key);
414 return cert;
418 * Just like hx509_cert_init(), but instead of a decode certificate
419 * takes an pointer and length to a memory region that contains a
420 * DER/BER encoded certificate.
422 * If the memory region doesn't contain just the certificate and
423 * nothing more the function will fail with
424 * HX509_EXTRA_DATA_AFTER_STRUCTURE.
426 * @param context A hx509 context.
427 * @param ptr pointer to memory region containing encoded certificate.
428 * @param len length of memory region.
429 * @param error possibly returns an error
431 * @return An hx509 certificate
433 * @ingroup hx509_cert
436 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
437 hx509_cert_init_data(hx509_context context,
438 const void *ptr,
439 size_t len,
440 heim_error_t *error)
442 hx509_cert cert;
443 Certificate t;
444 size_t size;
445 int ret;
447 ret = decode_Certificate(ptr, len, &t, &size);
448 if (ret) {
449 if (error)
450 *error = heim_error_create(ret, "Failed to decode certificate");
451 errno = ret;
452 return NULL;
454 if (size != len) {
455 free_Certificate(&t);
456 if (error)
457 *error = heim_error_create(HX509_EXTRA_DATA_AFTER_STRUCTURE,
458 "Extra data after certificate");
459 errno = HX509_EXTRA_DATA_AFTER_STRUCTURE;
460 return NULL;
463 cert = hx509_cert_init(context, &t, error);
464 free_Certificate(&t);
465 return cert;
468 HX509_LIB_FUNCTION void HX509_LIB_CALL
469 _hx509_cert_set_release(hx509_cert cert,
470 _hx509_cert_release_func release,
471 void *ctx)
473 cert->release = release;
474 cert->ctx = ctx;
478 /* Doesn't make a copy of `private_key'. */
480 HX509_LIB_FUNCTION int HX509_LIB_CALL
481 _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
483 if (cert->private_key)
484 hx509_private_key_free(&cert->private_key);
485 cert->private_key = _hx509_private_key_ref(private_key);
486 return 0;
490 * Free reference to the hx509 certificate object, if the refcounter
491 * reaches 0, the object if freed. Its allowed to pass in NULL.
493 * @param cert the cert to free.
495 * @ingroup hx509_cert
498 HX509_LIB_FUNCTION void HX509_LIB_CALL
499 hx509_cert_free(hx509_cert cert)
501 size_t i;
503 if (cert == NULL)
504 return;
506 if (cert->ref <= 0)
507 _hx509_abort("cert refcount <= 0 on free");
508 if (--cert->ref > 0)
509 return;
511 if (cert->release)
512 (cert->release)(cert, cert->ctx);
514 if (cert->private_key)
515 hx509_private_key_free(&cert->private_key);
517 if (cert->data)
518 free_Certificate(cert->data);
519 free(cert->data);
521 for (i = 0; i < cert->attrs.len; i++) {
522 der_free_octet_string(&cert->attrs.val[i]->data);
523 der_free_oid(&cert->attrs.val[i]->oid);
524 free(cert->attrs.val[i]);
526 free(cert->attrs.val);
527 free(cert->friendlyname);
528 if (cert->basename)
529 hx509_name_free(&cert->basename);
530 memset(cert, 0, sizeof(*cert));
531 free(cert);
535 * Add a reference to a hx509 certificate object.
537 * @param cert a pointer to an hx509 certificate object.
539 * @return the same object as is passed in.
541 * @ingroup hx509_cert
544 HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
545 hx509_cert_ref(hx509_cert cert)
547 if (cert == NULL)
548 return NULL;
549 if (cert->ref <= 0)
550 _hx509_abort("cert refcount <= 0");
551 cert->ref++;
552 if (cert->ref == 0)
553 _hx509_abort("cert refcount == 0");
554 return cert;
558 * Allocate an verification context that is used to control the
559 * verification process.
561 * @param context A hx509 context.
562 * @param ctx returns a pointer to a hx509_verify_ctx object.
564 * @return An hx509 error code, see hx509_get_error_string().
566 * @ingroup hx509_verify
569 HX509_LIB_FUNCTION int HX509_LIB_CALL
570 hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
572 hx509_verify_ctx c;
574 c = calloc(1, sizeof(*c));
575 if (c == NULL)
576 return ENOMEM;
578 c->max_depth = HX509_VERIFY_MAX_DEPTH;
580 *ctx = c;
582 return 0;
586 * Free an hx509 verification context.
588 * @param ctx the context to be freed.
590 * @ingroup hx509_verify
593 HX509_LIB_FUNCTION void HX509_LIB_CALL
594 hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
596 if (ctx) {
597 hx509_certs_free(&ctx->trust_anchors);
598 hx509_revoke_free(&ctx->revoke_ctx);
599 memset(ctx, 0, sizeof(*ctx));
601 free(ctx);
605 * Set the trust anchors in the verification context, makes an
606 * reference to the keyset, so the consumer can free the keyset
607 * independent of the destruction of the verification context (ctx).
608 * If there already is a keyset attached, it's released.
610 * @param ctx a verification context
611 * @param set a keyset containing the trust anchors.
613 * @ingroup hx509_verify
616 HX509_LIB_FUNCTION void HX509_LIB_CALL
617 hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
619 if (ctx->trust_anchors)
620 hx509_certs_free(&ctx->trust_anchors);
621 ctx->trust_anchors = hx509_certs_ref(set);
625 * Attach an revocation context to the verfication context, , makes an
626 * reference to the revoke context, so the consumer can free the
627 * revoke context independent of the destruction of the verification
628 * context. If there is no revoke context, the verification process is
629 * NOT going to check any verification status.
631 * @param ctx a verification context.
632 * @param revoke_ctx a revoke context.
634 * @ingroup hx509_verify
637 HX509_LIB_FUNCTION void HX509_LIB_CALL
638 hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
640 if (ctx->revoke_ctx)
641 hx509_revoke_free(&ctx->revoke_ctx);
642 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
646 * Set the clock time the the verification process is going to
647 * use. Used to check certificate in the past and future time. If not
648 * set the current time will be used.
650 * @param ctx a verification context.
651 * @param t the time the verifiation is using.
654 * @ingroup hx509_verify
657 HX509_LIB_FUNCTION void HX509_LIB_CALL
658 hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
660 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
661 ctx->time_now = t;
664 HX509_LIB_FUNCTION time_t HX509_LIB_CALL
665 _hx509_verify_get_time(hx509_verify_ctx ctx)
667 return ctx->time_now;
671 * Set the maximum depth of the certificate chain that the path
672 * builder is going to try.
674 * @param ctx a verification context
675 * @param max_depth maxium depth of the certificate chain, include
676 * trust anchor.
678 * @ingroup hx509_verify
681 HX509_LIB_FUNCTION void HX509_LIB_CALL
682 hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
684 ctx->max_depth = max_depth;
688 * Allow or deny the use of proxy certificates
690 * @param ctx a verification context
691 * @param boolean if non zero, allow proxy certificates.
693 * @ingroup hx509_verify
696 HX509_LIB_FUNCTION void HX509_LIB_CALL
697 hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
699 if (boolean)
700 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
701 else
702 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
706 * Select strict RFC3280 verification of certificiates. This means
707 * checking key usage on CA certificates, this will make version 1
708 * certificiates unuseable.
710 * @param ctx a verification context
711 * @param boolean if non zero, use strict verification.
713 * @ingroup hx509_verify
716 HX509_LIB_FUNCTION void HX509_LIB_CALL
717 hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
719 if (boolean)
720 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
721 else
722 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
726 * Allow using the operating system builtin trust anchors if no other
727 * trust anchors are configured.
729 * @param ctx a verification context
730 * @param boolean if non zero, useing the operating systems builtin
731 * trust anchors.
734 * @return An hx509 error code, see hx509_get_error_string().
736 * @ingroup hx509_cert
739 HX509_LIB_FUNCTION void HX509_LIB_CALL
740 hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
742 if (boolean)
743 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
744 else
745 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
748 HX509_LIB_FUNCTION void HX509_LIB_CALL
749 hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
750 int boolean)
752 if (boolean)
753 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
754 else
755 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
758 static const Extension *
759 find_extension(const Certificate *cert, const heim_oid *oid, size_t *idx)
761 const TBSCertificate *c = &cert->tbsCertificate;
763 if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
764 return NULL;
766 for (;*idx < c->extensions->len; (*idx)++) {
767 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
768 return &c->extensions->val[(*idx)++];
770 return NULL;
773 static int
774 find_extension_auth_key_id(const Certificate *subject,
775 AuthorityKeyIdentifier *ai)
777 const Extension *e;
778 size_t size;
779 size_t i = 0;
781 memset(ai, 0, sizeof(*ai));
783 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
784 if (e == NULL)
785 return HX509_EXTENSION_NOT_FOUND;
787 return decode_AuthorityKeyIdentifier(e->extnValue.data,
788 e->extnValue.length,
789 ai, &size);
792 HX509_LIB_FUNCTION int HX509_LIB_CALL
793 _hx509_find_extension_subject_key_id(const Certificate *issuer,
794 SubjectKeyIdentifier *si)
796 const Extension *e;
797 size_t size;
798 size_t i = 0;
800 memset(si, 0, sizeof(*si));
802 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
803 if (e == NULL)
804 return HX509_EXTENSION_NOT_FOUND;
806 return decode_SubjectKeyIdentifier(e->extnValue.data,
807 e->extnValue.length,
808 si, &size);
811 static int
812 find_extension_name_constraints(const Certificate *subject,
813 NameConstraints *nc)
815 const Extension *e;
816 size_t size;
817 size_t i = 0;
819 memset(nc, 0, sizeof(*nc));
821 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
822 if (e == NULL)
823 return HX509_EXTENSION_NOT_FOUND;
825 return decode_NameConstraints(e->extnValue.data,
826 e->extnValue.length,
827 nc, &size);
830 static int
831 find_extension_subject_alt_name(const Certificate *cert, size_t *i,
832 GeneralNames *sa)
834 const Extension *e;
835 size_t size;
837 memset(sa, 0, sizeof(*sa));
839 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
840 if (e == NULL)
841 return HX509_EXTENSION_NOT_FOUND;
843 return decode_GeneralNames(e->extnValue.data,
844 e->extnValue.length,
845 sa, &size);
848 static int
849 find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
851 const Extension *e;
852 size_t size;
853 size_t i = 0;
855 memset(eku, 0, sizeof(*eku));
857 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
858 if (e == NULL)
859 return HX509_EXTENSION_NOT_FOUND;
861 return decode_ExtKeyUsage(e->extnValue.data,
862 e->extnValue.length,
863 eku, &size);
866 static int
867 add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
869 void *p;
870 int ret;
872 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
873 if (p == NULL)
874 return ENOMEM;
875 list->val = p;
876 ret = der_copy_octet_string(entry, &list->val[list->len]);
877 if (ret)
878 return ret;
879 list->len++;
880 return 0;
884 * Free a list of octet strings returned by another hx509 library
885 * function.
887 * @param list list to be freed.
889 * @ingroup hx509_misc
892 HX509_LIB_FUNCTION void HX509_LIB_CALL
893 hx509_free_octet_string_list(hx509_octet_string_list *list)
895 size_t i;
897 if (list->val) {
898 for (i = 0; i < list->len; i++)
899 der_free_octet_string(&list->val[i]);
900 free(list->val);
902 list->val = NULL;
903 list->len = 0;
907 * Return a list of subjectAltNames specified by oid in the
908 * certificate. On error the
910 * The returned list of octet string should be freed with
911 * hx509_free_octet_string_list().
913 * @param context A hx509 context.
914 * @param cert a hx509 certificate object.
915 * @param oid an oid to for SubjectAltName.
916 * @param list list of matching SubjectAltName.
918 * @return An hx509 error code, see hx509_get_error_string().
920 * @ingroup hx509_cert
923 HX509_LIB_FUNCTION int HX509_LIB_CALL
924 hx509_cert_find_subjectAltName_otherName(hx509_context context,
925 hx509_cert cert,
926 const heim_oid *oid,
927 hx509_octet_string_list *list)
929 GeneralNames sa;
930 int ret;
931 size_t i, j;
933 list->val = NULL;
934 list->len = 0;
936 i = 0;
937 while (1) {
938 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
939 i++;
940 if (ret == HX509_EXTENSION_NOT_FOUND) {
941 return 0;
942 } else if (ret != 0) {
943 hx509_set_error_string(context, 0, ret, "Error searching for SAN");
944 hx509_free_octet_string_list(list);
945 return ret;
948 for (j = 0; j < sa.len; j++) {
949 if (sa.val[j].element == choice_GeneralName_otherName &&
950 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
952 ret = add_to_list(list, &sa.val[j].u.otherName.value);
953 if (ret) {
954 hx509_set_error_string(context, 0, ret,
955 "Error adding an extra SAN to "
956 "return list");
957 hx509_free_octet_string_list(list);
958 free_GeneralNames(&sa);
959 return ret;
963 free_GeneralNames(&sa);
968 static int
969 check_key_usage(hx509_context context, const Certificate *cert,
970 unsigned flags, int req_present)
972 const Extension *e;
973 KeyUsage ku;
974 size_t size;
975 int ret;
976 size_t i = 0;
977 uint64_t ku_flags;
979 if (_hx509_cert_get_version(cert) < 3)
980 return 0;
982 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
983 if (e == NULL) {
984 if (req_present) {
985 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
986 "Required extension key "
987 "usage missing from certificate");
988 return HX509_KU_CERT_MISSING;
990 return 0;
993 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
994 if (ret)
995 return ret;
996 ku_flags = KeyUsage2int(ku);
997 if ((ku_flags & flags) != flags) {
998 uint64_t missing = (~ku_flags) & flags;
999 char buf[256], *name;
1001 int result = unparse_flags(missing, asn1_KeyUsage_units(),
1002 buf, sizeof(buf));
1003 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
1004 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
1005 "Key usage %s required but missing "
1006 "from certificate %s",
1007 (result > 0) ? buf : "<unknown>",
1008 name ? name : "<unknown>");
1009 free(name);
1010 return HX509_KU_CERT_MISSING;
1012 return 0;
1016 * Return 0 on matching key usage 'flags' for 'cert', otherwise return
1017 * an error code. If 'req_present' the existence is required of the
1018 * KeyUsage extension.
1021 HX509_LIB_FUNCTION int HX509_LIB_CALL
1022 _hx509_check_key_usage(hx509_context context, hx509_cert cert,
1023 unsigned flags, int req_present)
1025 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
1028 enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
1030 static int
1031 check_basic_constraints(hx509_context context, const Certificate *cert,
1032 enum certtype type, size_t depth)
1034 BasicConstraints bc;
1035 const Extension *e;
1036 size_t size;
1037 int ret;
1038 size_t i = 0;
1040 if (_hx509_cert_get_version(cert) < 3)
1041 return 0;
1043 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
1044 if (e == NULL) {
1045 switch(type) {
1046 case PROXY_CERT:
1047 case EE_CERT:
1048 return 0;
1049 case CA_CERT: {
1050 char *name;
1051 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
1052 assert(ret == 0);
1053 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
1054 "basicConstraints missing from "
1055 "CA certifiacte %s", name);
1056 free(name);
1057 return HX509_EXTENSION_NOT_FOUND;
1062 ret = decode_BasicConstraints(e->extnValue.data,
1063 e->extnValue.length, &bc,
1064 &size);
1065 if (ret)
1066 return ret;
1067 switch(type) {
1068 case PROXY_CERT:
1069 if (bc.cA)
1070 ret = HX509_PARENT_IS_CA;
1071 break;
1072 case EE_CERT:
1073 ret = 0;
1074 break;
1075 case CA_CERT:
1076 if (!bc.cA)
1077 ret = HX509_PARENT_NOT_CA;
1078 else if (bc.pathLenConstraint)
1079 if (depth - 1 > *bc.pathLenConstraint)
1080 ret = HX509_CA_PATH_TOO_DEEP;
1081 break;
1083 free_BasicConstraints(&bc);
1084 return ret;
1087 HX509_LIB_FUNCTION int HX509_LIB_CALL
1088 _hx509_cert_is_parent_cmp(const Certificate *subject,
1089 const Certificate *issuer,
1090 int allow_self_signed)
1092 int diff;
1093 AuthorityKeyIdentifier ai;
1094 SubjectKeyIdentifier si;
1095 int ret_ai, ret_si, ret;
1097 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
1098 &subject->tbsCertificate.issuer,
1099 &diff);
1100 if (ret)
1101 return ret;
1102 if (diff)
1103 return diff;
1105 memset(&ai, 0, sizeof(ai));
1106 memset(&si, 0, sizeof(si));
1109 * Try to find AuthorityKeyIdentifier, if it's not present in the
1110 * subject certificate nor the parent.
1113 ret_ai = find_extension_auth_key_id(subject, &ai);
1114 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
1115 return 1;
1116 ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
1117 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
1118 return -1;
1120 if (ret_si && ret_ai)
1121 goto out;
1122 if (ret_ai)
1123 goto out;
1124 if (ret_si) {
1125 if (allow_self_signed) {
1126 diff = 0;
1127 goto out;
1128 } else if (ai.keyIdentifier) {
1129 diff = -1;
1130 goto out;
1134 if (ai.keyIdentifier == NULL) {
1135 Name name;
1137 if (ai.authorityCertIssuer == NULL)
1138 return -1;
1139 if (ai.authorityCertSerialNumber == NULL)
1140 return -1;
1142 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
1143 &issuer->tbsCertificate.serialNumber);
1144 if (diff)
1145 return diff;
1146 if (ai.authorityCertIssuer->len != 1)
1147 return -1;
1148 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
1149 return -1;
1151 name.element = (enum Name_enum)
1152 ai.authorityCertIssuer->val[0].u.directoryName.element;
1153 name.u.rdnSequence =
1154 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
1156 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
1157 &name,
1158 &diff);
1159 if (ret)
1160 return ret;
1161 if (diff)
1162 return diff;
1163 diff = 0;
1164 } else
1165 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
1166 if (diff)
1167 goto out;
1169 out:
1170 free_AuthorityKeyIdentifier(&ai);
1171 free_SubjectKeyIdentifier(&si);
1172 return diff;
1175 static int
1176 certificate_is_anchor(hx509_context context,
1177 hx509_certs trust_anchors,
1178 const hx509_cert cert)
1180 hx509_query q;
1181 hx509_cert c;
1182 int ret;
1184 if (trust_anchors == NULL)
1185 return 0;
1187 _hx509_query_clear(&q);
1189 q.match = HX509_QUERY_MATCH_CERTIFICATE;
1190 q.certificate = _hx509_get_cert(cert);
1192 ret = hx509_certs_find(context, trust_anchors, &q, &c);
1193 if (ret == 0)
1194 hx509_cert_free(c);
1195 return ret == 0;
1198 static int
1199 certificate_is_self_signed(hx509_context context,
1200 const Certificate *cert,
1201 int *self_signed)
1203 int ret, diff;
1204 ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1205 &cert->tbsCertificate.issuer, &diff);
1206 *self_signed = (diff == 0);
1207 if (ret) {
1208 hx509_set_error_string(context, 0, ret,
1209 "Failed to check if self signed");
1210 } else if (diff == 0)
1211 ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm);
1213 return ret;
1216 HX509_LIB_FUNCTION int HX509_LIB_CALL
1217 hx509_cert_is_self_signed(hx509_context context,
1218 hx509_cert c,
1219 int *self_signed)
1221 return certificate_is_self_signed(context, c->data, self_signed);
1224 HX509_LIB_FUNCTION int HX509_LIB_CALL
1225 hx509_cert_is_ca(hx509_context context,
1226 hx509_cert c,
1227 int *is_ca)
1229 BasicConstraints bc;
1230 const Extension *e;
1231 size_t size;
1232 size_t i = 0;
1233 int ret = 0;
1235 *is_ca = 0;
1236 if (_hx509_cert_get_version(c->data) < 3)
1237 return certificate_is_self_signed(context, c->data, is_ca);
1239 e = find_extension(c->data, &asn1_oid_id_x509_ce_basicConstraints, &i);
1240 if (e == NULL) {
1241 *is_ca = 0;
1242 return 0;
1245 ret = decode_BasicConstraints(e->extnValue.data,
1246 e->extnValue.length, &bc,
1247 &size);
1248 if (ret)
1249 return ret;
1251 *is_ca = bc.cA;
1252 free_BasicConstraints(&bc);
1253 return 0;
1256 HX509_LIB_FUNCTION int HX509_LIB_CALL
1257 hx509_cert_is_root(hx509_context context,
1258 hx509_cert c,
1259 int *is_root)
1261 int ret;
1263 *is_root = 0;
1264 ret = hx509_cert_is_ca(context, c, is_root);
1265 if (ret)
1266 return ret;
1267 if (*is_root == 0)
1268 /* Not a CA certificate -> not a root certificate */
1269 return 0;
1271 /* A CA certificate. If it's self-signed, it's a root certificate. */
1272 return hx509_cert_is_self_signed(context, c, is_root);
1276 * The subjectName is "null" when it's empty set of relative DBs.
1279 static int
1280 subject_null_p(const Certificate *c)
1282 return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1286 static int
1287 find_parent(hx509_context context,
1288 time_t time_now,
1289 hx509_certs trust_anchors,
1290 hx509_path *path,
1291 hx509_certs pool,
1292 hx509_cert current,
1293 hx509_cert *parent)
1295 AuthorityKeyIdentifier ai;
1296 hx509_query q;
1297 int ret;
1299 *parent = NULL;
1300 memset(&ai, 0, sizeof(ai));
1302 _hx509_query_clear(&q);
1304 if (!subject_null_p(current->data)) {
1305 q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1306 q.subject = _hx509_get_cert(current);
1307 } else {
1308 ret = find_extension_auth_key_id(current->data, &ai);
1309 if (ret) {
1310 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1311 "Subjectless certificate missing AuthKeyID");
1312 return HX509_CERTIFICATE_MALFORMED;
1315 if (ai.keyIdentifier == NULL) {
1316 free_AuthorityKeyIdentifier(&ai);
1317 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1318 "Subjectless certificate missing keyIdentifier "
1319 "inside AuthKeyID");
1320 return HX509_CERTIFICATE_MALFORMED;
1323 q.subject_id = ai.keyIdentifier;
1324 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1327 q.path = path;
1328 q.match |= HX509_QUERY_NO_MATCH_PATH;
1330 if (pool) {
1331 q.timenow = time_now;
1332 q.match |= HX509_QUERY_MATCH_TIME;
1334 ret = hx509_certs_find(context, pool, &q, parent);
1335 if (ret == 0) {
1336 free_AuthorityKeyIdentifier(&ai);
1337 return 0;
1339 q.match &= ~HX509_QUERY_MATCH_TIME;
1342 if (trust_anchors) {
1343 ret = hx509_certs_find(context, trust_anchors, &q, parent);
1344 if (ret == 0) {
1345 free_AuthorityKeyIdentifier(&ai);
1346 return ret;
1349 free_AuthorityKeyIdentifier(&ai);
1352 hx509_name name;
1353 char *str;
1355 ret = hx509_cert_get_subject(current, &name);
1356 if (ret) {
1357 hx509_clear_error_string(context);
1358 return HX509_ISSUER_NOT_FOUND;
1360 ret = hx509_name_to_string(name, &str);
1361 hx509_name_free(&name);
1362 if (ret) {
1363 hx509_clear_error_string(context);
1364 return HX509_ISSUER_NOT_FOUND;
1367 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1368 "Failed to find issuer for "
1369 "certificate with subject: '%s'", str);
1370 free(str);
1372 return HX509_ISSUER_NOT_FOUND;
1379 static int
1380 is_proxy_cert(hx509_context context,
1381 const Certificate *cert,
1382 ProxyCertInfo *rinfo)
1384 ProxyCertInfo info;
1385 const Extension *e;
1386 size_t size;
1387 int ret;
1388 size_t i = 0;
1390 if (rinfo)
1391 memset(rinfo, 0, sizeof(*rinfo));
1393 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1394 if (e == NULL) {
1395 hx509_clear_error_string(context);
1396 return HX509_EXTENSION_NOT_FOUND;
1399 ret = decode_ProxyCertInfo(e->extnValue.data,
1400 e->extnValue.length,
1401 &info,
1402 &size);
1403 if (ret) {
1404 hx509_clear_error_string(context);
1405 return ret;
1407 if (size != e->extnValue.length) {
1408 free_ProxyCertInfo(&info);
1409 hx509_clear_error_string(context);
1410 return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1412 if (rinfo == NULL)
1413 free_ProxyCertInfo(&info);
1414 else
1415 *rinfo = info;
1417 return 0;
1421 * Path operations are like MEMORY based keyset, but with exposed
1422 * internal so we can do easy searches.
1425 HX509_LIB_FUNCTION int HX509_LIB_CALL
1426 _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1428 hx509_cert *val;
1429 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1430 if (val == NULL) {
1431 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1432 return ENOMEM;
1435 path->val = val;
1436 path->val[path->len] = hx509_cert_ref(cert);
1437 path->len++;
1439 return 0;
1442 HX509_LIB_FUNCTION void HX509_LIB_CALL
1443 _hx509_path_free(hx509_path *path)
1445 unsigned i;
1447 for (i = 0; i < path->len; i++)
1448 hx509_cert_free(path->val[i]);
1449 free(path->val);
1450 path->val = NULL;
1451 path->len = 0;
1455 * Find path by looking up issuer for the top certificate and continue
1456 * until an anchor certificate is found or max limit is found. A
1457 * certificate never included twice in the path.
1459 * If the trust anchors are not given, calculate optimistic path, just
1460 * follow the chain upward until we no longer find a parent or we hit
1461 * the max path limit. In this case, a failure will always be returned
1462 * depending on what error condition is hit first.
1464 * The path includes a path from the top certificate to the anchor
1465 * certificate.
1467 * The caller needs to free `path´ both on successful built path and
1468 * failure.
1471 HX509_LIB_FUNCTION int HX509_LIB_CALL
1472 _hx509_calculate_path(hx509_context context,
1473 int flags,
1474 time_t time_now,
1475 hx509_certs anchors,
1476 unsigned int max_depth,
1477 hx509_cert cert,
1478 hx509_certs pool,
1479 hx509_path *path)
1481 hx509_cert parent, current;
1482 int ret;
1484 if (max_depth == 0)
1485 max_depth = HX509_VERIFY_MAX_DEPTH;
1487 ret = _hx509_path_append(context, path, cert);
1488 if (ret)
1489 return ret;
1491 current = hx509_cert_ref(cert);
1493 while (!certificate_is_anchor(context, anchors, current)) {
1495 ret = find_parent(context, time_now, anchors, path,
1496 pool, current, &parent);
1497 hx509_cert_free(current);
1498 if (ret)
1499 return ret;
1501 ret = _hx509_path_append(context, path, parent);
1502 if (ret)
1503 return ret;
1504 current = parent;
1506 if (path->len > max_depth) {
1507 hx509_cert_free(current);
1508 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1509 "Path too long while building "
1510 "certificate chain");
1511 return HX509_PATH_TOO_LONG;
1515 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1516 path->len > 0 &&
1517 certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1519 hx509_cert_free(path->val[path->len - 1]);
1520 path->len--;
1523 hx509_cert_free(current);
1524 return 0;
1527 HX509_LIB_FUNCTION int HX509_LIB_CALL
1528 _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1529 const AlgorithmIdentifier *q)
1531 int diff;
1532 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1533 if (diff)
1534 return diff;
1535 if (p->parameters) {
1536 if (q->parameters)
1537 return heim_any_cmp(p->parameters,
1538 q->parameters);
1539 else
1540 return 1;
1541 } else {
1542 if (q->parameters)
1543 return -1;
1544 else
1545 return 0;
1549 HX509_LIB_FUNCTION int HX509_LIB_CALL
1550 _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1552 int diff;
1553 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1554 if (diff)
1555 return diff;
1556 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1557 &q->signatureAlgorithm);
1558 if (diff)
1559 return diff;
1560 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1561 &q->tbsCertificate._save);
1562 return diff;
1566 * Compare to hx509 certificate object, useful for sorting.
1568 * @param p a hx509 certificate object.
1569 * @param q a hx509 certificate object.
1571 * @return 0 the objects are the same, returns > 0 is p is "larger"
1572 * then q, < 0 if p is "smaller" then q.
1574 * @ingroup hx509_cert
1577 HX509_LIB_FUNCTION int HX509_LIB_CALL
1578 hx509_cert_cmp(hx509_cert p, hx509_cert q)
1580 return _hx509_Certificate_cmp(p->data, q->data);
1584 * Return the name of the issuer of the hx509 certificate.
1586 * @param p a hx509 certificate object.
1587 * @param name a pointer to a hx509 name, should be freed by
1588 * hx509_name_free().
1590 * @return An hx509 error code, see hx509_get_error_string().
1592 * @ingroup hx509_cert
1595 HX509_LIB_FUNCTION int HX509_LIB_CALL
1596 hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1598 return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1602 * Return the name of the subject of the hx509 certificate.
1604 * @param p a hx509 certificate object.
1605 * @param name a pointer to a hx509 name, should be freed by
1606 * hx509_name_free(). See also hx509_cert_get_base_subject().
1608 * @return An hx509 error code, see hx509_get_error_string().
1610 * @ingroup hx509_cert
1613 HX509_LIB_FUNCTION int HX509_LIB_CALL
1614 hx509_cert_get_subject(hx509_cert p, hx509_name *name)
1616 return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1620 * Return the name of the base subject of the hx509 certificate. If
1621 * the certiicate is a verified proxy certificate, the this function
1622 * return the base certificate (root of the proxy chain). If the proxy
1623 * certificate is not verified with the base certificate
1624 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1626 * @param context a hx509 context.
1627 * @param c a hx509 certificate object.
1628 * @param name a pointer to a hx509 name, should be freed by
1629 * hx509_name_free(). See also hx509_cert_get_subject().
1631 * @return An hx509 error code, see hx509_get_error_string().
1633 * @ingroup hx509_cert
1636 HX509_LIB_FUNCTION int HX509_LIB_CALL
1637 hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1638 hx509_name *name)
1640 if (c->basename)
1641 return hx509_name_copy(context, c->basename, name);
1642 if (is_proxy_cert(context, c->data, NULL) == 0) {
1643 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1644 hx509_set_error_string(context, 0, ret,
1645 "Proxy certificate has not been "
1646 "canonicalized yet: no base name");
1647 return ret;
1649 return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1653 * Get serial number of the certificate.
1655 * @param p a hx509 certificate object.
1656 * @param i serial number, should be freed ith der_free_heim_integer().
1658 * @return An hx509 error code, see hx509_get_error_string().
1660 * @ingroup hx509_cert
1663 HX509_LIB_FUNCTION int HX509_LIB_CALL
1664 hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1666 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1670 * Get notBefore time of the certificate.
1672 * @param p a hx509 certificate object.
1674 * @return return not before time
1676 * @ingroup hx509_cert
1679 HX509_LIB_FUNCTION time_t HX509_LIB_CALL
1680 hx509_cert_get_notBefore(hx509_cert p)
1682 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1686 * Get notAfter time of the certificate.
1688 * @param p a hx509 certificate object.
1690 * @return return not after time.
1692 * @ingroup hx509_cert
1695 HX509_LIB_FUNCTION time_t HX509_LIB_CALL
1696 hx509_cert_get_notAfter(hx509_cert p)
1698 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1702 * Get a maximum Kerberos credential lifetime from a Heimdal certificate
1703 * extension.
1705 * @param context hx509 context.
1706 * @param cert Certificate.
1707 * @param bound If larger than zero, return no more than this.
1709 * @return maximum ticket lifetime.
1711 HX509_LIB_FUNCTION time_t HX509_LIB_CALL
1712 hx509_cert_get_pkinit_max_life(hx509_context context,
1713 hx509_cert cert,
1714 time_t bound)
1716 HeimPkinitPrincMaxLifeSecs r = 0;
1717 size_t sz, i;
1718 time_t b, e;
1719 int ret;
1721 for (i = 0; i < cert->data->tbsCertificate.extensions->len; i++) {
1722 Extension *ext = &cert->data->tbsCertificate.extensions->val[i];
1724 if (ext->_ioschoice_extnValue.element !=
1725 choice_Extension_iosnumunknown &&
1726 ext->_ioschoice_extnValue.element !=
1727 choice_Extension_iosnum_id_heim_ce_pkinit_princ_max_life)
1728 continue;
1729 if (ext->_ioschoice_extnValue.element == choice_Extension_iosnumunknown &&
1730 der_heim_oid_cmp(&asn1_oid_id_heim_ce_pkinit_princ_max_life, &ext->extnID))
1731 continue;
1732 if (ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife) {
1733 r = *ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife;
1734 } else {
1735 ret = decode_HeimPkinitPrincMaxLifeSecs(ext->extnValue.data,
1736 ext->extnValue.length,
1737 &r, &sz);
1738 /* No need to free_HeimPkinitPrincMaxLifeSecs(); it's an int */
1739 if (ret || r < 1)
1740 return 0;
1742 if (bound > 0 && r > bound)
1743 return bound;
1744 return r;
1746 if (hx509_cert_check_eku(context, cert,
1747 &asn1_oid_id_heim_eku_pkinit_certlife_is_max_life, 0))
1748 return 0;
1749 b = hx509_cert_get_notBefore(cert);
1750 e = hx509_cert_get_notAfter(cert);
1751 if (e > b)
1752 r = e - b;
1753 if (bound > 0 && r > bound)
1754 return bound;
1755 return r;
1759 * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1761 * @param context a hx509 context.
1762 * @param p a hx509 certificate object.
1763 * @param spki SubjectPublicKeyInfo, should be freed with
1764 * free_SubjectPublicKeyInfo().
1766 * @return An hx509 error code, see hx509_get_error_string().
1768 * @ingroup hx509_cert
1771 HX509_LIB_FUNCTION int HX509_LIB_CALL
1772 hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1774 int ret;
1776 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1777 if (ret)
1778 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1779 return ret;
1783 * Get the AlgorithmIdentifier from the hx509 certificate.
1785 * @param context a hx509 context.
1786 * @param p a hx509 certificate object.
1787 * @param alg AlgorithmIdentifier, should be freed with
1788 * free_AlgorithmIdentifier(). The algorithmidentifier is
1789 * typicly rsaEncryption, or id-ecPublicKey, or some other
1790 * public key mechanism.
1792 * @return An hx509 error code, see hx509_get_error_string().
1794 * @ingroup hx509_cert
1797 HX509_LIB_FUNCTION int HX509_LIB_CALL
1798 hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1799 hx509_cert p,
1800 AlgorithmIdentifier *alg)
1802 int ret;
1804 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1805 if (ret)
1806 hx509_set_error_string(context, 0, ret,
1807 "Failed to copy SPKI AlgorithmIdentifier");
1808 return ret;
1811 static int
1812 get_x_unique_id(hx509_context context, const char *name,
1813 const heim_bit_string *cert, heim_bit_string *subject)
1815 int ret;
1817 if (cert == NULL) {
1818 ret = HX509_EXTENSION_NOT_FOUND;
1819 hx509_set_error_string(context, 0, ret, "%s unique id doesn't exist", name);
1820 return ret;
1822 ret = der_copy_bit_string(cert, subject);
1823 if (ret) {
1824 hx509_set_error_string(context, 0, ret, "malloc out of memory", name);
1825 return ret;
1827 return 0;
1831 * Get a copy of the Issuer Unique ID
1833 * @param context a hx509_context
1834 * @param p a hx509 certificate
1835 * @param issuer the issuer id returned, free with der_free_bit_string()
1837 * @return An hx509 error code, see hx509_get_error_string(). The
1838 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1839 * doesn't have a issuerUniqueID
1841 * @ingroup hx509_cert
1844 HX509_LIB_FUNCTION int HX509_LIB_CALL
1845 hx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer)
1847 return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer);
1851 * Get a copy of the Subect Unique ID
1853 * @param context a hx509_context
1854 * @param p a hx509 certificate
1855 * @param subject the subject id returned, free with der_free_bit_string()
1857 * @return An hx509 error code, see hx509_get_error_string(). The
1858 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1859 * doesn't have a subjectUniqueID
1861 * @ingroup hx509_cert
1864 HX509_LIB_FUNCTION int HX509_LIB_CALL
1865 hx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject)
1867 return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject);
1871 HX509_LIB_FUNCTION hx509_private_key HX509_LIB_CALL
1872 _hx509_cert_private_key(hx509_cert p)
1874 return p->private_key;
1878 * Indicate whether a hx509_cert has a private key.
1880 * @param p a hx509 certificate
1882 * @return 1 if p has a private key, 0 otherwise.
1884 * @ingroup hx509_cert
1886 HX509_LIB_FUNCTION int HX509_LIB_CALL
1887 hx509_cert_have_private_key(hx509_cert p)
1889 return p->private_key ? 1 : 0;
1893 * Indicate whether a hx509_cert has a private key only (no certificate).
1895 * @param p a hx509 certificate
1897 * @return 1 if p has a private key only (no certificate), 0 otherwise.
1899 * @ingroup hx509_cert
1901 HX509_LIB_FUNCTION int HX509_LIB_CALL
1902 hx509_cert_have_private_key_only(hx509_cert p)
1904 return p->private_key && !p->data ? 1 : 0;
1908 HX509_LIB_FUNCTION int HX509_LIB_CALL
1909 _hx509_cert_private_key_exportable(hx509_cert p)
1911 if (p->private_key == NULL)
1912 return 0;
1913 return _hx509_private_key_exportable(p->private_key);
1916 HX509_LIB_FUNCTION int HX509_LIB_CALL
1917 _hx509_cert_private_decrypt(hx509_context context,
1918 const heim_octet_string *ciphertext,
1919 const heim_oid *encryption_oid,
1920 hx509_cert p,
1921 heim_octet_string *cleartext)
1923 cleartext->data = NULL;
1924 cleartext->length = 0;
1926 if (p->private_key == NULL) {
1927 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1928 "Private key missing");
1929 return HX509_PRIVATE_KEY_MISSING;
1932 return hx509_private_key_private_decrypt(context,
1933 ciphertext,
1934 encryption_oid,
1935 p->private_key,
1936 cleartext);
1939 HX509_LIB_FUNCTION int HX509_LIB_CALL
1940 hx509_cert_public_encrypt(hx509_context context,
1941 const heim_octet_string *cleartext,
1942 const hx509_cert p,
1943 heim_oid *encryption_oid,
1944 heim_octet_string *ciphertext)
1946 return _hx509_public_encrypt(context,
1947 cleartext, p->data,
1948 encryption_oid, ciphertext);
1955 HX509_LIB_FUNCTION time_t HX509_LIB_CALL
1956 _hx509_Time2time_t(const Time *t)
1958 switch(t->element) {
1959 case choice_Time_utcTime:
1960 return t->u.utcTime;
1961 case choice_Time_generalTime:
1962 return t->u.generalTime;
1964 return 0;
1971 static int
1972 init_name_constraints(hx509_name_constraints *nc)
1974 memset(nc, 0, sizeof(*nc));
1975 return 0;
1978 static int
1979 add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1980 hx509_name_constraints *nc)
1982 NameConstraints tnc;
1983 int ret;
1985 ret = find_extension_name_constraints(c, &tnc);
1986 if (ret == HX509_EXTENSION_NOT_FOUND)
1987 return 0;
1988 else if (ret) {
1989 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1990 return ret;
1991 } else if (not_ca) {
1992 ret = HX509_VERIFY_CONSTRAINTS;
1993 hx509_set_error_string(context, 0, ret, "Not a CA and "
1994 "have NameConstraints");
1995 } else {
1996 NameConstraints *val;
1997 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1998 if (val == NULL) {
1999 hx509_clear_error_string(context);
2000 ret = ENOMEM;
2001 goto out;
2003 nc->val = val;
2004 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
2005 if (ret) {
2006 hx509_clear_error_string(context);
2007 goto out;
2009 nc->len += 1;
2011 out:
2012 free_NameConstraints(&tnc);
2013 return ret;
2016 static int
2017 match_RDN(const RelativeDistinguishedName *c,
2018 const RelativeDistinguishedName *n)
2020 size_t i;
2022 if (c->len != n->len)
2023 return HX509_NAME_CONSTRAINT_ERROR;
2025 for (i = 0; i < n->len; i++) {
2026 int diff, ret;
2028 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
2029 return HX509_NAME_CONSTRAINT_ERROR;
2030 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
2031 if (ret)
2032 return ret;
2033 if (diff != 0)
2034 return HX509_NAME_CONSTRAINT_ERROR;
2036 return 0;
2039 static int
2040 match_X501Name(const Name *c, const Name *n)
2042 size_t i;
2043 int ret;
2045 if (c->element != choice_Name_rdnSequence
2046 || n->element != choice_Name_rdnSequence)
2047 return 0;
2048 if (c->u.rdnSequence.len > n->u.rdnSequence.len)
2049 return HX509_NAME_CONSTRAINT_ERROR;
2050 for (i = 0; i < c->u.rdnSequence.len; i++) {
2051 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
2052 if (ret)
2053 return ret;
2055 return 0;
2059 static int
2060 match_general_name(const GeneralName *c, const GeneralName *n, int *match)
2063 * Name constraints only apply to the same name type, see RFC3280,
2064 * 4.2.1.11.
2066 assert(c->element == n->element);
2068 switch(c->element) {
2069 case choice_GeneralName_otherName:
2070 if (der_heim_oid_cmp(&c->u.otherName.type_id,
2071 &n->u.otherName.type_id) != 0)
2072 return HX509_NAME_CONSTRAINT_ERROR;
2073 if (heim_any_cmp(&c->u.otherName.value,
2074 &n->u.otherName.value) != 0)
2075 return HX509_NAME_CONSTRAINT_ERROR;
2076 *match = 1;
2077 return 0;
2078 case choice_GeneralName_rfc822Name: {
2079 const char *s;
2080 size_t len1, len2;
2081 s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length);
2082 if (s) {
2083 if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0)
2084 return HX509_NAME_CONSTRAINT_ERROR;
2085 } else {
2086 s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length);
2087 if (s == NULL)
2088 return HX509_NAME_CONSTRAINT_ERROR;
2089 len1 = c->u.rfc822Name.length;
2090 len2 = n->u.rfc822Name.length -
2091 (s - ((char *)n->u.rfc822Name.data));
2092 if (len1 > len2)
2093 return HX509_NAME_CONSTRAINT_ERROR;
2094 if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0)
2095 return HX509_NAME_CONSTRAINT_ERROR;
2096 if (len1 < len2 && s[len2 - len1 + 1] != '.')
2097 return HX509_NAME_CONSTRAINT_ERROR;
2099 *match = 1;
2100 return 0;
2102 case choice_GeneralName_dNSName: {
2103 size_t lenc, lenn;
2104 char *ptr;
2106 lenc = c->u.dNSName.length;
2107 lenn = n->u.dNSName.length;
2108 if (lenc > lenn)
2109 return HX509_NAME_CONSTRAINT_ERROR;
2110 ptr = n->u.dNSName.data;
2111 if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0)
2112 return HX509_NAME_CONSTRAINT_ERROR;
2113 if (lenn != lenc && ptr[lenn - lenc - 1] != '.')
2114 return HX509_NAME_CONSTRAINT_ERROR;
2115 *match = 1;
2116 return 0;
2118 case choice_GeneralName_directoryName: {
2119 Name c_name, n_name;
2120 int ret;
2122 c_name._save.data = NULL;
2123 c_name._save.length = 0;
2124 c_name.element = (enum Name_enum)c->u.directoryName.element;
2125 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
2127 n_name._save.data = NULL;
2128 n_name._save.length = 0;
2129 n_name.element = (enum Name_enum)n->u.directoryName.element;
2130 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
2132 ret = match_X501Name(&c_name, &n_name);
2133 if (ret == 0)
2134 *match = 1;
2135 return ret;
2137 case choice_GeneralName_uniformResourceIdentifier:
2138 case choice_GeneralName_iPAddress:
2139 case choice_GeneralName_registeredID:
2140 default:
2141 return HX509_NAME_CONSTRAINT_ERROR;
2145 static int
2146 match_alt_name(const GeneralName *n, const Certificate *c,
2147 int *same, int *match)
2149 GeneralNames sa;
2150 int ret = 0;
2151 size_t i, j;
2153 i = 0;
2154 do {
2155 ret = find_extension_subject_alt_name(c, &i, &sa);
2156 if (ret == HX509_EXTENSION_NOT_FOUND) {
2157 ret = 0;
2158 break;
2159 } else if (ret != 0)
2160 break;
2162 for (j = 0; j < sa.len; j++) {
2163 if (n->element == sa.val[j].element) {
2164 *same = 1;
2165 match_general_name(n, &sa.val[j], match);
2168 free_GeneralNames(&sa);
2169 } while (1);
2170 return ret;
2174 static int
2175 match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
2177 int name, alt_name, same;
2178 unsigned int i;
2179 int ret = 0;
2181 name = alt_name = same = *match = 0;
2182 for (i = 0; i < t->len; i++) {
2183 if (t->val[i].minimum && t->val[i].maximum)
2184 return HX509_RANGE;
2187 * If the constraint apply to directoryNames, test is with
2188 * subjectName of the certificate if the certificate have a
2189 * non-null (empty) subjectName.
2192 if (t->val[i].base.element == choice_GeneralName_directoryName
2193 && !subject_null_p(c))
2195 GeneralName certname;
2197 memset(&certname, 0, sizeof(certname));
2198 certname.element = choice_GeneralName_directoryName;
2199 certname.u.directoryName.element = (enum Name_enum)
2200 c->tbsCertificate.subject.element;
2201 certname.u.directoryName.u.rdnSequence =
2202 c->tbsCertificate.subject.u.rdnSequence;
2204 match_general_name(&t->val[i].base, &certname, &name);
2207 /* Handle subjectAltNames, this is icky since they
2208 * restrictions only apply if the subjectAltName is of the
2209 * same type. So if there have been a match of type, require
2210 * altname to be set.
2212 match_alt_name(&t->val[i].base, c, &same, &alt_name);
2214 if (name && (!same || alt_name))
2215 *match = 1;
2216 return ret;
2219 static int
2220 check_name_constraints(hx509_context context,
2221 const hx509_name_constraints *nc,
2222 const Certificate *c)
2224 int match, ret;
2225 size_t i;
2227 for (i = 0 ; i < nc->len; i++) {
2228 GeneralSubtrees gs;
2230 if (nc->val[i].permittedSubtrees) {
2231 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
2232 ret = match_tree(&gs, c, &match);
2233 if (ret) {
2234 hx509_clear_error_string(context);
2235 return ret;
2237 /* allow null subjectNames, they wont matches anything */
2238 if (match == 0 && !subject_null_p(c)) {
2239 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
2240 "Error verifying constraints: "
2241 "certificate didn't match any "
2242 "permitted subtree");
2243 return HX509_VERIFY_CONSTRAINTS;
2246 if (nc->val[i].excludedSubtrees) {
2247 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
2248 ret = match_tree(&gs, c, &match);
2249 if (ret) {
2250 hx509_clear_error_string(context);
2251 return ret;
2253 if (match) {
2254 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
2255 "Error verifying constraints: "
2256 "certificate included in excluded "
2257 "subtree");
2258 return HX509_VERIFY_CONSTRAINTS;
2262 return 0;
2265 static void
2266 free_name_constraints(hx509_name_constraints *nc)
2268 size_t i;
2270 for (i = 0 ; i < nc->len; i++)
2271 free_NameConstraints(&nc->val[i]);
2272 free(nc->val);
2276 * Build and verify the path for the certificate to the trust anchor
2277 * specified in the verify context. The path is constructed from the
2278 * certificate, the pool and the trust anchors.
2280 * @param context A hx509 context.
2281 * @param ctx A hx509 verification context.
2282 * @param cert the certificate to build the path from.
2283 * @param pool A keyset of certificates to build the chain from.
2285 * @return An hx509 error code, see hx509_get_error_string().
2287 * @ingroup hx509_verify
2290 HX509_LIB_FUNCTION int HX509_LIB_CALL
2291 hx509_verify_path(hx509_context context,
2292 hx509_verify_ctx ctx,
2293 hx509_cert cert,
2294 hx509_certs pool)
2296 hx509_name_constraints nc;
2297 hx509_path path;
2298 int ret, proxy_cert_depth, selfsigned_depth, diff;
2299 size_t i, k;
2300 enum certtype type;
2301 Name proxy_issuer;
2302 hx509_certs anchors = NULL;
2304 memset(&proxy_issuer, 0, sizeof(proxy_issuer));
2306 if ((ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) == 0 &&
2307 is_proxy_cert(context, cert->data, NULL) == 0)
2309 ret = HX509_PROXY_CERT_INVALID;
2310 hx509_set_error_string(context, 0, ret,
2311 "Proxy certificate is not allowed as an EE "
2312 "certificate if proxy certificate is disabled");
2313 return ret;
2316 ret = init_name_constraints(&nc);
2317 if (ret)
2318 return ret;
2320 path.val = NULL;
2321 path.len = 0;
2323 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
2324 ctx->time_now = time(NULL);
2329 if (ctx->trust_anchors)
2330 anchors = hx509_certs_ref(ctx->trust_anchors);
2331 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
2332 anchors = hx509_certs_ref(context->default_trust_anchors);
2333 else {
2334 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
2335 if (ret)
2336 goto out;
2340 * Calculate the path from the certificate user presented to the
2341 * to an anchor.
2343 ret = _hx509_calculate_path(context, 0, ctx->time_now,
2344 anchors, ctx->max_depth,
2345 cert, pool, &path);
2346 if (ret)
2347 goto out;
2350 * Check CA and proxy certificate chain from the top of the
2351 * certificate chain. Also check certificate is valid with respect
2352 * to the current time.
2356 proxy_cert_depth = 0;
2357 selfsigned_depth = 0;
2359 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
2360 type = PROXY_CERT;
2361 else
2362 type = EE_CERT;
2364 for (i = 0; i < path.len; i++) {
2365 Certificate *c;
2366 time_t t;
2368 c = _hx509_get_cert(path.val[i]);
2371 * Lets do some basic check on issuer like
2372 * keyUsage.keyCertSign and basicConstraints.cA bit depending
2373 * on what type of certificate this is.
2376 switch (type) {
2377 case CA_CERT:
2379 /* XXX make constants for keyusage */
2380 ret = check_key_usage(context, c, 1 << 5,
2381 REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
2382 if (ret) {
2383 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2384 "Key usage missing from CA certificate");
2385 goto out;
2388 /* self signed cert doesn't add to path length */
2389 if (i + 1 != path.len) {
2390 int selfsigned;
2392 ret = certificate_is_self_signed(context, c, &selfsigned);
2393 if (ret)
2394 goto out;
2395 if (selfsigned)
2396 selfsigned_depth++;
2399 break;
2400 case PROXY_CERT: {
2401 ProxyCertInfo info;
2403 if (is_proxy_cert(context, c, &info) == 0) {
2404 size_t j;
2406 if (info.pCPathLenConstraint != NULL &&
2407 *info.pCPathLenConstraint < i)
2409 free_ProxyCertInfo(&info);
2410 ret = HX509_PATH_TOO_LONG;
2411 hx509_set_error_string(context, 0, ret,
2412 "Proxy certificate chain "
2413 "longer than allowed");
2414 goto out;
2416 /* XXX MUST check info.proxyPolicy */
2417 free_ProxyCertInfo(&info);
2419 j = 0;
2420 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2421 ret = HX509_PROXY_CERT_INVALID;
2422 hx509_set_error_string(context, 0, ret,
2423 "Proxy certificate has explicitly "
2424 "forbidden subjectAltName");
2425 goto out;
2428 j = 0;
2429 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2430 ret = HX509_PROXY_CERT_INVALID;
2431 hx509_set_error_string(context, 0, ret,
2432 "Proxy certificate has explicitly "
2433 "forbidden issuerAltName");
2434 goto out;
2438 * The subject name of the proxy certificate should be
2439 * CN=XXX,<proxy issuer>. Prune off CN and check if it's
2440 * the same over the whole chain of proxy certs and
2441 * then check with the EE cert when we get to it.
2444 if (proxy_cert_depth) {
2445 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2446 if (ret) {
2447 hx509_set_error_string(context, 0, ret, "Out of memory");
2448 goto out;
2450 if (diff) {
2451 ret = HX509_PROXY_CERT_NAME_WRONG;
2452 hx509_set_error_string(context, 0, ret,
2453 "Base proxy name not right");
2454 goto out;
2458 free_Name(&proxy_issuer);
2460 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2461 if (ret) {
2462 hx509_clear_error_string(context);
2463 goto out;
2466 j = proxy_issuer.u.rdnSequence.len;
2467 if (proxy_issuer.u.rdnSequence.len < 2
2468 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2469 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2470 &asn1_oid_id_at_commonName))
2472 ret = HX509_PROXY_CERT_NAME_WRONG;
2473 hx509_set_error_string(context, 0, ret,
2474 "Proxy name too short or "
2475 "does not have Common name "
2476 "at the top");
2477 goto out;
2480 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2481 proxy_issuer.u.rdnSequence.len -= 1;
2483 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2484 if (ret) {
2485 hx509_set_error_string(context, 0, ret, "Out of memory");
2486 goto out;
2488 if (diff != 0) {
2489 ret = HX509_PROXY_CERT_NAME_WRONG;
2490 hx509_set_error_string(context, 0, ret,
2491 "Proxy issuer name not as expected");
2492 goto out;
2495 break;
2496 } else {
2498 * Now we are done with the proxy certificates, this
2499 * cert was an EE cert and we will fall though to
2500 * EE checking below.
2502 type = EE_CERT;
2505 HEIM_FALLTHROUGH;
2506 case EE_CERT:
2508 * If there were any proxy certificates in the chain
2509 * (proxy_cert_depth > 0), check that the proxy issuer
2510 * matched the proxy certificate's "base" subject.
2512 if (proxy_cert_depth) {
2514 ret = _hx509_name_cmp(&proxy_issuer,
2515 &c->tbsCertificate.subject, &diff);
2516 if (ret) {
2517 hx509_set_error_string(context, 0, ret, "out of memory");
2518 goto out;
2520 if (diff) {
2521 ret = HX509_PROXY_CERT_NAME_WRONG;
2522 hx509_clear_error_string(context);
2523 goto out;
2525 if (cert->basename)
2526 hx509_name_free(&cert->basename);
2528 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2529 if (ret) {
2530 hx509_clear_error_string(context);
2531 goto out;
2535 break;
2538 ret = check_basic_constraints(context, c, type,
2539 i - proxy_cert_depth - selfsigned_depth);
2540 if (ret)
2541 goto out;
2544 * Don't check the trust anchors expiration time since they
2545 * are transported out of band, from RFC3820.
2547 if (i + 1 != path.len || CHECK_TA(ctx)) {
2549 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2550 if (t > ctx->time_now) {
2551 ret = HX509_CERT_USED_BEFORE_TIME;
2552 hx509_clear_error_string(context);
2553 goto out;
2555 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2556 if (t < ctx->time_now) {
2557 ret = HX509_CERT_USED_AFTER_TIME;
2558 hx509_clear_error_string(context);
2559 goto out;
2563 if (type == EE_CERT)
2564 type = CA_CERT;
2565 else if (type == PROXY_CERT)
2566 proxy_cert_depth++;
2570 * Verify constraints, do this backward so path constraints are
2571 * checked in the right order.
2574 for (ret = 0, k = path.len; k > 0; k--) {
2575 Certificate *c;
2576 int selfsigned;
2577 i = k - 1;
2579 c = _hx509_get_cert(path.val[i]);
2581 ret = certificate_is_self_signed(context, c, &selfsigned);
2582 if (ret)
2583 goto out;
2585 /* verify name constraints, not for selfsigned and anchor */
2586 if (!selfsigned || i + 1 != path.len) {
2587 ret = check_name_constraints(context, &nc, c);
2588 if (ret) {
2589 goto out;
2592 ret = add_name_constraints(context, c, i == 0, &nc);
2593 if (ret)
2594 goto out;
2596 /* XXX verify all other silly constraints */
2601 * Verify that no certificates have been revoked.
2604 if (ctx->revoke_ctx) {
2605 hx509_certs certs;
2607 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2608 NULL, &certs);
2609 if (ret)
2610 goto out;
2612 for (i = 0; i < path.len; i++) {
2613 ret = hx509_certs_add(context, certs, path.val[i]);
2614 if (ret) {
2615 hx509_certs_free(&certs);
2616 goto out;
2619 ret = hx509_certs_merge(context, certs, pool);
2620 if (ret) {
2621 hx509_certs_free(&certs);
2622 goto out;
2625 for (i = 0; i < path.len - 1; i++) {
2626 size_t parent = (i < path.len - 1) ? i + 1 : i;
2628 ret = hx509_revoke_verify(context,
2629 ctx->revoke_ctx,
2630 certs,
2631 ctx->time_now,
2632 path.val[i],
2633 path.val[parent]);
2634 if (ret) {
2635 hx509_certs_free(&certs);
2636 goto out;
2639 hx509_certs_free(&certs);
2643 * Verify signatures, do this backward so public key working
2644 * parameter is passed up from the anchor up though the chain.
2647 for (k = path.len; k > 0; k--) {
2648 hx509_cert signer;
2649 Certificate *c;
2650 i = k - 1;
2652 c = _hx509_get_cert(path.val[i]);
2654 /* is last in chain (trust anchor) */
2655 if (i + 1 == path.len) {
2656 int selfsigned;
2658 signer = path.val[i];
2660 ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2661 if (ret)
2662 goto out;
2664 /* if trust anchor is not self signed, don't check sig */
2665 if (!selfsigned)
2666 continue;
2667 } else {
2668 /* take next certificate in chain */
2669 signer = path.val[i + 1];
2672 /* verify signatureValue */
2673 ret = _hx509_verify_signature_bitstring(context,
2674 signer,
2675 &c->signatureAlgorithm,
2676 &c->tbsCertificate._save,
2677 &c->signatureValue);
2678 if (ret) {
2679 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2680 "Failed to verify signature of certificate");
2681 goto out;
2684 * Verify that the signature algorithm is not weak. Ignore
2685 * trust anchors since they are provisioned by the user.
2688 if (i + 1 != path.len && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2689 ret = _hx509_signature_is_weak(context, &c->signatureAlgorithm);
2690 if (ret)
2691 goto out;
2695 out:
2696 hx509_certs_free(&anchors);
2697 free_Name(&proxy_issuer);
2698 free_name_constraints(&nc);
2699 _hx509_path_free(&path);
2701 return ret;
2705 * Verify a signature made using the private key of an certificate.
2707 * @param context A hx509 context.
2708 * @param signer the certificate that made the signature.
2709 * @param alg algorthm that was used to sign the data.
2710 * @param data the data that was signed.
2711 * @param sig the signature to verify.
2713 * @return An hx509 error code, see hx509_get_error_string().
2715 * @ingroup hx509_crypto
2718 HX509_LIB_FUNCTION int HX509_LIB_CALL
2719 hx509_verify_signature(hx509_context context,
2720 const hx509_cert signer,
2721 const AlgorithmIdentifier *alg,
2722 const heim_octet_string *data,
2723 const heim_octet_string *sig)
2725 return _hx509_verify_signature(context, signer, alg, data, sig);
2728 HX509_LIB_FUNCTION int HX509_LIB_CALL
2729 _hx509_verify_signature_bitstring(hx509_context context,
2730 const hx509_cert signer,
2731 const AlgorithmIdentifier *alg,
2732 const heim_octet_string *data,
2733 const heim_bit_string *sig)
2735 heim_octet_string os;
2737 if (sig->length & 7) {
2738 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2739 "signature not multiple of 8 bits");
2740 return HX509_CRYPTO_SIG_INVALID_FORMAT;
2743 os.data = sig->data;
2744 os.length = sig->length / 8;
2746 return _hx509_verify_signature(context, signer, alg, data, &os);
2752 * Verify that the certificate is allowed to be used for the hostname
2753 * and address.
2755 * @param context A hx509 context.
2756 * @param cert the certificate to match with
2757 * @param flags Flags to modify the behavior:
2758 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2759 * @param type type of hostname:
2760 * - HX509_HN_HOSTNAME for plain hostname.
2761 * - HX509_HN_DNSSRV for DNS SRV names.
2762 * @param hostname the hostname to check
2763 * @param sa address of the host
2764 * @param sa_size length of address
2766 * @return An hx509 error code, see hx509_get_error_string().
2768 * @ingroup hx509_cert
2771 HX509_LIB_FUNCTION int HX509_LIB_CALL
2772 hx509_verify_hostname(hx509_context context,
2773 const hx509_cert cert,
2774 int flags,
2775 hx509_hostname_type type,
2776 const char *hostname,
2777 const struct sockaddr *sa,
2778 /* XXX krb5_socklen_t */ int sa_size)
2780 GeneralNames san;
2781 const Name *name;
2782 int ret;
2783 size_t i, j, k;
2785 if (sa && sa_size <= 0)
2786 return EINVAL;
2788 memset(&san, 0, sizeof(san));
2790 i = 0;
2791 do {
2792 ret = find_extension_subject_alt_name(cert->data, &i, &san);
2793 if (ret == HX509_EXTENSION_NOT_FOUND)
2794 break;
2795 else if (ret != 0)
2796 return HX509_PARSING_NAME_FAILED;
2798 for (j = 0; j < san.len; j++) {
2799 switch (san.val[j].element) {
2800 case choice_GeneralName_dNSName: {
2801 heim_printable_string hn;
2802 hn.data = rk_UNCONST(hostname);
2803 hn.length = strlen(hostname);
2805 if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) {
2806 free_GeneralNames(&san);
2807 return 0;
2809 break;
2811 default:
2812 break;
2815 free_GeneralNames(&san);
2816 } while (1);
2818 name = &cert->data->tbsCertificate.subject;
2820 /* Find first CN= in the name, and try to match the hostname on that */
2821 for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) {
2822 i = k - 1;
2823 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2824 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2826 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2827 DirectoryString *ds = &n->value;
2828 switch (ds->element) {
2829 case choice_DirectoryString_printableString: {
2830 heim_printable_string hn;
2831 hn.data = rk_UNCONST(hostname);
2832 hn.length = strlen(hostname);
2834 if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0)
2835 return 0;
2836 break;
2838 case choice_DirectoryString_ia5String: {
2839 heim_ia5_string hn;
2840 hn.data = rk_UNCONST(hostname);
2841 hn.length = strlen(hostname);
2843 if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0)
2844 return 0;
2845 break;
2847 case choice_DirectoryString_utf8String:
2848 if (strcasecmp(ds->u.utf8String, hostname) == 0)
2849 return 0;
2850 default:
2851 break;
2853 ret = HX509_NAME_CONSTRAINT_ERROR;
2858 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2859 ret = HX509_NAME_CONSTRAINT_ERROR;
2861 return ret;
2864 HX509_LIB_FUNCTION int HX509_LIB_CALL
2865 _hx509_set_cert_attribute(hx509_context context,
2866 hx509_cert cert,
2867 const heim_oid *oid,
2868 const heim_octet_string *attr)
2870 hx509_cert_attribute a;
2871 void *d;
2872 int ret;
2875 * TODO: Rewrite this (and hx509_cert_attribute, and _hx509_cert_attrs) to
2876 * use the add_AttributeValues() util generated by asn1_compile.
2879 if (hx509_cert_get_attribute(cert, oid) != NULL)
2880 return 0;
2882 d = realloc(cert->attrs.val,
2883 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2884 if (d == NULL) {
2885 hx509_clear_error_string(context);
2886 return ENOMEM;
2888 cert->attrs.val = d;
2890 a = malloc(sizeof(*a));
2891 if (a == NULL)
2892 return ENOMEM;
2894 ret = der_copy_octet_string(attr, &a->data);
2895 if (ret == 0)
2896 ret = der_copy_oid(oid, &a->oid);
2897 if (ret == 0) {
2898 cert->attrs.val[cert->attrs.len] = a;
2899 cert->attrs.len++;
2900 } else {
2901 der_free_octet_string(&a->data);
2902 free(a);
2905 return ret;
2909 * Get an external attribute for the certificate, examples are
2910 * friendly name and id.
2912 * @param cert hx509 certificate object to search
2913 * @param oid an oid to search for.
2915 * @return an hx509_cert_attribute, only valid as long as the
2916 * certificate is referenced.
2918 * @ingroup hx509_cert
2921 HX509_LIB_FUNCTION hx509_cert_attribute HX509_LIB_CALL
2922 hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2924 size_t i;
2925 for (i = 0; i < cert->attrs.len; i++)
2926 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2927 return cert->attrs.val[i];
2928 return NULL;
2932 * Set the friendly name on the certificate.
2934 * @param cert The certificate to set the friendly name on
2935 * @param name Friendly name.
2937 * @return An hx509 error code, see hx509_get_error_string().
2939 * @ingroup hx509_cert
2942 HX509_LIB_FUNCTION int HX509_LIB_CALL
2943 hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2945 if (cert->friendlyname)
2946 free(cert->friendlyname);
2947 cert->friendlyname = strdup(name);
2948 if (cert->friendlyname == NULL)
2949 return ENOMEM;
2950 return 0;
2954 * Get friendly name of the certificate.
2956 * @param cert cert to get the friendly name from.
2958 * @return an friendly name or NULL if there is. The friendly name is
2959 * only valid as long as the certificate is referenced.
2961 * @ingroup hx509_cert
2964 HX509_LIB_FUNCTION const char * HX509_LIB_CALL
2965 hx509_cert_get_friendly_name(hx509_cert cert)
2967 hx509_cert_attribute a;
2968 PKCS9_friendlyName n;
2969 size_t sz;
2970 int ret;
2971 size_t i;
2973 if (cert->friendlyname)
2974 return cert->friendlyname;
2976 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2977 if (a == NULL) {
2978 hx509_name name;
2980 ret = hx509_cert_get_subject(cert, &name);
2981 if (ret)
2982 return NULL;
2983 ret = hx509_name_to_string(name, &cert->friendlyname);
2984 hx509_name_free(&name);
2985 if (ret)
2986 return NULL;
2987 return cert->friendlyname;
2990 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2991 if (ret)
2992 return NULL;
2994 if (n.len != 1) {
2995 free_PKCS9_friendlyName(&n);
2996 return NULL;
2999 cert->friendlyname = malloc(n.val[0].length + 1);
3000 if (cert->friendlyname == NULL) {
3001 free_PKCS9_friendlyName(&n);
3002 return NULL;
3005 for (i = 0; i < n.val[0].length; i++) {
3006 if (n.val[0].data[i] <= 0xff)
3007 cert->friendlyname[i] = n.val[0].data[i] & 0xff;
3008 else
3009 cert->friendlyname[i] = 'X';
3011 cert->friendlyname[i] = '\0';
3012 free_PKCS9_friendlyName(&n);
3014 return cert->friendlyname;
3017 HX509_LIB_FUNCTION void HX509_LIB_CALL
3018 _hx509_query_clear(hx509_query *q)
3020 memset(q, 0, sizeof(*q));
3024 * Allocate an query controller. Free using hx509_query_free().
3026 * @param context A hx509 context.
3027 * @param q return pointer to a hx509_query.
3029 * @return An hx509 error code, see hx509_get_error_string().
3031 * @ingroup hx509_cert
3034 HX509_LIB_FUNCTION int HX509_LIB_CALL
3035 hx509_query_alloc(hx509_context context, hx509_query **q)
3037 *q = calloc(1, sizeof(**q));
3038 if (*q == NULL)
3039 return ENOMEM;
3040 return 0;
3045 * Set match options for the hx509 query controller.
3047 * @param q query controller.
3048 * @param option options to control the query controller.
3050 * @return An hx509 error code, see hx509_get_error_string().
3052 * @ingroup hx509_cert
3055 HX509_LIB_FUNCTION void HX509_LIB_CALL
3056 hx509_query_match_option(hx509_query *q, hx509_query_option option)
3058 switch(option) {
3059 case HX509_QUERY_OPTION_PRIVATE_KEY:
3060 q->match |= HX509_QUERY_PRIVATE_KEY;
3061 break;
3062 case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
3063 q->match |= HX509_QUERY_KU_ENCIPHERMENT;
3064 break;
3065 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
3066 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
3067 break;
3068 case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
3069 q->match |= HX509_QUERY_KU_KEYCERTSIGN;
3070 break;
3071 case HX509_QUERY_OPTION_END:
3072 default:
3073 break;
3078 * Set the issuer and serial number of match in the query
3079 * controller. The function make copies of the isser and serial number.
3081 * @param q a hx509 query controller
3082 * @param issuer issuer to search for
3083 * @param serialNumber the serialNumber of the issuer.
3085 * @return An hx509 error code, see hx509_get_error_string().
3087 * @ingroup hx509_cert
3090 HX509_LIB_FUNCTION int HX509_LIB_CALL
3091 hx509_query_match_issuer_serial(hx509_query *q,
3092 const Name *issuer,
3093 const heim_integer *serialNumber)
3095 int ret;
3096 if (q->serial) {
3097 der_free_heim_integer(q->serial);
3098 free(q->serial);
3100 q->serial = malloc(sizeof(*q->serial));
3101 if (q->serial == NULL)
3102 return ENOMEM;
3103 ret = der_copy_heim_integer(serialNumber, q->serial);
3104 if (ret) {
3105 free(q->serial);
3106 q->serial = NULL;
3107 return ret;
3109 if (q->issuer_name) {
3110 free_Name(q->issuer_name);
3111 free(q->issuer_name);
3113 q->issuer_name = malloc(sizeof(*q->issuer_name));
3114 if (q->issuer_name == NULL)
3115 return ENOMEM;
3116 ret = copy_Name(issuer, q->issuer_name);
3117 if (ret) {
3118 free(q->issuer_name);
3119 q->issuer_name = NULL;
3120 return ret;
3122 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
3123 return 0;
3127 * Set the query controller to match on a friendly name
3129 * @param q a hx509 query controller.
3130 * @param name a friendly name to match on
3132 * @return An hx509 error code, see hx509_get_error_string().
3134 * @ingroup hx509_cert
3137 HX509_LIB_FUNCTION int HX509_LIB_CALL
3138 hx509_query_match_friendly_name(hx509_query *q, const char *name)
3140 if (q->friendlyname)
3141 free(q->friendlyname);
3142 q->friendlyname = strdup(name);
3143 if (q->friendlyname == NULL)
3144 return ENOMEM;
3145 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
3146 return 0;
3150 * Set the query controller to require an one specific EKU (extended
3151 * key usage). Any previous EKU matching is overwitten. If NULL is
3152 * passed in as the eku, the EKU requirement is reset.
3154 * @param q a hx509 query controller.
3155 * @param eku an EKU to match on.
3157 * @return An hx509 error code, see hx509_get_error_string().
3159 * @ingroup hx509_cert
3162 HX509_LIB_FUNCTION int HX509_LIB_CALL
3163 hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
3165 int ret;
3167 if (eku == NULL) {
3168 if (q->eku) {
3169 der_free_oid(q->eku);
3170 free(q->eku);
3171 q->eku = NULL;
3173 q->match &= ~HX509_QUERY_MATCH_EKU;
3174 } else {
3175 if (q->eku) {
3176 der_free_oid(q->eku);
3177 } else {
3178 q->eku = calloc(1, sizeof(*q->eku));
3179 if (q->eku == NULL)
3180 return ENOMEM;
3182 ret = der_copy_oid(eku, q->eku);
3183 if (ret) {
3184 free(q->eku);
3185 q->eku = NULL;
3186 return ret;
3188 q->match |= HX509_QUERY_MATCH_EKU;
3190 return 0;
3193 HX509_LIB_FUNCTION int HX509_LIB_CALL
3194 hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
3196 if (q->expr) {
3197 _hx509_expr_free(q->expr);
3198 q->expr = NULL;
3201 if (expr == NULL) {
3202 q->match &= ~HX509_QUERY_MATCH_EXPR;
3203 return 0;
3206 q->expr = _hx509_expr_parse(expr);
3207 if (q->expr == NULL) {
3208 const char *reason = _hx509_expr_parse_error();
3210 hx509_set_error_string(context, 0, EINVAL,
3211 "Invalid certificate query match expression: "
3212 "%s (%s)", expr,
3213 reason ? reason : "syntax error");
3214 return EINVAL;
3217 q->match |= HX509_QUERY_MATCH_EXPR;
3218 return 0;
3222 * Set the query controller to match using a specific match function.
3224 * @param q a hx509 query controller.
3225 * @param func function to use for matching, if the argument is NULL,
3226 * the match function is removed.
3227 * @param ctx context passed to the function.
3229 * @return An hx509 error code, see hx509_get_error_string().
3231 * @ingroup hx509_cert
3234 HX509_LIB_FUNCTION int HX509_LIB_CALL
3235 hx509_query_match_cmp_func(hx509_query *q,
3236 int (*func)(hx509_context, hx509_cert, void *),
3237 void *ctx)
3239 if (func)
3240 q->match |= HX509_QUERY_MATCH_FUNCTION;
3241 else
3242 q->match &= ~HX509_QUERY_MATCH_FUNCTION;
3243 q->cmp_func = func;
3244 q->cmp_func_ctx = ctx;
3245 return 0;
3249 * Free the query controller.
3251 * @param context A hx509 context.
3252 * @param q a pointer to the query controller.
3254 * @ingroup hx509_cert
3257 HX509_LIB_FUNCTION void HX509_LIB_CALL
3258 hx509_query_free(hx509_context context, hx509_query *q)
3260 if (q == NULL)
3261 return;
3263 if (q->serial) {
3264 der_free_heim_integer(q->serial);
3265 free(q->serial);
3267 if (q->issuer_name) {
3268 free_Name(q->issuer_name);
3269 free(q->issuer_name);
3271 if (q->eku) {
3272 der_free_oid(q->eku);
3273 free(q->eku);
3275 if (q->friendlyname)
3276 free(q->friendlyname);
3277 if (q->expr)
3278 _hx509_expr_free(q->expr);
3280 memset(q, 0, sizeof(*q));
3281 free(q);
3284 HX509_LIB_FUNCTION int HX509_LIB_CALL
3285 _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
3287 Certificate *c = _hx509_get_cert(cert);
3288 int ret, diff;
3290 _hx509_query_statistic(context, 1, q);
3292 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
3293 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
3294 return 0;
3296 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
3297 _hx509_Certificate_cmp(q->certificate, c) != 0)
3298 return 0;
3300 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
3301 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
3302 return 0;
3304 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
3305 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
3306 if (ret || diff)
3307 return 0;
3310 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
3311 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
3312 if (ret || diff)
3313 return 0;
3316 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
3317 SubjectKeyIdentifier si;
3319 ret = _hx509_find_extension_subject_key_id(c, &si);
3320 if (ret == 0) {
3321 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
3322 ret = 1;
3323 free_SubjectKeyIdentifier(&si);
3325 if (ret)
3326 return 0;
3328 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
3329 return 0;
3330 if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
3331 _hx509_cert_private_key(cert) == NULL)
3332 return 0;
3335 unsigned ku = 0;
3336 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
3337 ku |= (1 << 0);
3338 if (q->match & HX509_QUERY_KU_NONREPUDIATION)
3339 ku |= (1 << 1);
3340 if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
3341 ku |= (1 << 2);
3342 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
3343 ku |= (1 << 3);
3344 if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
3345 ku |= (1 << 4);
3346 if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
3347 ku |= (1 << 5);
3348 if (q->match & HX509_QUERY_KU_CRLSIGN)
3349 ku |= (1 << 6);
3350 if (ku && check_key_usage(context, c, ku, TRUE))
3351 return 0;
3353 if ((q->match & HX509_QUERY_ANCHOR))
3354 return 0;
3356 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
3357 hx509_cert_attribute a;
3359 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
3360 if (a == NULL)
3361 return 0;
3362 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
3363 return 0;
3366 if (q->match & HX509_QUERY_NO_MATCH_PATH) {
3367 size_t i;
3369 for (i = 0; i < q->path->len; i++)
3370 if (hx509_cert_cmp(q->path->val[i], cert) == 0)
3371 return 0;
3373 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
3374 const char *name = hx509_cert_get_friendly_name(cert);
3375 if (name == NULL)
3376 return 0;
3377 if (strcasecmp(q->friendlyname, name) != 0)
3378 return 0;
3380 if (q->match & HX509_QUERY_MATCH_FUNCTION) {
3381 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
3382 if (ret != 0)
3383 return 0;
3386 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
3387 heim_octet_string os;
3389 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3390 os.length =
3391 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3393 ret = _hx509_verify_signature(context,
3394 NULL,
3395 hx509_signature_sha1(),
3396 &os,
3397 q->keyhash_sha1);
3398 if (ret != 0)
3399 return 0;
3402 if (q->match & HX509_QUERY_MATCH_TIME) {
3403 time_t t;
3404 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
3405 if (t > q->timenow)
3406 return 0;
3407 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
3408 if (t < q->timenow)
3409 return 0;
3412 /* If an EKU is required, check the cert for it. */
3413 if ((q->match & HX509_QUERY_MATCH_EKU) &&
3414 hx509_cert_check_eku(context, cert, q->eku, 0))
3415 return 0;
3417 if ((q->match & HX509_QUERY_MATCH_EXPR)) {
3418 hx509_env env = NULL;
3420 ret = _hx509_cert_to_env(context, cert, &env);
3421 if (ret)
3422 return 0;
3424 ret = _hx509_expr_eval(context, env, q->expr);
3425 hx509_env_free(&env);
3426 if (ret == 0)
3427 return 0;
3430 if (q->match & ~HX509_QUERY_MASK)
3431 return 0;
3433 return 1;
3437 * Set a statistic file for the query statistics.
3439 * @param context A hx509 context.
3440 * @param fn statistics file name
3442 * @ingroup hx509_cert
3445 HX509_LIB_FUNCTION void HX509_LIB_CALL
3446 hx509_query_statistic_file(hx509_context context, const char *fn)
3448 if (context->querystat)
3449 free(context->querystat);
3450 context->querystat = strdup(fn);
3453 HX509_LIB_FUNCTION void HX509_LIB_CALL
3454 _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3456 FILE *f;
3457 if (context->querystat == NULL)
3458 return;
3459 f = fopen(context->querystat, "a");
3460 if (f == NULL)
3461 return;
3462 rk_cloexec_file(f);
3463 fprintf(f, "%d %d\n", type, q->match);
3464 fclose(f);
3467 static const char *statname[] = {
3468 "find issuer cert",
3469 "match serialnumber",
3470 "match issuer name",
3471 "match subject name",
3472 "match subject key id",
3473 "match issuer id",
3474 "private key",
3475 "ku encipherment",
3476 "ku digitalsignature",
3477 "ku keycertsign",
3478 "ku crlsign",
3479 "ku nonrepudiation",
3480 "ku keyagreement",
3481 "ku dataencipherment",
3482 "anchor",
3483 "match certificate",
3484 "match local key id",
3485 "no match path",
3486 "match friendly name",
3487 "match function",
3488 "match key hash sha1",
3489 "match time"
3492 struct stat_el {
3493 unsigned long stats;
3494 unsigned int index;
3498 static int
3499 stat_sort(const void *a, const void *b)
3501 const struct stat_el *ae = a;
3502 const struct stat_el *be = b;
3503 return be->stats - ae->stats;
3507 * Unparse the statistics file and print the result on a FILE descriptor.
3509 * @param context A hx509 context.
3510 * @param printtype tyep to print
3511 * @param out the FILE to write the data on.
3513 * @ingroup hx509_cert
3516 HX509_LIB_FUNCTION void HX509_LIB_CALL
3517 hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3519 rtbl_t t;
3520 FILE *f;
3521 int type, mask, num;
3522 size_t i;
3523 unsigned long multiqueries = 0, totalqueries = 0;
3524 struct stat_el stats[32];
3526 if (context->querystat == NULL)
3527 return;
3528 f = fopen(context->querystat, "r");
3529 if (f == NULL) {
3530 fprintf(out, "No statistics file %s: %s.\n",
3531 context->querystat, strerror(errno));
3532 return;
3534 rk_cloexec_file(f);
3536 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3537 stats[i].index = i;
3538 stats[i].stats = 0;
3541 while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3542 if (type != printtype)
3543 continue;
3544 num = i = 0;
3545 while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3546 if (mask & 1) {
3547 stats[i].stats++;
3548 num++;
3550 mask = mask >>1 ;
3551 i++;
3553 if (num > 1)
3554 multiqueries++;
3555 totalqueries++;
3557 fclose(f);
3559 qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3561 t = rtbl_create();
3562 if (t == NULL)
3563 errx(1, "out of memory");
3565 rtbl_set_separator (t, " ");
3567 rtbl_add_column_by_id (t, 0, "Name", 0);
3568 rtbl_add_column_by_id (t, 1, "Counter", 0);
3571 for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3572 char str[10];
3574 if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3575 rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3576 else {
3577 snprintf(str, sizeof(str), "%d", stats[i].index);
3578 rtbl_add_column_entry_by_id (t, 0, str);
3580 snprintf(str, sizeof(str), "%lu", stats[i].stats);
3581 rtbl_add_column_entry_by_id (t, 1, str);
3584 rtbl_format(t, out);
3585 rtbl_destroy(t);
3587 fprintf(out, "\nQueries: multi %lu total %lu\n",
3588 multiqueries, totalqueries);
3592 * Check the extended key usage on the hx509 certificate.
3594 * @param context A hx509 context.
3595 * @param cert A hx509 context.
3596 * @param eku the EKU to check for
3597 * @param allow_any_eku if the any EKU is set, allow that to be a
3598 * substitute.
3600 * @return An hx509 error code, see hx509_get_error_string().
3602 * @ingroup hx509_cert
3605 HX509_LIB_FUNCTION int HX509_LIB_CALL
3606 hx509_cert_check_eku(hx509_context context, hx509_cert cert,
3607 const heim_oid *eku, int allow_any_eku)
3609 ExtKeyUsage e;
3610 int ret;
3611 size_t i;
3613 ret = find_extension_eku(_hx509_get_cert(cert), &e);
3614 if (ret) {
3615 hx509_clear_error_string(context);
3616 return ret;
3619 for (i = 0; i < e.len; i++) {
3620 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3621 free_ExtKeyUsage(&e);
3622 return 0;
3624 if (allow_any_eku) {
3625 if (der_heim_oid_cmp(&asn1_oid_id_x509_ce_anyExtendedKeyUsage,
3626 &e.val[i]) == 0) {
3627 free_ExtKeyUsage(&e);
3628 return 0;
3632 free_ExtKeyUsage(&e);
3633 hx509_clear_error_string(context);
3634 return HX509_CERTIFICATE_MISSING_EKU;
3637 HX509_LIB_FUNCTION int HX509_LIB_CALL
3638 _hx509_cert_get_keyusage(hx509_context context,
3639 hx509_cert c,
3640 KeyUsage *ku)
3642 Certificate *cert;
3643 const Extension *e;
3644 size_t size;
3645 int ret;
3646 size_t i = 0;
3648 memset(ku, 0, sizeof(*ku));
3650 cert = _hx509_get_cert(c);
3652 if (_hx509_cert_get_version(cert) < 3)
3653 return 0;
3655 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3656 if (e == NULL)
3657 return HX509_KU_CERT_MISSING;
3659 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3660 if (ret)
3661 return ret;
3662 return 0;
3665 HX509_LIB_FUNCTION int HX509_LIB_CALL
3666 _hx509_cert_get_eku(hx509_context context,
3667 hx509_cert cert,
3668 ExtKeyUsage *e)
3670 int ret;
3672 memset(e, 0, sizeof(*e));
3674 ret = find_extension_eku(_hx509_get_cert(cert), e);
3675 if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3676 hx509_clear_error_string(context);
3677 return ret;
3679 return 0;
3683 * Encodes the hx509 certificate as a DER encode binary.
3685 * @param context A hx509 context.
3686 * @param c the certificate to encode.
3687 * @param os the encode certificate, set to NULL, 0 on case of
3688 * error. Free the os->data with hx509_xfree().
3690 * @return An hx509 error code, see hx509_get_error_string().
3692 * @ingroup hx509_cert
3695 HX509_LIB_FUNCTION int HX509_LIB_CALL
3696 hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3698 size_t size;
3699 int ret;
3701 os->data = NULL;
3702 os->length = 0;
3704 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3705 _hx509_get_cert(c), &size, ret);
3706 if (ret) {
3707 os->data = NULL;
3708 os->length = 0;
3709 return ret;
3711 if (os->length != size)
3712 _hx509_abort("internal ASN.1 encoder error");
3713 return ret;
3717 * Last to avoid lost __attribute__s due to #undef.
3720 #undef __attribute__
3721 #define __attribute__(X)
3723 HX509_LIB_NORETURN_FUNCTION void HX509_LIB_CALL
3724 _hx509_abort(const char *fmt, ...)
3725 __attribute__ ((__noreturn__, __format__ (__printf__, 1, 2)))
3727 va_list ap;
3728 va_start(ap, fmt);
3729 vprintf(fmt, ap);
3730 va_end(ap);
3731 printf("\n");
3732 fflush(stdout);
3733 abort();
3737 * Free a data element allocated in the library.
3739 * @param ptr data to be freed.
3741 * @ingroup hx509_misc
3744 HX509_LIB_FUNCTION void HX509_LIB_CALL
3745 hx509_xfree(void *ptr)
3747 free(ptr);
3754 HX509_LIB_FUNCTION int HX509_LIB_CALL
3755 _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3757 ExtKeyUsage eku;
3758 hx509_name name;
3759 char *buf;
3760 int ret;
3761 hx509_env envcert = NULL;
3763 *env = NULL;
3765 /* version */
3766 ret = asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3767 if (ret == -1)
3768 goto out;
3769 ret = hx509_env_add(context, &envcert, "version", buf);
3770 free(buf);
3771 if (ret)
3772 goto out;
3774 /* subject */
3775 ret = hx509_cert_get_subject(cert, &name);
3776 if (ret)
3777 goto out;
3779 ret = hx509_name_to_string(name, &buf);
3780 hx509_name_free(&name);
3781 if (ret)
3782 goto out;
3784 ret = hx509_env_add(context, &envcert, "subject", buf);
3785 hx509_xfree(buf);
3786 if (ret)
3787 goto out;
3789 /* issuer */
3790 ret = hx509_cert_get_issuer(cert, &name);
3791 if (ret)
3792 goto out;
3794 ret = hx509_name_to_string(name, &buf);
3795 hx509_name_free(&name);
3796 if (ret)
3797 goto out;
3799 ret = hx509_env_add(context, &envcert, "issuer", buf);
3800 hx509_xfree(buf);
3801 if (ret)
3802 goto out;
3804 /* eku */
3806 ret = _hx509_cert_get_eku(context, cert, &eku);
3807 if (ret == HX509_EXTENSION_NOT_FOUND)
3809 else if (ret != 0)
3810 goto out;
3811 else {
3812 size_t i;
3813 hx509_env enveku = NULL;
3815 for (i = 0; i < eku.len; i++) {
3817 ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3818 if (ret) {
3819 free_ExtKeyUsage(&eku);
3820 hx509_env_free(&enveku);
3821 goto out;
3823 ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3824 free(buf);
3825 if (ret) {
3826 free_ExtKeyUsage(&eku);
3827 hx509_env_free(&enveku);
3828 goto out;
3831 free_ExtKeyUsage(&eku);
3833 ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3834 if (ret) {
3835 hx509_env_free(&enveku);
3836 goto out;
3841 Certificate *c = _hx509_get_cert(cert);
3842 heim_octet_string os, sig;
3843 hx509_env envhash = NULL;
3845 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3846 os.length =
3847 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3849 ret = _hx509_create_signature(context,
3850 NULL,
3851 hx509_signature_sha1(),
3852 &os,
3853 NULL,
3854 &sig);
3855 if (ret != 0)
3856 goto out;
3858 ret = hex_encode(sig.data, sig.length, &buf);
3859 der_free_octet_string(&sig);
3860 if (ret < 0) {
3861 ret = ENOMEM;
3862 hx509_set_error_string(context, 0, ret,
3863 "Out of memory");
3864 goto out;
3867 ret = hx509_env_add(context, &envhash, "sha1", buf);
3868 free(buf);
3869 if (ret)
3870 goto out;
3872 ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3873 if (ret) {
3874 hx509_env_free(&envhash);
3875 goto out;
3879 ret = hx509_env_add_binding(context, env, "certificate", envcert);
3880 if (ret)
3881 goto out;
3883 return 0;
3885 out:
3886 hx509_env_free(&envcert);
3887 return ret;
3891 * Print a simple representation of a certificate
3893 * @param context A hx509 context, can be NULL
3894 * @param cert certificate to print
3895 * @param out the stdio output stream, if NULL, stdout is used
3897 * @return An hx509 error code
3899 * @ingroup hx509_cert
3902 HX509_LIB_FUNCTION int HX509_LIB_CALL
3903 hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3905 hx509_name name;
3906 char *str;
3907 int ret;
3909 if (out == NULL)
3910 out = stderr;
3912 ret = hx509_cert_get_issuer(cert, &name);
3913 if (ret)
3914 return ret;
3915 hx509_name_to_string(name, &str);
3916 hx509_name_free(&name);
3917 fprintf(out, " issuer: \"%s\"\n", str);
3918 free(str);
3920 ret = hx509_cert_get_subject(cert, &name);
3921 if (ret)
3922 return ret;
3923 hx509_name_to_string(name, &str);
3924 hx509_name_free(&name);
3925 fprintf(out, " subject: \"%s\"\n", str);
3926 free(str);
3929 heim_integer serialNumber;
3931 ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3932 if (ret)
3933 return ret;
3934 ret = der_print_hex_heim_integer(&serialNumber, &str);
3935 if (ret)
3936 return ret;
3937 der_free_heim_integer(&serialNumber);
3938 fprintf(out, " serial: %s\n", str);
3939 free(str);
3942 fprintf(out, " keyusage: ");
3943 ret = hx509_cert_keyusage_print(context, cert, &str);
3944 if (ret == 0) {
3945 fprintf(out, "%s\n", str);
3946 free(str);
3947 } else
3948 fprintf(out, "no");
3950 return 0;