LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - cert.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 209 1604 13.0 %
Date: 2024-06-13 04:01:37 Functions: 27 112 24.1 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      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.
      16             :  *
      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.
      20             :  *
      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.
      32             :  */
      33             : 
      34             : #include "hx_locl.h"
      35             : #include "crypto-headers.h"
      36             : #include <rtbl.h>
      37             : 
      38             : /**
      39             :  * @page page_cert The basic certificate
      40             :  *
      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.
      44             :  *
      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().
      49             :  *
      50             :  * See the library functions here: @ref hx509_cert
      51             :  */
      52             : 
      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;
      66             : };
      67             : 
      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)
      71             : 
      72             : struct _hx509_cert_attrs {
      73             :     size_t len;
      74             :     hx509_cert_attribute *val;
      75             : };
      76             : 
      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;
      86             : };
      87             : 
      88             : typedef struct hx509_name_constraints {
      89             :     NameConstraints *val;
      90             :     size_t len;
      91             : } hx509_name_constraints;
      92             : 
      93             : #define GeneralSubtrees_SET(g,var) \
      94             :         (g)->len = (var)->len, (g)->val = (var)->val;
      95             : 
      96             : static void
      97       16879 : init_context_once(void *ignored)
      98             : {
      99             : 
     100       16879 :     ENGINE_add_conf_module();
     101       16879 :     OpenSSL_add_all_algorithms();
     102       16879 : }
     103             : 
     104             : /**
     105             :  * Return a cookie identifying this instance of a library.
     106             :  *
     107             :  * Inputs:
     108             :  *
     109             :  * @context     A krb5_context
     110             :  * @module      Our library name or a library we depend on
     111             :  *
     112             :  * Outputs:     The instance cookie
     113             :  *
     114             :  * @ingroup     krb5_support
     115             :  */
     116             : 
     117             : HX509_LIB_FUNCTION uintptr_t HX509_LIB_CALL
     118           0 : hx509_get_instance(const char *libname)
     119             : {
     120             :     static const char *instance = "libhx509";
     121             : 
     122           0 :     if (strcmp(libname, "hx509") == 0)
     123           0 :         return (uintptr_t)instance;
     124             : 
     125           0 :     return 0;
     126             : }
     127             : 
     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 */
     140             : ;
     141             : 
     142             : /**
     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().
     146             :  *
     147             :  * @param context Returns a pointer to new hx509 context.
     148             :  *
     149             :  * @return Returns an hx509 error code.
     150             :  *
     151             :  * @ingroup hx509
     152             :  */
     153             : 
     154             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     155      555816 : hx509_context_init(hx509_context *contextp)
     156             : {
     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      555816 :     char **files = NULL;
     162             : 
     163      555816 :     *contextp = NULL;
     164      555816 :     context = calloc(1, sizeof(*context));
     165      555816 :     if (context == NULL)
     166           0 :         return ENOMEM;
     167             : 
     168      555816 :     heim_base_once_f(&init_context, NULL, init_context_once);
     169             : 
     170      555816 :     if ((context->hcontext = heim_context_init()) == NULL) {
     171           0 :         free(context);
     172           0 :         return ENOMEM;
     173             :     }
     174             : 
     175      555816 :     if ((ret = heim_get_default_config_files(hx509_config_file,
     176             :                                              "HX509_CONFIG",
     177             :                                              &files))) {
     178           0 :         heim_context_free(&context->hcontext);
     179           0 :         free(context);
     180           0 :         return ret;
     181             :     }
     182             : 
     183             :     /* If there's no hx509 config, we continue, as we never needed it before */
     184      555816 :     if (files)
     185      555816 :         (void) heim_set_config_files(context->hcontext, files, &context->cf);
     186      555816 :     heim_free_config_files(files);
     187             : 
     188      555816 :     _hx509_ks_null_register(context);
     189      555816 :     _hx509_ks_mem_register(context);
     190      555816 :     _hx509_ks_file_register(context);
     191      555816 :     _hx509_ks_pkcs12_register(context);
     192      555816 :     _hx509_ks_pkcs11_register(context);
     193      555816 :     _hx509_ks_dir_register(context);
     194      555816 :     _hx509_ks_keychain_register(context);
     195             : 
     196      555816 :     context->ocsp_time_diff =
     197      555816 :         heim_config_get_time_default(context->hcontext, context->cf,
     198             :                                      HX509_DEFAULT_OCSP_TIME_DIFF,
     199             :                                      "libdefaults", "ocsp_time_dif", NULL);
     200             : 
     201      555816 :     initialize_hx_error_table_r(&context->et_list);
     202      555816 :     initialize_asn1_error_table_r(&context->et_list);
     203             : 
     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      555816 :     anchors = heim_config_get_string(context->hcontext, context->cf,
     210             :                                      "libdefaults", "anchors", NULL);
     211             : #endif
     212      555816 :     if (anchors)
     213           0 :         (void)hx509_certs_init(context, anchors, 0, NULL,
     214             :                                &context->default_trust_anchors);
     215             : 
     216      555816 :     *contextp = context;
     217      555816 :     return 0;
     218             : }
     219             : 
     220             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     221           0 : hx509_set_log_dest(hx509_context context, heim_log_facility *fac)
     222             : {
     223           0 :     return heim_set_log_dest(context->hcontext, fac);
     224             : }
     225             : 
     226             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     227           0 : hx509_set_debug_dest(hx509_context context, heim_log_facility *fac)
     228             : {
     229           0 :     return heim_set_debug_dest(context->hcontext, fac);
     230             : }
     231             : 
     232             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     233           0 : hx509_set_warn_dest(hx509_context context, heim_log_facility *fac)
     234             : {
     235           0 :     return heim_set_warn_dest(context->hcontext, fac);
     236             : }
     237             : 
     238             : /**
     239             :  * Selects if the hx509_revoke_verify() function is going to require
     240             :  * the existans of a revokation method (OCSP, CRL) or not. Note that
     241             :  * hx509_verify_path(), hx509_cms_verify_signed(), and other function
     242             :  * call hx509_revoke_verify().
     243             :  *
     244             :  * @param context hx509 context to change the flag for.
     245             :  * @param flag zero, revokation method required, non zero missing
     246             :  * revokation method ok
     247             :  *
     248             :  * @ingroup hx509_verify
     249             :  */
     250             : 
     251             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     252         115 : hx509_context_set_missing_revoke(hx509_context context, int flag)
     253             : {
     254         115 :     if (flag)
     255         115 :         context->flags |= HX509_CTX_VERIFY_MISSING_OK;
     256             :     else
     257           0 :         context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
     258         115 : }
     259             : 
     260             : /**
     261             :  * Free the context allocated by hx509_context_init().
     262             :  *
     263             :  * @param context context to be freed.
     264             :  *
     265             :  * @ingroup hx509
     266             :  */
     267             : 
     268             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     269      533651 : hx509_context_free(hx509_context *context)
     270             : {
     271      533651 :     if (!*context)
     272           0 :         return;
     273             : 
     274      533651 :     hx509_clear_error_string(*context);
     275      533651 :     if ((*context)->ks_ops) {
     276      533651 :         free((*context)->ks_ops);
     277      533651 :         (*context)->ks_ops = NULL;
     278             :     }
     279      533651 :     (*context)->ks_num_ops = 0;
     280      533651 :     free_error_table ((*context)->et_list);
     281      533651 :     if ((*context)->querystat)
     282           0 :         free((*context)->querystat);
     283      533651 :     hx509_certs_free(&(*context)->default_trust_anchors);
     284      533651 :     heim_config_file_free((*context)->hcontext, (*context)->cf);
     285      533651 :     heim_context_free(&(*context)->hcontext);
     286      533651 :     memset(*context, 0, sizeof(**context));
     287      533651 :     free(*context);
     288      533651 :     *context = NULL;
     289             : }
     290             : 
     291             : /*
     292             :  *
     293             :  */
     294             : 
     295             : HX509_LIB_FUNCTION Certificate * HX509_LIB_CALL
     296         114 : _hx509_get_cert(hx509_cert cert)
     297             : {
     298         114 :     return cert->data;
     299             : }
     300             : 
     301             : /*
     302             :  *
     303             :  */
     304             : 
     305             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     306           0 : _hx509_cert_get_version(const Certificate *t)
     307             : {
     308           0 :     return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
     309             : }
     310             : 
     311             : static hx509_cert
     312         151 : cert_init(hx509_context context, heim_error_t *error)
     313             : {
     314             :     hx509_cert cert;
     315             : 
     316         151 :     cert = malloc(sizeof(*cert));
     317         151 :     if (cert == NULL) {
     318           0 :         if (error)
     319           0 :             *error = heim_error_create_enomem();
     320           0 :         return NULL;
     321             :     }
     322         151 :     cert->ref = 1;
     323         151 :     cert->friendlyname = NULL;
     324         151 :     cert->attrs.len = 0;
     325         151 :     cert->attrs.val = NULL;
     326         151 :     cert->private_key = NULL;
     327         151 :     cert->basename = NULL;
     328         151 :     cert->release = NULL;
     329         151 :     cert->ctx = NULL;
     330         151 :     cert->data= NULL;
     331         151 :     return cert;
     332             : }
     333             : 
     334             : /**
     335             :  * Allocate and init an hx509 certificate object from the decoded
     336             :  * certificate `c´.
     337             :  *
     338             :  * @param context A hx509 context.
     339             :  * @param c
     340             :  * @param error
     341             :  *
     342             :  * @return Returns an hx509 certificate
     343             :  *
     344             :  * @ingroup hx509_cert
     345             :  */
     346             : 
     347             : HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
     348         151 : hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error)
     349             : {
     350             :     hx509_cert cert;
     351             :     int ret;
     352             : 
     353         151 :     if ((cert = cert_init(context, error)) == NULL)
     354           0 :         return NULL;
     355             : 
     356         151 :     cert->data = calloc(1, sizeof(*(cert->data)));
     357         151 :     if (cert->data == NULL) {
     358           0 :         free(cert);
     359           0 :         if (error)
     360           0 :             *error = heim_error_create_enomem();
     361           0 :         return NULL;
     362             :     }
     363         151 :     ret = copy_Certificate(c, cert->data);
     364         151 :     if (ret) {
     365           0 :         free(cert->data);
     366           0 :         free(cert);
     367           0 :         cert = NULL;
     368             :     }
     369         151 :     return cert;
     370             : }
     371             : 
     372             : /**
     373             :  * Copy a certificate object, but drop any private key assignment.
     374             :  *
     375             :  * @param context A hx509 context.
     376             :  * @param src Certificate object
     377             :  * @param error
     378             :  *
     379             :  * @return Returns an hx509 certificate
     380             :  *
     381             :  * @ingroup hx509_cert
     382             :  */
     383             : 
     384             : HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
     385           0 : hx509_cert_copy_no_private_key(hx509_context context,
     386             :                                hx509_cert src,
     387             :                                heim_error_t *error)
     388             : {
     389           0 :     return hx509_cert_init(context, src->data, error);
     390             : }
     391             : 
     392             : /**
     393             :  * Allocate and init an hx509 certificate object containing only a private key
     394             :  * (but no Certificate).
     395             :  *
     396             :  * @param context A hx509 context.
     397             :  * @param key
     398             :  * @param error
     399             :  *
     400             :  * @return Returns an hx509 certificate
     401             :  *
     402             :  * @ingroup hx509_cert
     403             :  */
     404             : 
     405             : HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
     406           0 : hx509_cert_init_private_key(hx509_context context,
     407             :                             hx509_private_key key,
     408             :                             heim_error_t *error)
     409             : {
     410             :     hx509_cert cert;
     411             : 
     412           0 :     if ((cert = cert_init(context, error)))
     413           0 :         (void) _hx509_cert_assign_key(cert, key);
     414           0 :     return cert;
     415             : }
     416             : 
     417             : /**
     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.
     421             :  *
     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.
     425             :  *
     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
     430             :  *
     431             :  * @return An hx509 certificate
     432             :  *
     433             :  * @ingroup hx509_cert
     434             :  */
     435             : 
     436             : HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
     437         151 : hx509_cert_init_data(hx509_context context,
     438             :                      const void *ptr,
     439             :                      size_t len,
     440             :                      heim_error_t *error)
     441             : {
     442             :     hx509_cert cert;
     443             :     Certificate t;
     444             :     size_t size;
     445             :     int ret;
     446             : 
     447         151 :     ret = decode_Certificate(ptr, len, &t, &size);
     448         151 :     if (ret) {
     449           0 :         if (error)
     450           0 :             *error = heim_error_create(ret, "Failed to decode certificate");
     451           0 :         errno = ret;
     452           0 :         return NULL;
     453             :     }
     454         151 :     if (size != len) {
     455           0 :         free_Certificate(&t);
     456           0 :         if (error)
     457           0 :             *error = heim_error_create(HX509_EXTRA_DATA_AFTER_STRUCTURE,
     458             :                                        "Extra data after certificate");
     459           0 :         errno = HX509_EXTRA_DATA_AFTER_STRUCTURE;
     460           0 :         return NULL;
     461             :     }
     462             : 
     463         151 :     cert = hx509_cert_init(context, &t, error);
     464         151 :     free_Certificate(&t);
     465         151 :     return cert;
     466             : }
     467             : 
     468             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     469           0 : _hx509_cert_set_release(hx509_cert cert,
     470             :                         _hx509_cert_release_func release,
     471             :                         void *ctx)
     472             : {
     473           0 :     cert->release = release;
     474           0 :     cert->ctx = ctx;
     475           0 : }
     476             : 
     477             : 
     478             : /* Doesn't make a copy of `private_key'. */
     479             : 
     480             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     481          38 : _hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
     482             : {
     483          38 :     if (cert->private_key)
     484           0 :         hx509_private_key_free(&cert->private_key);
     485          38 :     cert->private_key = _hx509_private_key_ref(private_key);
     486          38 :     return 0;
     487             : }
     488             : 
     489             : /**
     490             :  * Free reference to the hx509 certificate object, if the refcounter
     491             :  * reaches 0, the object if freed. Its allowed to pass in NULL.
     492             :  *
     493             :  * @param cert the cert to free.
     494             :  *
     495             :  * @ingroup hx509_cert
     496             :  */
     497             : 
     498             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     499        1250 : hx509_cert_free(hx509_cert cert)
     500             : {
     501             :     size_t i;
     502             : 
     503        1250 :     if (cert == NULL)
     504         571 :         return;
     505             : 
     506         679 :     if (cert->ref <= 0)
     507           0 :         _hx509_abort("cert refcount <= 0 on free");
     508         679 :     if (--cert->ref > 0)
     509         604 :         return;
     510             : 
     511          75 :     if (cert->release)
     512           0 :         (cert->release)(cert, cert->ctx);
     513             : 
     514          75 :     if (cert->private_key)
     515           0 :         hx509_private_key_free(&cert->private_key);
     516             : 
     517          75 :     if (cert->data)
     518          75 :         free_Certificate(cert->data);
     519          75 :     free(cert->data);
     520             : 
     521          75 :     for (i = 0; i < cert->attrs.len; i++) {
     522           0 :         der_free_octet_string(&cert->attrs.val[i]->data);
     523           0 :         der_free_oid(&cert->attrs.val[i]->oid);
     524           0 :         free(cert->attrs.val[i]);
     525             :     }
     526          75 :     free(cert->attrs.val);
     527          75 :     free(cert->friendlyname);
     528          75 :     if (cert->basename)
     529           0 :         hx509_name_free(&cert->basename);
     530          75 :     memset(cert, 0, sizeof(*cert));
     531          75 :     free(cert);
     532             : }
     533             : 
     534             : /**
     535             :  * Add a reference to a hx509 certificate object.
     536             :  *
     537             :  * @param cert a pointer to an hx509 certificate object.
     538             :  *
     539             :  * @return the same object as is passed in.
     540             :  *
     541             :  * @ingroup hx509_cert
     542             :  */
     543             : 
     544             : HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
     545         681 : hx509_cert_ref(hx509_cert cert)
     546             : {
     547         681 :     if (cert == NULL)
     548          77 :         return NULL;
     549         604 :     if (cert->ref <= 0)
     550           0 :         _hx509_abort("cert refcount <= 0");
     551         604 :     cert->ref++;
     552         604 :     if (cert->ref == 0)
     553           0 :         _hx509_abort("cert refcount == 0");
     554         604 :     return cert;
     555             : }
     556             : 
     557             : /**
     558             :  * Allocate an verification context that is used fo control the
     559             :  * verification process.
     560             :  *
     561             :  * @param context A hx509 context.
     562             :  * @param ctx returns a pointer to a hx509_verify_ctx object.
     563             :  *
     564             :  * @return An hx509 error code, see hx509_get_error_string().
     565             :  *
     566             :  * @ingroup hx509_verify
     567             :  */
     568             : 
     569             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     570         115 : hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
     571             : {
     572             :     hx509_verify_ctx c;
     573             : 
     574         115 :     c = calloc(1, sizeof(*c));
     575         115 :     if (c == NULL)
     576           0 :         return ENOMEM;
     577             : 
     578         115 :     c->max_depth = HX509_VERIFY_MAX_DEPTH;
     579             : 
     580         115 :     *ctx = c;
     581             : 
     582         115 :     return 0;
     583             : }
     584             : 
     585             : /**
     586             :  * Free an hx509 verification context.
     587             :  *
     588             :  * @param ctx the context to be freed.
     589             :  *
     590             :  * @ingroup hx509_verify
     591             :  */
     592             : 
     593             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     594         110 : hx509_verify_destroy_ctx(hx509_verify_ctx ctx)
     595             : {
     596         110 :     if (ctx) {
     597          77 :         hx509_certs_free(&ctx->trust_anchors);
     598          77 :         hx509_revoke_free(&ctx->revoke_ctx);
     599          77 :         memset(ctx, 0, sizeof(*ctx));
     600             :     }
     601         110 :     free(ctx);
     602         110 : }
     603             : 
     604             : /**
     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.
     609             :  *
     610             :  * @param ctx a verification context
     611             :  * @param set a keyset containing the trust anchors.
     612             :  *
     613             :  * @ingroup hx509_verify
     614             :  */
     615             : 
     616             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     617         115 : hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
     618             : {
     619         115 :     if (ctx->trust_anchors)
     620           0 :         hx509_certs_free(&ctx->trust_anchors);
     621         115 :     ctx->trust_anchors = hx509_certs_ref(set);
     622         115 : }
     623             : 
     624             : /**
     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.
     630             :  *
     631             :  * @param ctx a verification context.
     632             :  * @param revoke_ctx a revoke context.
     633             :  *
     634             :  * @ingroup hx509_verify
     635             :  */
     636             : 
     637             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     638         115 : hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
     639             : {
     640         115 :     if (ctx->revoke_ctx)
     641           0 :         hx509_revoke_free(&ctx->revoke_ctx);
     642         115 :     ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
     643         115 : }
     644             : 
     645             : /**
     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.
     649             :  *
     650             :  * @param ctx a verification context.
     651             :  * @param t the time the verifiation is using.
     652             :  *
     653             :  *
     654             :  * @ingroup hx509_verify
     655             :  */
     656             : 
     657             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     658           0 : hx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
     659             : {
     660           0 :     ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
     661           0 :     ctx->time_now = t;
     662           0 : }
     663             : 
     664             : HX509_LIB_FUNCTION time_t HX509_LIB_CALL
     665           0 : _hx509_verify_get_time(hx509_verify_ctx ctx)
     666             : {
     667           0 :     return ctx->time_now;
     668             : }
     669             : 
     670             : /**
     671             :  * Set the maximum depth of the certificate chain that the path
     672             :  * builder is going to try.
     673             :  *
     674             :  * @param ctx a verification context
     675             :  * @param max_depth maxium depth of the certificate chain, include
     676             :  * trust anchor.
     677             :  *
     678             :  * @ingroup hx509_verify
     679             :  */
     680             : 
     681             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     682           0 : hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
     683             : {
     684           0 :     ctx->max_depth = max_depth;
     685           0 : }
     686             : 
     687             : /**
     688             :  * Allow or deny the use of proxy certificates
     689             :  *
     690             :  * @param ctx a verification context
     691             :  * @param boolean if non zero, allow proxy certificates.
     692             :  *
     693             :  * @ingroup hx509_verify
     694             :  */
     695             : 
     696             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     697           0 : hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
     698             : {
     699           0 :     if (boolean)
     700           0 :         ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
     701             :     else
     702           0 :         ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
     703           0 : }
     704             : 
     705             : /**
     706             :  * Select strict RFC3280 verification of certificiates. This means
     707             :  * checking key usage on CA certificates, this will make version 1
     708             :  * certificiates unuseable.
     709             :  *
     710             :  * @param ctx a verification context
     711             :  * @param boolean if non zero, use strict verification.
     712             :  *
     713             :  * @ingroup hx509_verify
     714             :  */
     715             : 
     716             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     717           0 : hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
     718             : {
     719           0 :     if (boolean)
     720           0 :         ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
     721             :     else
     722           0 :         ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
     723           0 : }
     724             : 
     725             : /**
     726             :  * Allow using the operating system builtin trust anchors if no other
     727             :  * trust anchors are configured.
     728             :  *
     729             :  * @param ctx a verification context
     730             :  * @param boolean if non zero, useing the operating systems builtin
     731             :  * trust anchors.
     732             :  *
     733             :  *
     734             :  * @return An hx509 error code, see hx509_get_error_string().
     735             :  *
     736             :  * @ingroup hx509_cert
     737             :  */
     738             : 
     739             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     740           0 : hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
     741             : {
     742           0 :     if (boolean)
     743           0 :         ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
     744             :     else
     745           0 :         ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
     746           0 : }
     747             : 
     748             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     749           0 : hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
     750             :                                                     int boolean)
     751             : {
     752           0 :     if (boolean)
     753           0 :         ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
     754             :     else
     755           0 :         ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
     756           0 : }
     757             : 
     758             : static const Extension *
     759          38 : find_extension(const Certificate *cert, const heim_oid *oid, size_t *idx)
     760             : {
     761          38 :     const TBSCertificate *c = &cert->tbsCertificate;
     762             : 
     763          38 :     if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
     764           0 :         return NULL;
     765             : 
     766         418 :     for (;*idx < c->extensions->len; (*idx)++) {
     767         418 :         if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
     768          38 :             return &c->extensions->val[(*idx)++];
     769             :     }
     770           0 :     return NULL;
     771             : }
     772             : 
     773             : static int
     774           0 : find_extension_auth_key_id(const Certificate *subject,
     775             :                            AuthorityKeyIdentifier *ai)
     776             : {
     777             :     const Extension *e;
     778             :     size_t size;
     779           0 :     size_t i = 0;
     780             : 
     781           0 :     memset(ai, 0, sizeof(*ai));
     782             : 
     783           0 :     e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
     784           0 :     if (e == NULL)
     785           0 :         return HX509_EXTENSION_NOT_FOUND;
     786             : 
     787           0 :     return decode_AuthorityKeyIdentifier(e->extnValue.data,
     788             :                                          e->extnValue.length,
     789             :                                          ai, &size);
     790             : }
     791             : 
     792             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     793           0 : _hx509_find_extension_subject_key_id(const Certificate *issuer,
     794             :                                      SubjectKeyIdentifier *si)
     795             : {
     796             :     const Extension *e;
     797             :     size_t size;
     798           0 :     size_t i = 0;
     799             : 
     800           0 :     memset(si, 0, sizeof(*si));
     801             : 
     802           0 :     e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
     803           0 :     if (e == NULL)
     804           0 :         return HX509_EXTENSION_NOT_FOUND;
     805             : 
     806           0 :     return decode_SubjectKeyIdentifier(e->extnValue.data,
     807             :                                        e->extnValue.length,
     808             :                                        si, &size);
     809             : }
     810             : 
     811             : static int
     812           0 : find_extension_name_constraints(const Certificate *subject,
     813             :                                 NameConstraints *nc)
     814             : {
     815             :     const Extension *e;
     816             :     size_t size;
     817           0 :     size_t i = 0;
     818             : 
     819           0 :     memset(nc, 0, sizeof(*nc));
     820             : 
     821           0 :     e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
     822           0 :     if (e == NULL)
     823           0 :         return HX509_EXTENSION_NOT_FOUND;
     824             : 
     825           0 :     return decode_NameConstraints(e->extnValue.data,
     826             :                                   e->extnValue.length,
     827             :                                   nc, &size);
     828             : }
     829             : 
     830             : static int
     831           0 : find_extension_subject_alt_name(const Certificate *cert, size_t *i,
     832             :                                 GeneralNames *sa)
     833             : {
     834             :     const Extension *e;
     835             :     size_t size;
     836             : 
     837           0 :     memset(sa, 0, sizeof(*sa));
     838             : 
     839           0 :     e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
     840           0 :     if (e == NULL)
     841           0 :         return HX509_EXTENSION_NOT_FOUND;
     842             : 
     843           0 :     return decode_GeneralNames(e->extnValue.data,
     844             :                                e->extnValue.length,
     845             :                                sa, &size);
     846             : }
     847             : 
     848             : static int
     849          38 : find_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
     850             : {
     851             :     const Extension *e;
     852             :     size_t size;
     853          38 :     size_t i = 0;
     854             : 
     855          38 :     memset(eku, 0, sizeof(*eku));
     856             : 
     857          38 :     e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
     858          38 :     if (e == NULL)
     859           0 :         return HX509_EXTENSION_NOT_FOUND;
     860             : 
     861          38 :     return decode_ExtKeyUsage(e->extnValue.data,
     862             :                               e->extnValue.length,
     863             :                               eku, &size);
     864             : }
     865             : 
     866             : static int
     867           0 : add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
     868             : {
     869             :     void *p;
     870             :     int ret;
     871             : 
     872           0 :     p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
     873           0 :     if (p == NULL)
     874           0 :         return ENOMEM;
     875           0 :     list->val = p;
     876           0 :     ret = der_copy_octet_string(entry, &list->val[list->len]);
     877           0 :     if (ret)
     878           0 :         return ret;
     879           0 :     list->len++;
     880           0 :     return 0;
     881             : }
     882             : 
     883             : /**
     884             :  * Free a list of octet strings returned by another hx509 library
     885             :  * function.
     886             :  *
     887             :  * @param list list to be freed.
     888             :  *
     889             :  * @ingroup hx509_misc
     890             :  */
     891             : 
     892             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     893           0 : hx509_free_octet_string_list(hx509_octet_string_list *list)
     894             : {
     895             :     size_t i;
     896             : 
     897           0 :     if (list->val) {
     898           0 :         for (i = 0; i < list->len; i++)
     899           0 :             der_free_octet_string(&list->val[i]);
     900           0 :         free(list->val);
     901             :     }
     902           0 :     list->val = NULL;
     903           0 :     list->len = 0;
     904           0 : }
     905             : 
     906             : /**
     907             :  * Return a list of subjectAltNames specified by oid in the
     908             :  * certificate. On error the
     909             :  *
     910             :  * The returned list of octet string should be freed with
     911             :  * hx509_free_octet_string_list().
     912             :  *
     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.
     917             :  *
     918             :  * @return An hx509 error code, see hx509_get_error_string().
     919             :  *
     920             :  * @ingroup hx509_cert
     921             :  */
     922             : 
     923             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     924           0 : hx509_cert_find_subjectAltName_otherName(hx509_context context,
     925             :                                          hx509_cert cert,
     926             :                                          const heim_oid *oid,
     927             :                                          hx509_octet_string_list *list)
     928             : {
     929             :     GeneralNames sa;
     930             :     int ret;
     931             :     size_t i, j;
     932             : 
     933           0 :     list->val = NULL;
     934           0 :     list->len = 0;
     935             : 
     936           0 :     i = 0;
     937             :     while (1) {
     938           0 :         ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
     939           0 :         i++;
     940           0 :         if (ret == HX509_EXTENSION_NOT_FOUND) {
     941           0 :             return 0;
     942           0 :         } else if (ret != 0) {
     943           0 :             hx509_set_error_string(context, 0, ret, "Error searching for SAN");
     944           0 :             hx509_free_octet_string_list(list);
     945           0 :             return ret;
     946             :         }
     947             : 
     948           0 :         for (j = 0; j < sa.len; j++) {
     949           0 :             if (sa.val[j].element == choice_GeneralName_otherName &&
     950           0 :                 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
     951             :             {
     952           0 :                 ret = add_to_list(list, &sa.val[j].u.otherName.value);
     953           0 :                 if (ret) {
     954           0 :                     hx509_set_error_string(context, 0, ret,
     955             :                                            "Error adding an exra SAN to "
     956             :                                            "return list");
     957           0 :                     hx509_free_octet_string_list(list);
     958           0 :                     free_GeneralNames(&sa);
     959           0 :                     return ret;
     960             :                 }
     961             :             }
     962             :         }
     963           0 :         free_GeneralNames(&sa);
     964             :     }
     965             : }
     966             : 
     967             : 
     968             : static int
     969           0 : check_key_usage(hx509_context context, const Certificate *cert,
     970             :                 unsigned flags, int req_present)
     971             : {
     972             :     const Extension *e;
     973             :     KeyUsage ku;
     974             :     size_t size;
     975             :     int ret;
     976           0 :     size_t i = 0;
     977             :     uint64_t ku_flags;
     978             : 
     979           0 :     if (_hx509_cert_get_version(cert) < 3)
     980           0 :         return 0;
     981             : 
     982           0 :     e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
     983           0 :     if (e == NULL) {
     984           0 :         if (req_present) {
     985           0 :             hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
     986             :                                    "Required extension key "
     987             :                                    "usage missing from certificate");
     988           0 :             return HX509_KU_CERT_MISSING;
     989             :         }
     990           0 :         return 0;
     991             :     }
     992             : 
     993           0 :     ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
     994           0 :     if (ret)
     995           0 :         return ret;
     996           0 :     ku_flags = KeyUsage2int(ku);
     997           0 :     if ((ku_flags & flags) != flags) {
     998           0 :         uint64_t missing = (~ku_flags) & flags;
     999             :         char buf[256], *name;
    1000             : 
    1001           0 :         int result = unparse_flags(missing, asn1_KeyUsage_units(),
    1002             :                                    buf, sizeof(buf));
    1003           0 :         _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
    1004           0 :         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           0 :                                name ? name : "<unknown>");
    1009           0 :         free(name);
    1010           0 :         return HX509_KU_CERT_MISSING;
    1011             :     }
    1012           0 :     return 0;
    1013             : }
    1014             : 
    1015             : /*
    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.
    1019             :  */
    1020             : 
    1021             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1022           0 : _hx509_check_key_usage(hx509_context context, hx509_cert cert,
    1023             :                        unsigned flags, int req_present)
    1024             : {
    1025           0 :     return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
    1026             : }
    1027             : 
    1028             : enum certtype { PROXY_CERT, EE_CERT, CA_CERT };
    1029             : 
    1030             : static int
    1031           0 : check_basic_constraints(hx509_context context, const Certificate *cert,
    1032             :                         enum certtype type, size_t depth)
    1033             : {
    1034             :     BasicConstraints bc;
    1035             :     const Extension *e;
    1036             :     size_t size;
    1037             :     int ret;
    1038           0 :     size_t i = 0;
    1039             : 
    1040           0 :     if (_hx509_cert_get_version(cert) < 3)
    1041           0 :         return 0;
    1042             : 
    1043           0 :     e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
    1044           0 :     if (e == NULL) {
    1045           0 :         switch(type) {
    1046           0 :         case PROXY_CERT:
    1047             :         case EE_CERT:
    1048           0 :             return 0;
    1049           0 :         case CA_CERT: {
    1050             :             char *name;
    1051           0 :             ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
    1052           0 :             assert(ret == 0);
    1053           0 :             hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
    1054             :                                    "basicConstraints missing from "
    1055             :                                    "CA certifiacte %s", name);
    1056           0 :             free(name);
    1057           0 :             return HX509_EXTENSION_NOT_FOUND;
    1058             :         }
    1059             :         }
    1060             :     }
    1061             : 
    1062           0 :     ret = decode_BasicConstraints(e->extnValue.data,
    1063             :                                   e->extnValue.length, &bc,
    1064             :                                   &size);
    1065           0 :     if (ret)
    1066           0 :         return ret;
    1067           0 :     switch(type) {
    1068           0 :     case PROXY_CERT:
    1069           0 :         if (bc.cA)
    1070           0 :             ret = HX509_PARENT_IS_CA;
    1071           0 :         break;
    1072           0 :     case EE_CERT:
    1073           0 :         ret = 0;
    1074           0 :         break;
    1075           0 :     case CA_CERT:
    1076           0 :         if (!bc.cA)
    1077           0 :             ret = HX509_PARENT_NOT_CA;
    1078           0 :         else if (bc.pathLenConstraint)
    1079           0 :             if (depth - 1 > *bc.pathLenConstraint)
    1080           0 :                 ret = HX509_CA_PATH_TOO_DEEP;
    1081           0 :         break;
    1082             :     }
    1083           0 :     free_BasicConstraints(&bc);
    1084           0 :     return ret;
    1085             : }
    1086             : 
    1087             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1088           0 : _hx509_cert_is_parent_cmp(const Certificate *subject,
    1089             :                           const Certificate *issuer,
    1090             :                           int allow_self_signed)
    1091             : {
    1092             :     int diff;
    1093             :     AuthorityKeyIdentifier ai;
    1094             :     SubjectKeyIdentifier si;
    1095             :     int ret_ai, ret_si, ret;
    1096             : 
    1097           0 :     ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
    1098             :                           &subject->tbsCertificate.issuer,
    1099             :                           &diff);
    1100           0 :     if (ret)
    1101           0 :         return ret;
    1102           0 :     if (diff)
    1103           0 :         return diff;
    1104             : 
    1105           0 :     memset(&ai, 0, sizeof(ai));
    1106           0 :     memset(&si, 0, sizeof(si));
    1107             : 
    1108             :     /*
    1109             :      * Try to find AuthorityKeyIdentifier, if it's not present in the
    1110             :      * subject certificate nor the parent.
    1111             :      */
    1112             : 
    1113           0 :     ret_ai = find_extension_auth_key_id(subject, &ai);
    1114           0 :     if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
    1115           0 :         return 1;
    1116           0 :     ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
    1117           0 :     if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
    1118           0 :         return -1;
    1119             : 
    1120           0 :     if (ret_si && ret_ai)
    1121           0 :         goto out;
    1122           0 :     if (ret_ai)
    1123           0 :         goto out;
    1124           0 :     if (ret_si) {
    1125           0 :         if (allow_self_signed) {
    1126           0 :             diff = 0;
    1127           0 :             goto out;
    1128           0 :         } else if (ai.keyIdentifier) {
    1129           0 :             diff = -1;
    1130           0 :             goto out;
    1131             :         }
    1132             :     }
    1133             : 
    1134           0 :     if (ai.keyIdentifier == NULL) {
    1135             :         Name name;
    1136             : 
    1137           0 :         if (ai.authorityCertIssuer == NULL)
    1138           0 :             return -1;
    1139           0 :         if (ai.authorityCertSerialNumber == NULL)
    1140           0 :             return -1;
    1141             : 
    1142           0 :         diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
    1143           0 :                                     &issuer->tbsCertificate.serialNumber);
    1144           0 :         if (diff)
    1145           0 :             return diff;
    1146           0 :         if (ai.authorityCertIssuer->len != 1)
    1147           0 :             return -1;
    1148           0 :         if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
    1149           0 :             return -1;
    1150             : 
    1151           0 :         name.element = (enum Name_enum)
    1152           0 :             ai.authorityCertIssuer->val[0].u.directoryName.element;
    1153           0 :         name.u.rdnSequence =
    1154           0 :             ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
    1155             : 
    1156           0 :         ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
    1157             :                               &name,
    1158             :                               &diff);
    1159           0 :         if (ret)
    1160           0 :             return ret;
    1161           0 :         if (diff)
    1162           0 :             return diff;
    1163           0 :         diff = 0;
    1164             :     } else
    1165           0 :         diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
    1166           0 :     if (diff)
    1167           0 :         goto out;
    1168             : 
    1169           0 :  out:
    1170           0 :     free_AuthorityKeyIdentifier(&ai);
    1171           0 :     free_SubjectKeyIdentifier(&si);
    1172           0 :     return diff;
    1173             : }
    1174             : 
    1175             : static int
    1176           0 : certificate_is_anchor(hx509_context context,
    1177             :                       hx509_certs trust_anchors,
    1178             :                       const hx509_cert cert)
    1179             : {
    1180             :     hx509_query q;
    1181             :     hx509_cert c;
    1182             :     int ret;
    1183             : 
    1184           0 :     if (trust_anchors == NULL)
    1185           0 :         return 0;
    1186             : 
    1187           0 :     _hx509_query_clear(&q);
    1188             : 
    1189           0 :     q.match = HX509_QUERY_MATCH_CERTIFICATE;
    1190           0 :     q.certificate = _hx509_get_cert(cert);
    1191             : 
    1192           0 :     ret = hx509_certs_find(context, trust_anchors, &q, &c);
    1193           0 :     if (ret == 0)
    1194           0 :         hx509_cert_free(c);
    1195           0 :     return ret == 0;
    1196             : }
    1197             : 
    1198             : static int
    1199           0 : certificate_is_self_signed(hx509_context context,
    1200             :                            const Certificate *cert,
    1201             :                            int *self_signed)
    1202             : {
    1203             :     int ret, diff;
    1204           0 :     ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
    1205             :                           &cert->tbsCertificate.issuer, &diff);
    1206           0 :     *self_signed = (diff == 0);
    1207           0 :     if (ret) {
    1208           0 :         hx509_set_error_string(context, 0, ret,
    1209             :                                "Failed to check if self signed");
    1210             :     } else
    1211           0 :         ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm);
    1212             : 
    1213           0 :     return ret;
    1214             : }
    1215             : 
    1216             : /*
    1217             :  * The subjectName is "null" when it's empty set of relative DBs.
    1218             :  */
    1219             : 
    1220             : static int
    1221           0 : subject_null_p(const Certificate *c)
    1222             : {
    1223           0 :     return c->tbsCertificate.subject.u.rdnSequence.len == 0;
    1224             : }
    1225             : 
    1226             : 
    1227             : static int
    1228           0 : find_parent(hx509_context context,
    1229             :             time_t time_now,
    1230             :             hx509_certs trust_anchors,
    1231             :             hx509_path *path,
    1232             :             hx509_certs pool,
    1233             :             hx509_cert current,
    1234             :             hx509_cert *parent)
    1235             : {
    1236             :     AuthorityKeyIdentifier ai;
    1237             :     hx509_query q;
    1238             :     int ret;
    1239             : 
    1240           0 :     *parent = NULL;
    1241           0 :     memset(&ai, 0, sizeof(ai));
    1242             : 
    1243           0 :     _hx509_query_clear(&q);
    1244             : 
    1245           0 :     if (!subject_null_p(current->data)) {
    1246           0 :         q.match |= HX509_QUERY_FIND_ISSUER_CERT;
    1247           0 :         q.subject = _hx509_get_cert(current);
    1248             :     } else {
    1249           0 :         ret = find_extension_auth_key_id(current->data, &ai);
    1250           0 :         if (ret) {
    1251           0 :             hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
    1252             :                                    "Subjectless certificate missing AuthKeyID");
    1253           0 :             return HX509_CERTIFICATE_MALFORMED;
    1254             :         }
    1255             : 
    1256           0 :         if (ai.keyIdentifier == NULL) {
    1257           0 :             free_AuthorityKeyIdentifier(&ai);
    1258           0 :             hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
    1259             :                                    "Subjectless certificate missing keyIdentifier "
    1260             :                                    "inside AuthKeyID");
    1261           0 :             return HX509_CERTIFICATE_MALFORMED;
    1262             :         }
    1263             : 
    1264           0 :         q.subject_id = ai.keyIdentifier;
    1265           0 :         q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
    1266             :     }
    1267             : 
    1268           0 :     q.path = path;
    1269           0 :     q.match |= HX509_QUERY_NO_MATCH_PATH;
    1270             : 
    1271           0 :     if (pool) {
    1272           0 :         q.timenow = time_now;
    1273           0 :         q.match |= HX509_QUERY_MATCH_TIME;
    1274             : 
    1275           0 :         ret = hx509_certs_find(context, pool, &q, parent);
    1276           0 :         if (ret == 0) {
    1277           0 :             free_AuthorityKeyIdentifier(&ai);
    1278           0 :             return 0;
    1279             :         }
    1280           0 :         q.match &= ~HX509_QUERY_MATCH_TIME;
    1281             :     }
    1282             : 
    1283           0 :     if (trust_anchors) {
    1284           0 :         ret = hx509_certs_find(context, trust_anchors, &q, parent);
    1285           0 :         if (ret == 0) {
    1286           0 :             free_AuthorityKeyIdentifier(&ai);
    1287           0 :             return ret;
    1288             :         }
    1289             :     }
    1290           0 :     free_AuthorityKeyIdentifier(&ai);
    1291             : 
    1292             :     {
    1293             :         hx509_name name;
    1294             :         char *str;
    1295             : 
    1296           0 :         ret = hx509_cert_get_subject(current, &name);
    1297           0 :         if (ret) {
    1298           0 :             hx509_clear_error_string(context);
    1299           0 :             return HX509_ISSUER_NOT_FOUND;
    1300             :         }
    1301           0 :         ret = hx509_name_to_string(name, &str);
    1302           0 :         hx509_name_free(&name);
    1303           0 :         if (ret) {
    1304           0 :             hx509_clear_error_string(context);
    1305           0 :             return HX509_ISSUER_NOT_FOUND;
    1306             :         }
    1307             : 
    1308           0 :         hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
    1309             :                                "Failed to find issuer for "
    1310             :                                "certificate with subject: '%s'", str);
    1311           0 :         free(str);
    1312             :     }
    1313           0 :     return HX509_ISSUER_NOT_FOUND;
    1314             : }
    1315             : 
    1316             : /*
    1317             :  *
    1318             :  */
    1319             : 
    1320             : static int
    1321           0 : is_proxy_cert(hx509_context context,
    1322             :               const Certificate *cert,
    1323             :               ProxyCertInfo *rinfo)
    1324             : {
    1325             :     ProxyCertInfo info;
    1326             :     const Extension *e;
    1327             :     size_t size;
    1328             :     int ret;
    1329           0 :     size_t i = 0;
    1330             : 
    1331           0 :     if (rinfo)
    1332           0 :         memset(rinfo, 0, sizeof(*rinfo));
    1333             : 
    1334           0 :     e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
    1335           0 :     if (e == NULL) {
    1336           0 :         hx509_clear_error_string(context);
    1337           0 :         return HX509_EXTENSION_NOT_FOUND;
    1338             :     }
    1339             : 
    1340           0 :     ret = decode_ProxyCertInfo(e->extnValue.data,
    1341             :                                e->extnValue.length,
    1342             :                                &info,
    1343             :                                &size);
    1344           0 :     if (ret) {
    1345           0 :         hx509_clear_error_string(context);
    1346           0 :         return ret;
    1347             :     }
    1348           0 :     if (size != e->extnValue.length) {
    1349           0 :         free_ProxyCertInfo(&info);
    1350           0 :         hx509_clear_error_string(context);
    1351           0 :         return HX509_EXTRA_DATA_AFTER_STRUCTURE;
    1352             :     }
    1353           0 :     if (rinfo == NULL)
    1354           0 :         free_ProxyCertInfo(&info);
    1355             :     else
    1356           0 :         *rinfo = info;
    1357             : 
    1358           0 :     return 0;
    1359             : }
    1360             : 
    1361             : /*
    1362             :  * Path operations are like MEMORY based keyset, but with exposed
    1363             :  * internal so we can do easy searches.
    1364             :  */
    1365             : 
    1366             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1367           0 : _hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
    1368             : {
    1369             :     hx509_cert *val;
    1370           0 :     val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
    1371           0 :     if (val == NULL) {
    1372           0 :         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
    1373           0 :         return ENOMEM;
    1374             :     }
    1375             : 
    1376           0 :     path->val = val;
    1377           0 :     path->val[path->len] = hx509_cert_ref(cert);
    1378           0 :     path->len++;
    1379             : 
    1380           0 :     return 0;
    1381             : }
    1382             : 
    1383             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    1384           0 : _hx509_path_free(hx509_path *path)
    1385             : {
    1386             :     unsigned i;
    1387             : 
    1388           0 :     for (i = 0; i < path->len; i++)
    1389           0 :         hx509_cert_free(path->val[i]);
    1390           0 :     free(path->val);
    1391           0 :     path->val = NULL;
    1392           0 :     path->len = 0;
    1393           0 : }
    1394             : 
    1395             : /*
    1396             :  * Find path by looking up issuer for the top certificate and continue
    1397             :  * until an anchor certificate is found or max limit is found. A
    1398             :  * certificate never included twice in the path.
    1399             :  *
    1400             :  * If the trust anchors are not given, calculate optimistic path, just
    1401             :  * follow the chain upward until we no longer find a parent or we hit
    1402             :  * the max path limit. In this case, a failure will always be returned
    1403             :  * depending on what error condition is hit first.
    1404             :  *
    1405             :  * The path includes a path from the top certificate to the anchor
    1406             :  * certificate.
    1407             :  *
    1408             :  * The caller needs to free `path´ both on successful built path and
    1409             :  * failure.
    1410             :  */
    1411             : 
    1412             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1413           0 : _hx509_calculate_path(hx509_context context,
    1414             :                       int flags,
    1415             :                       time_t time_now,
    1416             :                       hx509_certs anchors,
    1417             :                       unsigned int max_depth,
    1418             :                       hx509_cert cert,
    1419             :                       hx509_certs pool,
    1420             :                       hx509_path *path)
    1421             : {
    1422             :     hx509_cert parent, current;
    1423             :     int ret;
    1424             : 
    1425           0 :     if (max_depth == 0)
    1426           0 :         max_depth = HX509_VERIFY_MAX_DEPTH;
    1427             : 
    1428           0 :     ret = _hx509_path_append(context, path, cert);
    1429           0 :     if (ret)
    1430           0 :         return ret;
    1431             : 
    1432           0 :     current = hx509_cert_ref(cert);
    1433             : 
    1434           0 :     while (!certificate_is_anchor(context, anchors, current)) {
    1435             : 
    1436           0 :         ret = find_parent(context, time_now, anchors, path,
    1437             :                           pool, current, &parent);
    1438           0 :         hx509_cert_free(current);
    1439           0 :         if (ret)
    1440           0 :             return ret;
    1441             : 
    1442           0 :         ret = _hx509_path_append(context, path, parent);
    1443           0 :         if (ret)
    1444           0 :             return ret;
    1445           0 :         current = parent;
    1446             : 
    1447           0 :         if (path->len > max_depth) {
    1448           0 :             hx509_cert_free(current);
    1449           0 :             hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
    1450             :                                    "Path too long while bulding "
    1451             :                                    "certificate chain");
    1452           0 :             return HX509_PATH_TOO_LONG;
    1453             :         }
    1454             :     }
    1455             : 
    1456           0 :     if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
    1457           0 :         path->len > 0 &&
    1458           0 :         certificate_is_anchor(context, anchors, path->val[path->len - 1]))
    1459             :     {
    1460           0 :         hx509_cert_free(path->val[path->len - 1]);
    1461           0 :         path->len--;
    1462             :     }
    1463             : 
    1464           0 :     hx509_cert_free(current);
    1465           0 :     return 0;
    1466             : }
    1467             : 
    1468             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1469           0 : _hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
    1470             :                                const AlgorithmIdentifier *q)
    1471             : {
    1472             :     int diff;
    1473           0 :     diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
    1474           0 :     if (diff)
    1475           0 :         return diff;
    1476           0 :     if (p->parameters) {
    1477           0 :         if (q->parameters)
    1478           0 :             return heim_any_cmp(p->parameters,
    1479           0 :                                 q->parameters);
    1480             :         else
    1481           0 :             return 1;
    1482             :     } else {
    1483           0 :         if (q->parameters)
    1484           0 :             return -1;
    1485             :         else
    1486           0 :             return 0;
    1487             :     }
    1488             : }
    1489             : 
    1490             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1491           0 : _hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
    1492             : {
    1493             :     int diff;
    1494           0 :     diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
    1495           0 :     if (diff)
    1496           0 :         return diff;
    1497           0 :     diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
    1498             :                                           &q->signatureAlgorithm);
    1499           0 :     if (diff)
    1500           0 :         return diff;
    1501           0 :     diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
    1502             :                                      &q->tbsCertificate._save);
    1503           0 :     return diff;
    1504             : }
    1505             : 
    1506             : /**
    1507             :  * Compare to hx509 certificate object, useful for sorting.
    1508             :  *
    1509             :  * @param p a hx509 certificate object.
    1510             :  * @param q a hx509 certificate object.
    1511             :  *
    1512             :  * @return 0 the objects are the same, returns > 0 is p is "larger"
    1513             :  * then q, < 0 if p is "smaller" then q.
    1514             :  *
    1515             :  * @ingroup hx509_cert
    1516             :  */
    1517             : 
    1518             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1519           0 : hx509_cert_cmp(hx509_cert p, hx509_cert q)
    1520             : {
    1521           0 :     return _hx509_Certificate_cmp(p->data, q->data);
    1522             : }
    1523             : 
    1524             : /**
    1525             :  * Return the name of the issuer of the hx509 certificate.
    1526             :  *
    1527             :  * @param p a hx509 certificate object.
    1528             :  * @param name a pointer to a hx509 name, should be freed by
    1529             :  * hx509_name_free().
    1530             :  *
    1531             :  * @return An hx509 error code, see hx509_get_error_string().
    1532             :  *
    1533             :  * @ingroup hx509_cert
    1534             :  */
    1535             : 
    1536             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1537          75 : hx509_cert_get_issuer(hx509_cert p, hx509_name *name)
    1538             : {
    1539          75 :     return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
    1540             : }
    1541             : 
    1542             : /**
    1543             :  * Return the name of the subject of the hx509 certificate.
    1544             :  *
    1545             :  * @param p a hx509 certificate object.
    1546             :  * @param name a pointer to a hx509 name, should be freed by
    1547             :  * hx509_name_free(). See also hx509_cert_get_base_subject().
    1548             :  *
    1549             :  * @return An hx509 error code, see hx509_get_error_string().
    1550             :  *
    1551             :  * @ingroup hx509_cert
    1552             :  */
    1553             : 
    1554             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1555          75 : hx509_cert_get_subject(hx509_cert p, hx509_name *name)
    1556             : {
    1557          75 :     return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
    1558             : }
    1559             : 
    1560             : /**
    1561             :  * Return the name of the base subject of the hx509 certificate. If
    1562             :  * the certiicate is a verified proxy certificate, the this function
    1563             :  * return the base certificate (root of the proxy chain). If the proxy
    1564             :  * certificate is not verified with the base certificate
    1565             :  * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
    1566             :  *
    1567             :  * @param context a hx509 context.
    1568             :  * @param c a hx509 certificate object.
    1569             :  * @param name a pointer to a hx509 name, should be freed by
    1570             :  * hx509_name_free(). See also hx509_cert_get_subject().
    1571             :  *
    1572             :  * @return An hx509 error code, see hx509_get_error_string().
    1573             :  *
    1574             :  * @ingroup hx509_cert
    1575             :  */
    1576             : 
    1577             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1578           0 : hx509_cert_get_base_subject(hx509_context context, hx509_cert c,
    1579             :                             hx509_name *name)
    1580             : {
    1581           0 :     if (c->basename)
    1582           0 :         return hx509_name_copy(context, c->basename, name);
    1583           0 :     if (is_proxy_cert(context, c->data, NULL) == 0) {
    1584           0 :         int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
    1585           0 :         hx509_set_error_string(context, 0, ret,
    1586             :                                "Proxy certificate has not been "
    1587             :                                "canonicalized yet: no base name");
    1588           0 :         return ret;
    1589             :     }
    1590           0 :     return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
    1591             : }
    1592             : 
    1593             : /**
    1594             :  * Get serial number of the certificate.
    1595             :  *
    1596             :  * @param p a hx509 certificate object.
    1597             :  * @param i serial number, should be freed ith der_free_heim_integer().
    1598             :  *
    1599             :  * @return An hx509 error code, see hx509_get_error_string().
    1600             :  *
    1601             :  * @ingroup hx509_cert
    1602             :  */
    1603             : 
    1604             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1605          75 : hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
    1606             : {
    1607          75 :     return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
    1608             : }
    1609             : 
    1610             : /**
    1611             :  * Get notBefore time of the certificate.
    1612             :  *
    1613             :  * @param p a hx509 certificate object.
    1614             :  *
    1615             :  * @return return not before time
    1616             :  *
    1617             :  * @ingroup hx509_cert
    1618             :  */
    1619             : 
    1620             : HX509_LIB_FUNCTION time_t HX509_LIB_CALL
    1621           0 : hx509_cert_get_notBefore(hx509_cert p)
    1622             : {
    1623           0 :     return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
    1624             : }
    1625             : 
    1626             : /**
    1627             :  * Get notAfter time of the certificate.
    1628             :  *
    1629             :  * @param p a hx509 certificate object.
    1630             :  *
    1631             :  * @return return not after time.
    1632             :  *
    1633             :  * @ingroup hx509_cert
    1634             :  */
    1635             : 
    1636             : HX509_LIB_FUNCTION time_t HX509_LIB_CALL
    1637           0 : hx509_cert_get_notAfter(hx509_cert p)
    1638             : {
    1639           0 :     return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
    1640             : }
    1641             : 
    1642             : /**
    1643             :  * Get a maximum Kerberos credential lifetime from a Heimdal certificate
    1644             :  * extension.
    1645             :  *
    1646             :  * @param context hx509 context.
    1647             :  * @param cert Certificate.
    1648             :  * @param bound If larger than zero, return no more than this.
    1649             :  *
    1650             :  * @return maximum ticket lifetime.
    1651             :  */
    1652             : HX509_LIB_FUNCTION time_t HX509_LIB_CALL
    1653           0 : hx509_cert_get_pkinit_max_life(hx509_context context,
    1654             :                                hx509_cert cert,
    1655             :                                time_t bound)
    1656             : {
    1657           0 :     HeimPkinitPrincMaxLifeSecs r = 0;
    1658             :     size_t sz, i;
    1659             :     time_t b, e;
    1660             :     int ret;
    1661             : 
    1662           0 :     for (i = 0; i < cert->data->tbsCertificate.extensions->len; i++) {
    1663           0 :         Extension *ext = &cert->data->tbsCertificate.extensions->val[i];
    1664             : 
    1665           0 :         if (ext->_ioschoice_extnValue.element !=
    1666           0 :             choice_Extension_iosnumunknown &&
    1667           0 :             ext->_ioschoice_extnValue.element !=
    1668             :             choice_Extension_iosnum_id_heim_ce_pkinit_princ_max_life)
    1669           0 :             continue;
    1670           0 :         if (ext->_ioschoice_extnValue.element == choice_Extension_iosnumunknown &&
    1671           0 :             der_heim_oid_cmp(&asn1_oid_id_heim_ce_pkinit_princ_max_life, &ext->extnID))
    1672           0 :             continue;
    1673           0 :         if (ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife) {
    1674           0 :             r = *ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife;
    1675             :         } else {
    1676           0 :             ret = decode_HeimPkinitPrincMaxLifeSecs(ext->extnValue.data,
    1677             :                                                     ext->extnValue.length,
    1678             :                                                     &r, &sz);
    1679             :             /* No need to free_HeimPkinitPrincMaxLifeSecs(); it's an int */
    1680           0 :             if (ret || r < 1)
    1681           0 :                 return 0;
    1682             :         }
    1683           0 :         if (bound > 0 && r > bound)
    1684           0 :             return bound;
    1685           0 :         return r;
    1686             :     }
    1687           0 :     if (hx509_cert_check_eku(context, cert,
    1688             :                              &asn1_oid_id_heim_eku_pkinit_certlife_is_max_life, 0))
    1689           0 :         return 0;
    1690           0 :     b = hx509_cert_get_notBefore(cert);
    1691           0 :     e = hx509_cert_get_notAfter(cert);
    1692           0 :     if (e > b)
    1693           0 :         r = e - b;
    1694           0 :     if (bound > 0 && r > bound)
    1695           0 :         return bound;
    1696           0 :     return r;
    1697             : }
    1698             : 
    1699             : /**
    1700             :  * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
    1701             :  *
    1702             :  * @param context a hx509 context.
    1703             :  * @param p a hx509 certificate object.
    1704             :  * @param spki SubjectPublicKeyInfo, should be freed with
    1705             :  * free_SubjectPublicKeyInfo().
    1706             :  *
    1707             :  * @return An hx509 error code, see hx509_get_error_string().
    1708             :  *
    1709             :  * @ingroup hx509_cert
    1710             :  */
    1711             : 
    1712             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1713           0 : hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
    1714             : {
    1715             :     int ret;
    1716             : 
    1717           0 :     ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
    1718           0 :     if (ret)
    1719           0 :         hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
    1720           0 :     return ret;
    1721             : }
    1722             : 
    1723             : /**
    1724             :  * Get the AlgorithmIdentifier from the hx509 certificate.
    1725             :  *
    1726             :  * @param context a hx509 context.
    1727             :  * @param p a hx509 certificate object.
    1728             :  * @param alg AlgorithmIdentifier, should be freed with
    1729             :  *            free_AlgorithmIdentifier(). The algorithmidentifier is
    1730             :  *            typicly rsaEncryption, or id-ecPublicKey, or some other
    1731             :  *            public key mechanism.
    1732             :  *
    1733             :  * @return An hx509 error code, see hx509_get_error_string().
    1734             :  *
    1735             :  * @ingroup hx509_cert
    1736             :  */
    1737             : 
    1738             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1739           0 : hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
    1740             :                                         hx509_cert p,
    1741             :                                         AlgorithmIdentifier *alg)
    1742             : {
    1743             :     int ret;
    1744             : 
    1745           0 :     ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
    1746           0 :     if (ret)
    1747           0 :         hx509_set_error_string(context, 0, ret,
    1748             :                                "Failed to copy SPKI AlgorithmIdentifier");
    1749           0 :     return ret;
    1750             : }
    1751             : 
    1752             : static int
    1753           0 : get_x_unique_id(hx509_context context, const char *name,
    1754             :                 const heim_bit_string *cert, heim_bit_string *subject)
    1755             : {
    1756             :     int ret;
    1757             : 
    1758           0 :     if (cert == NULL) {
    1759           0 :         ret = HX509_EXTENSION_NOT_FOUND;
    1760           0 :         hx509_set_error_string(context, 0, ret, "%s unique id doesn't exist", name);
    1761           0 :         return ret;
    1762             :     }
    1763           0 :     ret = der_copy_bit_string(cert, subject);
    1764           0 :     if (ret) {
    1765           0 :         hx509_set_error_string(context, 0, ret, "malloc out of memory", name);
    1766           0 :         return ret;
    1767             :     }
    1768           0 :     return 0;
    1769             : }
    1770             : 
    1771             : /**
    1772             :  * Get a copy of the Issuer Unique ID
    1773             :  *
    1774             :  * @param context a hx509_context
    1775             :  * @param p a hx509 certificate
    1776             :  * @param issuer the issuer id returned, free with der_free_bit_string()
    1777             :  *
    1778             :  * @return An hx509 error code, see hx509_get_error_string(). The
    1779             :  * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
    1780             :  * doesn't have a issuerUniqueID
    1781             :  *
    1782             :  * @ingroup hx509_cert
    1783             :  */
    1784             : 
    1785             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1786           0 : hx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer)
    1787             : {
    1788           0 :     return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer);
    1789             : }
    1790             : 
    1791             : /**
    1792             :  * Get a copy of the Subect Unique ID
    1793             :  *
    1794             :  * @param context a hx509_context
    1795             :  * @param p a hx509 certificate
    1796             :  * @param subject the subject id returned, free with der_free_bit_string()
    1797             :  *
    1798             :  * @return An hx509 error code, see hx509_get_error_string(). The
    1799             :  * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
    1800             :  * doesn't have a subjectUniqueID
    1801             :  *
    1802             :  * @ingroup hx509_cert
    1803             :  */
    1804             : 
    1805             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1806           0 : hx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject)
    1807             : {
    1808           0 :     return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject);
    1809             : }
    1810             : 
    1811             : 
    1812             : HX509_LIB_FUNCTION hx509_private_key HX509_LIB_CALL
    1813          76 : _hx509_cert_private_key(hx509_cert p)
    1814             : {
    1815          76 :     return p->private_key;
    1816             : }
    1817             : 
    1818             : /**
    1819             :  * Indicate whether a hx509_cert has a private key.
    1820             :  *
    1821             :  * @param p a hx509 certificate
    1822             :  *
    1823             :  * @return 1 if p has a private key, 0 otherwise.
    1824             :  *
    1825             :  * @ingroup hx509_cert
    1826             :  */
    1827             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1828           0 : hx509_cert_have_private_key(hx509_cert p)
    1829             : {
    1830           0 :     return p->private_key ? 1 : 0;
    1831             : }
    1832             : 
    1833             : /**
    1834             :  * Indicate whether a hx509_cert has a private key only (no certificate).
    1835             :  *
    1836             :  * @param p a hx509 certificate
    1837             :  *
    1838             :  * @return 1 if p has a private key only (no certificate), 0 otherwise.
    1839             :  *
    1840             :  * @ingroup hx509_cert
    1841             :  */
    1842             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1843           0 : hx509_cert_have_private_key_only(hx509_cert p)
    1844             : {
    1845           0 :     return p->private_key && !p->data ? 1 : 0;
    1846             : }
    1847             : 
    1848             : 
    1849             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1850           0 : _hx509_cert_private_key_exportable(hx509_cert p)
    1851             : {
    1852           0 :     if (p->private_key == NULL)
    1853           0 :         return 0;
    1854           0 :     return _hx509_private_key_exportable(p->private_key);
    1855             : }
    1856             : 
    1857             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1858           0 : _hx509_cert_private_decrypt(hx509_context context,
    1859             :                             const heim_octet_string *ciphertext,
    1860             :                             const heim_oid *encryption_oid,
    1861             :                             hx509_cert p,
    1862             :                             heim_octet_string *cleartext)
    1863             : {
    1864           0 :     cleartext->data = NULL;
    1865           0 :     cleartext->length = 0;
    1866             : 
    1867           0 :     if (p->private_key == NULL) {
    1868           0 :         hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
    1869             :                                "Private key missing");
    1870           0 :         return HX509_PRIVATE_KEY_MISSING;
    1871             :     }
    1872             : 
    1873           0 :     return hx509_private_key_private_decrypt(context,
    1874             :                                               ciphertext,
    1875             :                                               encryption_oid,
    1876             :                                               p->private_key,
    1877             :                                               cleartext);
    1878             : }
    1879             : 
    1880             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    1881           0 : hx509_cert_public_encrypt(hx509_context context,
    1882             :                            const heim_octet_string *cleartext,
    1883             :                            const hx509_cert p,
    1884             :                            heim_oid *encryption_oid,
    1885             :                            heim_octet_string *ciphertext)
    1886             : {
    1887           0 :     return _hx509_public_encrypt(context,
    1888           0 :                                  cleartext, p->data,
    1889             :                                  encryption_oid, ciphertext);
    1890             : }
    1891             : 
    1892             : /*
    1893             :  *
    1894             :  */
    1895             : 
    1896             : HX509_LIB_FUNCTION time_t HX509_LIB_CALL
    1897           0 : _hx509_Time2time_t(const Time *t)
    1898             : {
    1899           0 :     switch(t->element) {
    1900           0 :     case choice_Time_utcTime:
    1901           0 :         return t->u.utcTime;
    1902           0 :     case choice_Time_generalTime:
    1903           0 :         return t->u.generalTime;
    1904             :     }
    1905           0 :     return 0;
    1906             : }
    1907             : 
    1908             : /*
    1909             :  *
    1910             :  */
    1911             : 
    1912             : static int
    1913           0 : init_name_constraints(hx509_name_constraints *nc)
    1914             : {
    1915           0 :     memset(nc, 0, sizeof(*nc));
    1916           0 :     return 0;
    1917             : }
    1918             : 
    1919             : static int
    1920           0 : add_name_constraints(hx509_context context, const Certificate *c, int not_ca,
    1921             :                      hx509_name_constraints *nc)
    1922             : {
    1923             :     NameConstraints tnc;
    1924             :     int ret;
    1925             : 
    1926           0 :     ret = find_extension_name_constraints(c, &tnc);
    1927           0 :     if (ret == HX509_EXTENSION_NOT_FOUND)
    1928           0 :         return 0;
    1929           0 :     else if (ret) {
    1930           0 :         hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
    1931           0 :         return ret;
    1932           0 :     } else if (not_ca) {
    1933           0 :         ret = HX509_VERIFY_CONSTRAINTS;
    1934           0 :         hx509_set_error_string(context, 0, ret, "Not a CA and "
    1935             :                                "have NameConstraints");
    1936             :     } else {
    1937             :         NameConstraints *val;
    1938           0 :         val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
    1939           0 :         if (val == NULL) {
    1940           0 :             hx509_clear_error_string(context);
    1941           0 :             ret = ENOMEM;
    1942           0 :             goto out;
    1943             :         }
    1944           0 :         nc->val = val;
    1945           0 :         ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
    1946           0 :         if (ret) {
    1947           0 :             hx509_clear_error_string(context);
    1948           0 :             goto out;
    1949             :         }
    1950           0 :         nc->len += 1;
    1951             :     }
    1952           0 : out:
    1953           0 :     free_NameConstraints(&tnc);
    1954           0 :     return ret;
    1955             : }
    1956             : 
    1957             : static int
    1958           0 : match_RDN(const RelativeDistinguishedName *c,
    1959             :           const RelativeDistinguishedName *n)
    1960             : {
    1961             :     size_t i;
    1962             : 
    1963           0 :     if (c->len != n->len)
    1964           0 :         return HX509_NAME_CONSTRAINT_ERROR;
    1965             : 
    1966           0 :     for (i = 0; i < n->len; i++) {
    1967             :         int diff, ret;
    1968             : 
    1969           0 :         if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
    1970           0 :             return HX509_NAME_CONSTRAINT_ERROR;
    1971           0 :         ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
    1972           0 :         if (ret)
    1973           0 :             return ret;
    1974           0 :         if (diff != 0)
    1975           0 :             return HX509_NAME_CONSTRAINT_ERROR;
    1976             :     }
    1977           0 :     return 0;
    1978             : }
    1979             : 
    1980             : static int
    1981           0 : match_X501Name(const Name *c, const Name *n)
    1982             : {
    1983             :     size_t i;
    1984             :     int ret;
    1985             : 
    1986           0 :     if (c->element != choice_Name_rdnSequence
    1987           0 :         || n->element != choice_Name_rdnSequence)
    1988           0 :         return 0;
    1989           0 :     if (c->u.rdnSequence.len > n->u.rdnSequence.len)
    1990           0 :         return HX509_NAME_CONSTRAINT_ERROR;
    1991           0 :     for (i = 0; i < c->u.rdnSequence.len; i++) {
    1992           0 :         ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
    1993           0 :         if (ret)
    1994           0 :             return ret;
    1995             :     }
    1996           0 :     return 0;
    1997             : }
    1998             : 
    1999             : 
    2000             : static int
    2001           0 : match_general_name(const GeneralName *c, const GeneralName *n, int *match)
    2002             : {
    2003             :     /*
    2004             :      * Name constraints only apply to the same name type, see RFC3280,
    2005             :      * 4.2.1.11.
    2006             :      */
    2007           0 :     assert(c->element == n->element);
    2008             : 
    2009           0 :     switch(c->element) {
    2010           0 :     case choice_GeneralName_otherName:
    2011           0 :         if (der_heim_oid_cmp(&c->u.otherName.type_id,
    2012             :                          &n->u.otherName.type_id) != 0)
    2013           0 :             return HX509_NAME_CONSTRAINT_ERROR;
    2014           0 :         if (heim_any_cmp(&c->u.otherName.value,
    2015           0 :                          &n->u.otherName.value) != 0)
    2016           0 :             return HX509_NAME_CONSTRAINT_ERROR;
    2017           0 :         *match = 1;
    2018           0 :         return 0;
    2019           0 :     case choice_GeneralName_rfc822Name: {
    2020             :         const char *s;
    2021             :         size_t len1, len2;
    2022           0 :         s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length);
    2023           0 :         if (s) {
    2024           0 :             if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0)
    2025           0 :                 return HX509_NAME_CONSTRAINT_ERROR;
    2026             :         } else {
    2027           0 :             s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length);
    2028           0 :             if (s == NULL)
    2029           0 :                 return HX509_NAME_CONSTRAINT_ERROR;
    2030           0 :             len1 = c->u.rfc822Name.length;
    2031           0 :             len2 = n->u.rfc822Name.length -
    2032           0 :                 (s - ((char *)n->u.rfc822Name.data));
    2033           0 :             if (len1 > len2)
    2034           0 :                 return HX509_NAME_CONSTRAINT_ERROR;
    2035           0 :             if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0)
    2036           0 :                 return HX509_NAME_CONSTRAINT_ERROR;
    2037           0 :             if (len1 < len2 && s[len2 - len1 + 1] != '.')
    2038           0 :                 return HX509_NAME_CONSTRAINT_ERROR;
    2039             :         }
    2040           0 :         *match = 1;
    2041           0 :         return 0;
    2042             :     }
    2043           0 :     case choice_GeneralName_dNSName: {
    2044             :         size_t lenc, lenn;
    2045             :         char *ptr;
    2046             : 
    2047           0 :         lenc = c->u.dNSName.length;
    2048           0 :         lenn = n->u.dNSName.length;
    2049           0 :         if (lenc > lenn)
    2050           0 :             return HX509_NAME_CONSTRAINT_ERROR;
    2051           0 :         ptr = n->u.dNSName.data;
    2052           0 :         if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0)
    2053           0 :             return HX509_NAME_CONSTRAINT_ERROR;
    2054           0 :         if (lenn != lenc && ptr[lenn - lenc - 1] != '.')
    2055           0 :             return HX509_NAME_CONSTRAINT_ERROR;
    2056           0 :         *match = 1;
    2057           0 :         return 0;
    2058             :     }
    2059           0 :     case choice_GeneralName_directoryName: {
    2060             :         Name c_name, n_name;
    2061             :         int ret;
    2062             : 
    2063           0 :         c_name._save.data = NULL;
    2064           0 :         c_name._save.length = 0;
    2065           0 :         c_name.element = (enum Name_enum)c->u.directoryName.element;
    2066           0 :         c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
    2067             : 
    2068           0 :         n_name._save.data = NULL;
    2069           0 :         n_name._save.length = 0;
    2070           0 :         n_name.element = (enum Name_enum)n->u.directoryName.element;
    2071           0 :         n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
    2072             : 
    2073           0 :         ret = match_X501Name(&c_name, &n_name);
    2074           0 :         if (ret == 0)
    2075           0 :             *match = 1;
    2076           0 :         return ret;
    2077             :     }
    2078           0 :     case choice_GeneralName_uniformResourceIdentifier:
    2079             :     case choice_GeneralName_iPAddress:
    2080             :     case choice_GeneralName_registeredID:
    2081             :     default:
    2082           0 :         return HX509_NAME_CONSTRAINT_ERROR;
    2083             :     }
    2084             : }
    2085             : 
    2086             : static int
    2087           0 : match_alt_name(const GeneralName *n, const Certificate *c,
    2088             :                int *same, int *match)
    2089             : {
    2090             :     GeneralNames sa;
    2091           0 :     int ret = 0;
    2092             :     size_t i, j;
    2093             : 
    2094           0 :     i = 0;
    2095             :     do {
    2096           0 :         ret = find_extension_subject_alt_name(c, &i, &sa);
    2097           0 :         if (ret == HX509_EXTENSION_NOT_FOUND) {
    2098           0 :             ret = 0;
    2099           0 :             break;
    2100           0 :         } else if (ret != 0)
    2101           0 :             break;
    2102             : 
    2103           0 :         for (j = 0; j < sa.len; j++) {
    2104           0 :             if (n->element == sa.val[j].element) {
    2105           0 :                 *same = 1;
    2106           0 :                 match_general_name(n, &sa.val[j], match);
    2107             :             }
    2108             :         }
    2109           0 :         free_GeneralNames(&sa);
    2110             :     } while (1);
    2111           0 :     return ret;
    2112             : }
    2113             : 
    2114             : 
    2115             : static int
    2116           0 : match_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
    2117             : {
    2118             :     int name, alt_name, same;
    2119             :     unsigned int i;
    2120           0 :     int ret = 0;
    2121             : 
    2122           0 :     name = alt_name = same = *match = 0;
    2123           0 :     for (i = 0; i < t->len; i++) {
    2124           0 :         if (t->val[i].minimum && t->val[i].maximum)
    2125           0 :             return HX509_RANGE;
    2126             : 
    2127             :         /*
    2128             :          * If the constraint apply to directoryNames, test is with
    2129             :          * subjectName of the certificate if the certificate have a
    2130             :          * non-null (empty) subjectName.
    2131             :          */
    2132             : 
    2133           0 :         if (t->val[i].base.element == choice_GeneralName_directoryName
    2134           0 :             && !subject_null_p(c))
    2135             :         {
    2136             :             GeneralName certname;
    2137             : 
    2138           0 :             memset(&certname, 0, sizeof(certname));
    2139           0 :             certname.element = choice_GeneralName_directoryName;
    2140           0 :             certname.u.directoryName.element = (enum Name_enum)
    2141           0 :                 c->tbsCertificate.subject.element;
    2142           0 :             certname.u.directoryName.u.rdnSequence =
    2143             :                 c->tbsCertificate.subject.u.rdnSequence;
    2144             : 
    2145           0 :             match_general_name(&t->val[i].base, &certname, &name);
    2146             :         }
    2147             : 
    2148             :         /* Handle subjectAltNames, this is icky since they
    2149             :          * restrictions only apply if the subjectAltName is of the
    2150             :          * same type. So if there have been a match of type, require
    2151             :          * altname to be set.
    2152             :          */
    2153           0 :         match_alt_name(&t->val[i].base, c, &same, &alt_name);
    2154             :     }
    2155           0 :     if (name && (!same || alt_name))
    2156           0 :         *match = 1;
    2157           0 :     return ret;
    2158             : }
    2159             : 
    2160             : static int
    2161           0 : check_name_constraints(hx509_context context,
    2162             :                        const hx509_name_constraints *nc,
    2163             :                        const Certificate *c)
    2164             : {
    2165             :     int match, ret;
    2166             :     size_t i;
    2167             : 
    2168           0 :     for (i = 0 ; i < nc->len; i++) {
    2169             :         GeneralSubtrees gs;
    2170             : 
    2171           0 :         if (nc->val[i].permittedSubtrees) {
    2172           0 :             GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
    2173           0 :             ret = match_tree(&gs, c, &match);
    2174           0 :             if (ret) {
    2175           0 :                 hx509_clear_error_string(context);
    2176           0 :                 return ret;
    2177             :             }
    2178             :             /* allow null subjectNames, they wont matches anything */
    2179           0 :             if (match == 0 && !subject_null_p(c)) {
    2180           0 :                 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
    2181             :                                        "Error verifying constraints: "
    2182             :                                        "certificate didn't match any "
    2183             :                                        "permitted subtree");
    2184           0 :                 return HX509_VERIFY_CONSTRAINTS;
    2185             :             }
    2186             :         }
    2187           0 :         if (nc->val[i].excludedSubtrees) {
    2188           0 :             GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
    2189           0 :             ret = match_tree(&gs, c, &match);
    2190           0 :             if (ret) {
    2191           0 :                 hx509_clear_error_string(context);
    2192           0 :                 return ret;
    2193             :             }
    2194           0 :             if (match) {
    2195           0 :                 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
    2196             :                                        "Error verifying constraints: "
    2197             :                                        "certificate included in excluded "
    2198             :                                        "subtree");
    2199           0 :                 return HX509_VERIFY_CONSTRAINTS;
    2200             :             }
    2201             :         }
    2202             :     }
    2203           0 :     return 0;
    2204             : }
    2205             : 
    2206             : static void
    2207           0 : free_name_constraints(hx509_name_constraints *nc)
    2208             : {
    2209             :     size_t i;
    2210             : 
    2211           0 :     for (i = 0 ; i < nc->len; i++)
    2212           0 :         free_NameConstraints(&nc->val[i]);
    2213           0 :     free(nc->val);
    2214           0 : }
    2215             : 
    2216             : /**
    2217             :  * Build and verify the path for the certificate to the trust anchor
    2218             :  * specified in the verify context. The path is constructed from the
    2219             :  * certificate, the pool and the trust anchors.
    2220             :  *
    2221             :  * @param context A hx509 context.
    2222             :  * @param ctx A hx509 verification context.
    2223             :  * @param cert the certificate to build the path from.
    2224             :  * @param pool A keyset of certificates to build the chain from.
    2225             :  *
    2226             :  * @return An hx509 error code, see hx509_get_error_string().
    2227             :  *
    2228             :  * @ingroup hx509_verify
    2229             :  */
    2230             : 
    2231             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    2232           0 : hx509_verify_path(hx509_context context,
    2233             :                   hx509_verify_ctx ctx,
    2234             :                   hx509_cert cert,
    2235             :                   hx509_certs pool)
    2236             : {
    2237             :     hx509_name_constraints nc;
    2238             :     hx509_path path;
    2239             :     int ret, proxy_cert_depth, selfsigned_depth, diff;
    2240             :     size_t i, k;
    2241             :     enum certtype type;
    2242             :     Name proxy_issuer;
    2243           0 :     hx509_certs anchors = NULL;
    2244             : 
    2245           0 :     memset(&proxy_issuer, 0, sizeof(proxy_issuer));
    2246             : 
    2247           0 :     if ((ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) == 0 &&
    2248           0 :         is_proxy_cert(context, cert->data, NULL) == 0)
    2249             :     {
    2250           0 :         ret = HX509_PROXY_CERT_INVALID;
    2251           0 :         hx509_set_error_string(context, 0, ret,
    2252             :                                "Proxy certificate is not allowed as an EE "
    2253             :                                "certificate if proxy certificate is disabled");
    2254           0 :         return ret;
    2255             :     }
    2256             : 
    2257           0 :     ret = init_name_constraints(&nc);
    2258           0 :     if (ret)
    2259           0 :         return ret;
    2260             : 
    2261           0 :     path.val = NULL;
    2262           0 :     path.len = 0;
    2263             : 
    2264           0 :     if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
    2265           0 :         ctx->time_now = time(NULL);
    2266             : 
    2267             :     /*
    2268             :      *
    2269             :      */
    2270           0 :     if (ctx->trust_anchors)
    2271           0 :         anchors = hx509_certs_ref(ctx->trust_anchors);
    2272           0 :     else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
    2273           0 :         anchors = hx509_certs_ref(context->default_trust_anchors);
    2274             :     else {
    2275           0 :         ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
    2276           0 :         if (ret)
    2277           0 :             goto out;
    2278             :     }
    2279             : 
    2280             :     /*
    2281             :      * Calculate the path from the certificate user presented to the
    2282             :      * to an anchor.
    2283             :      */
    2284           0 :     ret = _hx509_calculate_path(context, 0, ctx->time_now,
    2285             :                                 anchors, ctx->max_depth,
    2286             :                                 cert, pool, &path);
    2287           0 :     if (ret)
    2288           0 :         goto out;
    2289             : 
    2290             :     /*
    2291             :      * Check CA and proxy certificate chain from the top of the
    2292             :      * certificate chain. Also check certificate is valid with respect
    2293             :      * to the current time.
    2294             :      *
    2295             :      */
    2296             : 
    2297           0 :     proxy_cert_depth = 0;
    2298           0 :     selfsigned_depth = 0;
    2299             : 
    2300           0 :     if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
    2301           0 :         type = PROXY_CERT;
    2302             :     else
    2303           0 :         type = EE_CERT;
    2304             : 
    2305           0 :     for (i = 0; i < path.len; i++) {
    2306             :         Certificate *c;
    2307             :         time_t t;
    2308             : 
    2309           0 :         c = _hx509_get_cert(path.val[i]);
    2310             : 
    2311             :         /*
    2312             :          * Lets do some basic check on issuer like
    2313             :          * keyUsage.keyCertSign and basicConstraints.cA bit depending
    2314             :          * on what type of certificate this is.
    2315             :          */
    2316             : 
    2317           0 :         switch (type) {
    2318           0 :         case CA_CERT:
    2319             : 
    2320             :             /* XXX make constants for keyusage */
    2321           0 :             ret = check_key_usage(context, c, 1 << 5,
    2322           0 :                                   REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
    2323           0 :             if (ret) {
    2324           0 :                 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
    2325             :                                        "Key usage missing from CA certificate");
    2326           0 :                 goto out;
    2327             :             }
    2328             : 
    2329             :             /* self signed cert doesn't add to path length */
    2330           0 :             if (i + 1 != path.len) {
    2331             :                 int selfsigned;
    2332             : 
    2333           0 :                 ret = certificate_is_self_signed(context, c, &selfsigned);
    2334           0 :                 if (ret)
    2335           0 :                     goto out;
    2336           0 :                 if (selfsigned)
    2337           0 :                     selfsigned_depth++;
    2338             :             }
    2339             : 
    2340           0 :             break;
    2341           0 :         case PROXY_CERT: {
    2342             :             ProxyCertInfo info;
    2343             : 
    2344           0 :             if (is_proxy_cert(context, c, &info) == 0) {
    2345             :                 size_t j;
    2346             : 
    2347           0 :                 if (info.pCPathLenConstraint != NULL &&
    2348           0 :                     *info.pCPathLenConstraint < i)
    2349             :                 {
    2350           0 :                     free_ProxyCertInfo(&info);
    2351           0 :                     ret = HX509_PATH_TOO_LONG;
    2352           0 :                     hx509_set_error_string(context, 0, ret,
    2353             :                                            "Proxy certificate chain "
    2354             :                                            "longer than allowed");
    2355           0 :                     goto out;
    2356             :                 }
    2357             :                 /* XXX MUST check info.proxyPolicy */
    2358           0 :                 free_ProxyCertInfo(&info);
    2359             : 
    2360           0 :                 j = 0;
    2361           0 :                 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
    2362           0 :                     ret = HX509_PROXY_CERT_INVALID;
    2363           0 :                     hx509_set_error_string(context, 0, ret,
    2364             :                                            "Proxy certificate has explicitly "
    2365             :                                            "forbidden subjectAltName");
    2366           0 :                     goto out;
    2367             :                 }
    2368             : 
    2369           0 :                 j = 0;
    2370           0 :                 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
    2371           0 :                     ret = HX509_PROXY_CERT_INVALID;
    2372           0 :                     hx509_set_error_string(context, 0, ret,
    2373             :                                            "Proxy certificate has explicitly "
    2374             :                                            "forbidden issuerAltName");
    2375           0 :                     goto out;
    2376             :                 }
    2377             : 
    2378             :                 /*
    2379             :                  * The subject name of the proxy certificate should be
    2380             :                  * CN=XXX,<proxy issuer>, prune of CN and check if its
    2381             :                  * the same over the whole chain of proxy certs and
    2382             :                  * then check with the EE cert when we get to it.
    2383             :                  */
    2384             : 
    2385           0 :                 if (proxy_cert_depth) {
    2386           0 :                     ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
    2387           0 :                     if (ret) {
    2388           0 :                         hx509_set_error_string(context, 0, ret, "Out of memory");
    2389           0 :                         goto out;
    2390             :                     }
    2391           0 :                     if (diff) {
    2392           0 :                         ret = HX509_PROXY_CERT_NAME_WRONG;
    2393           0 :                         hx509_set_error_string(context, 0, ret,
    2394             :                                                "Base proxy name not right");
    2395           0 :                         goto out;
    2396             :                     }
    2397             :                 }
    2398             : 
    2399           0 :                 free_Name(&proxy_issuer);
    2400             : 
    2401           0 :                 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
    2402           0 :                 if (ret) {
    2403           0 :                     hx509_clear_error_string(context);
    2404           0 :                     goto out;
    2405             :                 }
    2406             : 
    2407           0 :                 j = proxy_issuer.u.rdnSequence.len;
    2408           0 :                 if (proxy_issuer.u.rdnSequence.len < 2
    2409           0 :                     || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
    2410           0 :                     || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
    2411             :                                         &asn1_oid_id_at_commonName))
    2412             :                 {
    2413           0 :                     ret = HX509_PROXY_CERT_NAME_WRONG;
    2414           0 :                     hx509_set_error_string(context, 0, ret,
    2415             :                                            "Proxy name too short or "
    2416             :                                            "does not have Common name "
    2417             :                                            "at the top");
    2418           0 :                     goto out;
    2419             :                 }
    2420             : 
    2421           0 :                 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
    2422           0 :                 proxy_issuer.u.rdnSequence.len -= 1;
    2423             : 
    2424           0 :                 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
    2425           0 :                 if (ret) {
    2426           0 :                     hx509_set_error_string(context, 0, ret, "Out of memory");
    2427           0 :                     goto out;
    2428             :                 }
    2429           0 :                 if (diff != 0) {
    2430           0 :                     ret = HX509_PROXY_CERT_NAME_WRONG;
    2431           0 :                     hx509_set_error_string(context, 0, ret,
    2432             :                                            "Proxy issuer name not as expected");
    2433           0 :                     goto out;
    2434             :                 }
    2435             : 
    2436           0 :                 break;
    2437             :             } else {
    2438             :                 /*
    2439             :                  * Now we are done with the proxy certificates, this
    2440             :                  * cert was an EE cert and we we will fall though to
    2441             :                  * EE checking below.
    2442             :                  */
    2443           0 :                 type = EE_CERT;
    2444             :             }
    2445             :         }
    2446             :         fallthrough;
    2447             :         case EE_CERT:
    2448             :             /*
    2449             :              * If there where any proxy certificates in the chain
    2450             :              * (proxy_cert_depth > 0), check that the proxy issuer
    2451             :              * matched proxy certificates "base" subject.
    2452             :              */
    2453           0 :             if (proxy_cert_depth) {
    2454             : 
    2455           0 :                 ret = _hx509_name_cmp(&proxy_issuer,
    2456           0 :                                       &c->tbsCertificate.subject, &diff);
    2457           0 :                 if (ret) {
    2458           0 :                     hx509_set_error_string(context, 0, ret, "out of memory");
    2459           0 :                     goto out;
    2460             :                 }
    2461           0 :                 if (diff) {
    2462           0 :                     ret = HX509_PROXY_CERT_NAME_WRONG;
    2463           0 :                     hx509_clear_error_string(context);
    2464           0 :                     goto out;
    2465             :                 }
    2466           0 :                 if (cert->basename)
    2467           0 :                     hx509_name_free(&cert->basename);
    2468             : 
    2469           0 :                 ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
    2470           0 :                 if (ret) {
    2471           0 :                     hx509_clear_error_string(context);
    2472           0 :                     goto out;
    2473             :                 }
    2474             :             }
    2475             : 
    2476           0 :             break;
    2477             :         }
    2478             : 
    2479           0 :         ret = check_basic_constraints(context, c, type,
    2480           0 :                                       i - proxy_cert_depth - selfsigned_depth);
    2481           0 :         if (ret)
    2482           0 :             goto out;
    2483             : 
    2484             :         /*
    2485             :          * Don't check the trust anchors expiration time since they
    2486             :          * are transported out of band, from RFC3820.
    2487             :          */
    2488           0 :         if (i + 1 != path.len || CHECK_TA(ctx)) {
    2489             : 
    2490           0 :             t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
    2491           0 :             if (t > ctx->time_now) {
    2492           0 :                 ret = HX509_CERT_USED_BEFORE_TIME;
    2493           0 :                 hx509_clear_error_string(context);
    2494           0 :                 goto out;
    2495             :             }
    2496           0 :             t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
    2497           0 :             if (t < ctx->time_now) {
    2498           0 :                 ret = HX509_CERT_USED_AFTER_TIME;
    2499           0 :                 hx509_clear_error_string(context);
    2500           0 :                 goto out;
    2501             :             }
    2502             :         }
    2503             : 
    2504           0 :         if (type == EE_CERT)
    2505           0 :             type = CA_CERT;
    2506           0 :         else if (type == PROXY_CERT)
    2507           0 :             proxy_cert_depth++;
    2508             :     }
    2509             : 
    2510             :     /*
    2511             :      * Verify constraints, do this backward so path constraints are
    2512             :      * checked in the right order.
    2513             :      */
    2514             : 
    2515           0 :     for (ret = 0, k = path.len; k > 0; k--) {
    2516             :         Certificate *c;
    2517             :         int selfsigned;
    2518           0 :         i = k - 1;
    2519             : 
    2520           0 :         c = _hx509_get_cert(path.val[i]);
    2521             : 
    2522           0 :         ret = certificate_is_self_signed(context, c, &selfsigned);
    2523           0 :         if (ret)
    2524           0 :             goto out;
    2525             : 
    2526             :         /* verify name constraints, not for selfsigned and anchor */
    2527           0 :         if (!selfsigned || i + 1 != path.len) {
    2528           0 :             ret = check_name_constraints(context, &nc, c);
    2529           0 :             if (ret) {
    2530           0 :                 goto out;
    2531             :             }
    2532             :         }
    2533           0 :         ret = add_name_constraints(context, c, i == 0, &nc);
    2534           0 :         if (ret)
    2535           0 :             goto out;
    2536             : 
    2537             :         /* XXX verify all other silly constraints */
    2538             : 
    2539             :     }
    2540             : 
    2541             :     /*
    2542             :      * Verify that no certificates has been revoked.
    2543             :      */
    2544             : 
    2545           0 :     if (ctx->revoke_ctx) {
    2546             :         hx509_certs certs;
    2547             : 
    2548           0 :         ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
    2549             :                                NULL, &certs);
    2550           0 :         if (ret)
    2551           0 :             goto out;
    2552             : 
    2553           0 :         for (i = 0; i < path.len; i++) {
    2554           0 :             ret = hx509_certs_add(context, certs, path.val[i]);
    2555           0 :             if (ret) {
    2556           0 :                 hx509_certs_free(&certs);
    2557           0 :                 goto out;
    2558             :             }
    2559             :         }
    2560           0 :         ret = hx509_certs_merge(context, certs, pool);
    2561           0 :         if (ret) {
    2562           0 :             hx509_certs_free(&certs);
    2563           0 :             goto out;
    2564             :         }
    2565             : 
    2566           0 :         for (i = 0; i < path.len - 1; i++) {
    2567           0 :             size_t parent = (i < path.len - 1) ? i + 1 : i;
    2568             : 
    2569           0 :             ret = hx509_revoke_verify(context,
    2570             :                                       ctx->revoke_ctx,
    2571             :                                       certs,
    2572             :                                       ctx->time_now,
    2573           0 :                                       path.val[i],
    2574           0 :                                       path.val[parent]);
    2575           0 :             if (ret) {
    2576           0 :                 hx509_certs_free(&certs);
    2577           0 :                 goto out;
    2578             :             }
    2579             :         }
    2580           0 :         hx509_certs_free(&certs);
    2581             :     }
    2582             : 
    2583             :     /*
    2584             :      * Verify signatures, do this backward so public key working
    2585             :      * parameter is passed up from the anchor up though the chain.
    2586             :      */
    2587             : 
    2588           0 :     for (k = path.len; k > 0; k--) {
    2589             :         hx509_cert signer;
    2590             :         Certificate *c;
    2591           0 :         i = k - 1;
    2592             : 
    2593           0 :         c = _hx509_get_cert(path.val[i]);
    2594             : 
    2595             :         /* is last in chain (trust anchor) */
    2596           0 :         if (i + 1 == path.len) {
    2597             :             int selfsigned;
    2598             : 
    2599           0 :             signer = path.val[i];
    2600             : 
    2601           0 :             ret = certificate_is_self_signed(context, signer->data, &selfsigned);
    2602           0 :             if (ret)
    2603           0 :                 goto out;
    2604             : 
    2605             :             /* if trust anchor is not self signed, don't check sig */
    2606           0 :             if (!selfsigned)
    2607           0 :                 continue;
    2608             :         } else {
    2609             :             /* take next certificate in chain */
    2610           0 :             signer = path.val[i + 1];
    2611             :         }
    2612             : 
    2613             :         /* verify signatureValue */
    2614           0 :         ret = _hx509_verify_signature_bitstring(context,
    2615             :                                                 signer,
    2616           0 :                                                 &c->signatureAlgorithm,
    2617           0 :                                                 &c->tbsCertificate._save,
    2618           0 :                                                 &c->signatureValue);
    2619           0 :         if (ret) {
    2620           0 :             hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
    2621             :                                    "Failed to verify signature of certificate");
    2622           0 :             goto out;
    2623             :         }
    2624             :         /*
    2625             :          * Verify that the sigature algorithm is not weak. Ignore
    2626             :          * trust anchors since they are provisioned by the user.
    2627             :          */
    2628             : 
    2629           0 :         if (i + 1 != path.len && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
    2630           0 :             ret = _hx509_signature_is_weak(context, &c->signatureAlgorithm);
    2631           0 :             if (ret)
    2632           0 :                 goto out;
    2633             :         }
    2634             :     }
    2635             : 
    2636           0 : out:
    2637           0 :     hx509_certs_free(&anchors);
    2638           0 :     free_Name(&proxy_issuer);
    2639           0 :     free_name_constraints(&nc);
    2640           0 :     _hx509_path_free(&path);
    2641             : 
    2642           0 :     return ret;
    2643             : }
    2644             : 
    2645             : /**
    2646             :  * Verify a signature made using the private key of an certificate.
    2647             :  *
    2648             :  * @param context A hx509 context.
    2649             :  * @param signer the certificate that made the signature.
    2650             :  * @param alg algorthm that was used to sign the data.
    2651             :  * @param data the data that was signed.
    2652             :  * @param sig the sigature to verify.
    2653             :  *
    2654             :  * @return An hx509 error code, see hx509_get_error_string().
    2655             :  *
    2656             :  * @ingroup hx509_crypto
    2657             :  */
    2658             : 
    2659             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    2660           0 : hx509_verify_signature(hx509_context context,
    2661             :                        const hx509_cert signer,
    2662             :                        const AlgorithmIdentifier *alg,
    2663             :                        const heim_octet_string *data,
    2664             :                        const heim_octet_string *sig)
    2665             : {
    2666           0 :     return _hx509_verify_signature(context, signer, alg, data, sig);
    2667             : }
    2668             : 
    2669             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    2670           0 : _hx509_verify_signature_bitstring(hx509_context context,
    2671             :                                   const hx509_cert signer,
    2672             :                                   const AlgorithmIdentifier *alg,
    2673             :                                   const heim_octet_string *data,
    2674             :                                   const heim_bit_string *sig)
    2675             : {
    2676             :     heim_octet_string os;
    2677             : 
    2678           0 :     if (sig->length & 7) {
    2679           0 :         hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
    2680             :                                "signature not multiple of 8 bits");
    2681           0 :         return HX509_CRYPTO_SIG_INVALID_FORMAT;
    2682             :     }
    2683             : 
    2684           0 :     os.data = sig->data;
    2685           0 :     os.length = sig->length / 8;
    2686             : 
    2687           0 :     return _hx509_verify_signature(context, signer, alg, data, &os);
    2688             : }
    2689             : 
    2690             : 
    2691             : 
    2692             : /**
    2693             :  * Verify that the certificate is allowed to be used for the hostname
    2694             :  * and address.
    2695             :  *
    2696             :  * @param context A hx509 context.
    2697             :  * @param cert the certificate to match with
    2698             :  * @param flags Flags to modify the behavior:
    2699             :  * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
    2700             :  * @param type type of hostname:
    2701             :  * - HX509_HN_HOSTNAME for plain hostname.
    2702             :  * - HX509_HN_DNSSRV for DNS SRV names.
    2703             :  * @param hostname the hostname to check
    2704             :  * @param sa address of the host
    2705             :  * @param sa_size length of address
    2706             :  *
    2707             :  * @return An hx509 error code, see hx509_get_error_string().
    2708             :  *
    2709             :  * @ingroup hx509_cert
    2710             :  */
    2711             : 
    2712             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    2713           0 : hx509_verify_hostname(hx509_context context,
    2714             :                       const hx509_cert cert,
    2715             :                       int flags,
    2716             :                       hx509_hostname_type type,
    2717             :                       const char *hostname,
    2718             :                       const struct sockaddr *sa,
    2719             :                       /* XXX krb5_socklen_t */ int sa_size)
    2720             : {
    2721             :     GeneralNames san;
    2722             :     const Name *name;
    2723             :     int ret;
    2724             :     size_t i, j, k;
    2725             : 
    2726           0 :     if (sa && sa_size <= 0)
    2727           0 :         return EINVAL;
    2728             : 
    2729           0 :     memset(&san, 0, sizeof(san));
    2730             : 
    2731           0 :     i = 0;
    2732             :     do {
    2733           0 :         ret = find_extension_subject_alt_name(cert->data, &i, &san);
    2734           0 :         if (ret == HX509_EXTENSION_NOT_FOUND)
    2735           0 :             break;
    2736           0 :         else if (ret != 0)
    2737           0 :             return HX509_PARSING_NAME_FAILED;
    2738             : 
    2739           0 :         for (j = 0; j < san.len; j++) {
    2740           0 :             switch (san.val[j].element) {
    2741           0 :             case choice_GeneralName_dNSName: {
    2742             :                 heim_printable_string hn;
    2743           0 :                 hn.data = rk_UNCONST(hostname);
    2744           0 :                 hn.length = strlen(hostname);
    2745             : 
    2746           0 :                 if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) {
    2747           0 :                     free_GeneralNames(&san);
    2748           0 :                     return 0;
    2749             :                 }
    2750           0 :                 break;
    2751             :             }
    2752           0 :             default:
    2753           0 :                 break;
    2754             :             }
    2755             :         }
    2756           0 :         free_GeneralNames(&san);
    2757             :     } while (1);
    2758             : 
    2759           0 :     name = &cert->data->tbsCertificate.subject;
    2760             : 
    2761             :     /* Find first CN= in the name, and try to match the hostname on that */
    2762           0 :     for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) {
    2763           0 :         i = k - 1;
    2764           0 :         for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
    2765           0 :             AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
    2766             : 
    2767           0 :             if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
    2768           0 :                 DirectoryString *ds = &n->value;
    2769           0 :                 switch (ds->element) {
    2770           0 :                 case choice_DirectoryString_printableString: {
    2771             :                     heim_printable_string hn;
    2772           0 :                     hn.data = rk_UNCONST(hostname);
    2773           0 :                     hn.length = strlen(hostname);
    2774             : 
    2775           0 :                     if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0)
    2776           0 :                         return 0;
    2777           0 :                     break;
    2778             :                 }
    2779           0 :                 case choice_DirectoryString_ia5String: {
    2780             :                     heim_ia5_string hn;
    2781           0 :                     hn.data = rk_UNCONST(hostname);
    2782           0 :                     hn.length = strlen(hostname);
    2783             : 
    2784           0 :                     if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0)
    2785           0 :                         return 0;
    2786           0 :                     break;
    2787             :                 }
    2788           0 :                 case choice_DirectoryString_utf8String:
    2789           0 :                     if (strcasecmp(ds->u.utf8String, hostname) == 0)
    2790           0 :                         return 0;
    2791             :                 default:
    2792           0 :                     break;
    2793             :                 }
    2794           0 :                 ret = HX509_NAME_CONSTRAINT_ERROR;
    2795             :             }
    2796             :         }
    2797             :     }
    2798             : 
    2799           0 :     if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
    2800           0 :         ret = HX509_NAME_CONSTRAINT_ERROR;
    2801             : 
    2802           0 :     return ret;
    2803             : }
    2804             : 
    2805             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    2806           0 : _hx509_set_cert_attribute(hx509_context context,
    2807             :                           hx509_cert cert,
    2808             :                           const heim_oid *oid,
    2809             :                           const heim_octet_string *attr)
    2810             : {
    2811             :     hx509_cert_attribute a;
    2812             :     void *d;
    2813             :     int ret;
    2814             : 
    2815             :     /*
    2816             :      * TODO: Rewrite this (and hx509_cert_attribute, and _hx509_cert_attrs) to
    2817             :      * use the add_AttributeValues() util generated by asn1_compile.
    2818             :      */
    2819             : 
    2820           0 :     if (hx509_cert_get_attribute(cert, oid) != NULL)
    2821           0 :         return 0;
    2822             : 
    2823           0 :     d = realloc(cert->attrs.val,
    2824           0 :                 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
    2825           0 :     if (d == NULL) {
    2826           0 :         hx509_clear_error_string(context);
    2827           0 :         return ENOMEM;
    2828             :     }
    2829           0 :     cert->attrs.val = d;
    2830             : 
    2831           0 :     a = malloc(sizeof(*a));
    2832           0 :     if (a == NULL)
    2833           0 :         return ENOMEM;
    2834             : 
    2835           0 :     ret = der_copy_octet_string(attr, &a->data);
    2836           0 :     if (ret == 0)
    2837           0 :         ret = der_copy_oid(oid, &a->oid);
    2838           0 :     if (ret == 0) {
    2839           0 :         cert->attrs.val[cert->attrs.len] = a;
    2840           0 :         cert->attrs.len++;
    2841             :     } else {
    2842           0 :         der_free_octet_string(&a->data);
    2843           0 :         free(a);
    2844             :     }
    2845             : 
    2846           0 :     return ret;
    2847             : }
    2848             : 
    2849             : /**
    2850             :  * Get an external attribute for the certificate, examples are
    2851             :  * friendly name and id.
    2852             :  *
    2853             :  * @param cert hx509 certificate object to search
    2854             :  * @param oid an oid to search for.
    2855             :  *
    2856             :  * @return an hx509_cert_attribute, only valid as long as the
    2857             :  * certificate is referenced.
    2858             :  *
    2859             :  * @ingroup hx509_cert
    2860             :  */
    2861             : 
    2862             : HX509_LIB_FUNCTION hx509_cert_attribute HX509_LIB_CALL
    2863           0 : hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
    2864             : {
    2865             :     size_t i;
    2866           0 :     for (i = 0; i < cert->attrs.len; i++)
    2867           0 :         if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
    2868           0 :             return cert->attrs.val[i];
    2869           0 :     return NULL;
    2870             : }
    2871             : 
    2872             : /**
    2873             :  * Set the friendly name on the certificate.
    2874             :  *
    2875             :  * @param cert The certificate to set the friendly name on
    2876             :  * @param name Friendly name.
    2877             :  *
    2878             :  * @return An hx509 error code, see hx509_get_error_string().
    2879             :  *
    2880             :  * @ingroup hx509_cert
    2881             :  */
    2882             : 
    2883             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    2884           0 : hx509_cert_set_friendly_name(hx509_cert cert, const char *name)
    2885             : {
    2886           0 :     if (cert->friendlyname)
    2887           0 :         free(cert->friendlyname);
    2888           0 :     cert->friendlyname = strdup(name);
    2889           0 :     if (cert->friendlyname == NULL)
    2890           0 :         return ENOMEM;
    2891           0 :     return 0;
    2892             : }
    2893             : 
    2894             : /**
    2895             :  * Get friendly name of the certificate.
    2896             :  *
    2897             :  * @param cert cert to get the friendly name from.
    2898             :  *
    2899             :  * @return an friendly name or NULL if there is. The friendly name is
    2900             :  * only valid as long as the certificate is referenced.
    2901             :  *
    2902             :  * @ingroup hx509_cert
    2903             :  */
    2904             : 
    2905             : HX509_LIB_FUNCTION const char * HX509_LIB_CALL
    2906           0 : hx509_cert_get_friendly_name(hx509_cert cert)
    2907             : {
    2908             :     hx509_cert_attribute a;
    2909             :     PKCS9_friendlyName n;
    2910             :     size_t sz;
    2911             :     int ret;
    2912             :     size_t i;
    2913             : 
    2914           0 :     if (cert->friendlyname)
    2915           0 :         return cert->friendlyname;
    2916             : 
    2917           0 :     a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
    2918           0 :     if (a == NULL) {
    2919             :         hx509_name name;
    2920             : 
    2921           0 :         ret = hx509_cert_get_subject(cert, &name);
    2922           0 :         if (ret)
    2923           0 :             return NULL;
    2924           0 :         ret = hx509_name_to_string(name, &cert->friendlyname);
    2925           0 :         hx509_name_free(&name);
    2926           0 :         if (ret)
    2927           0 :             return NULL;
    2928           0 :         return cert->friendlyname;
    2929             :     }
    2930             : 
    2931           0 :     ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
    2932           0 :     if (ret)
    2933           0 :         return NULL;
    2934             : 
    2935           0 :     if (n.len != 1) {
    2936           0 :         free_PKCS9_friendlyName(&n);
    2937           0 :         return NULL;
    2938             :     }
    2939             : 
    2940           0 :     cert->friendlyname = malloc(n.val[0].length + 1);
    2941           0 :     if (cert->friendlyname == NULL) {
    2942           0 :         free_PKCS9_friendlyName(&n);
    2943           0 :         return NULL;
    2944             :     }
    2945             : 
    2946           0 :     for (i = 0; i < n.val[0].length; i++) {
    2947           0 :         if (n.val[0].data[i] <= 0xff)
    2948           0 :             cert->friendlyname[i] = n.val[0].data[i] & 0xff;
    2949             :         else
    2950           0 :             cert->friendlyname[i] = 'X';
    2951             :     }
    2952           0 :     cert->friendlyname[i] = '\0';
    2953           0 :     free_PKCS9_friendlyName(&n);
    2954             : 
    2955           0 :     return cert->friendlyname;
    2956             : }
    2957             : 
    2958             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    2959           0 : _hx509_query_clear(hx509_query *q)
    2960             : {
    2961           0 :     memset(q, 0, sizeof(*q));
    2962           0 : }
    2963             : 
    2964             : /**
    2965             :  * Allocate an query controller. Free using hx509_query_free().
    2966             :  *
    2967             :  * @param context A hx509 context.
    2968             :  * @param q return pointer to a hx509_query.
    2969             :  *
    2970             :  * @return An hx509 error code, see hx509_get_error_string().
    2971             :  *
    2972             :  * @ingroup hx509_cert
    2973             :  */
    2974             : 
    2975             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    2976          38 : hx509_query_alloc(hx509_context context, hx509_query **q)
    2977             : {
    2978          38 :     *q = calloc(1, sizeof(**q));
    2979          38 :     if (*q == NULL)
    2980           0 :         return ENOMEM;
    2981          38 :     return 0;
    2982             : }
    2983             : 
    2984             : 
    2985             : /**
    2986             :  * Set match options for the hx509 query controller.
    2987             :  *
    2988             :  * @param q query controller.
    2989             :  * @param option options to control the query controller.
    2990             :  *
    2991             :  * @return An hx509 error code, see hx509_get_error_string().
    2992             :  *
    2993             :  * @ingroup hx509_cert
    2994             :  */
    2995             : 
    2996             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    2997          38 : hx509_query_match_option(hx509_query *q, hx509_query_option option)
    2998             : {
    2999          38 :     switch(option) {
    3000          38 :     case HX509_QUERY_OPTION_PRIVATE_KEY:
    3001          38 :         q->match |= HX509_QUERY_PRIVATE_KEY;
    3002          38 :         break;
    3003           0 :     case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
    3004           0 :         q->match |= HX509_QUERY_KU_ENCIPHERMENT;
    3005           0 :         break;
    3006           0 :     case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
    3007           0 :         q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
    3008           0 :         break;
    3009           0 :     case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
    3010           0 :         q->match |= HX509_QUERY_KU_KEYCERTSIGN;
    3011           0 :         break;
    3012           0 :     case HX509_QUERY_OPTION_END:
    3013             :     default:
    3014           0 :         break;
    3015             :     }
    3016          38 : }
    3017             : 
    3018             : /**
    3019             :  * Set the issuer and serial number of match in the query
    3020             :  * controller. The function make copies of the isser and serial number.
    3021             :  *
    3022             :  * @param q a hx509 query controller
    3023             :  * @param issuer issuer to search for
    3024             :  * @param serialNumber the serialNumber of the issuer.
    3025             :  *
    3026             :  * @return An hx509 error code, see hx509_get_error_string().
    3027             :  *
    3028             :  * @ingroup hx509_cert
    3029             :  */
    3030             : 
    3031             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3032           0 : hx509_query_match_issuer_serial(hx509_query *q,
    3033             :                                 const Name *issuer,
    3034             :                                 const heim_integer *serialNumber)
    3035             : {
    3036             :     int ret;
    3037           0 :     if (q->serial) {
    3038           0 :         der_free_heim_integer(q->serial);
    3039           0 :         free(q->serial);
    3040             :     }
    3041           0 :     q->serial = malloc(sizeof(*q->serial));
    3042           0 :     if (q->serial == NULL)
    3043           0 :         return ENOMEM;
    3044           0 :     ret = der_copy_heim_integer(serialNumber, q->serial);
    3045           0 :     if (ret) {
    3046           0 :         free(q->serial);
    3047           0 :         q->serial = NULL;
    3048           0 :         return ret;
    3049             :     }
    3050           0 :     if (q->issuer_name) {
    3051           0 :         free_Name(q->issuer_name);
    3052           0 :         free(q->issuer_name);
    3053             :     }
    3054           0 :     q->issuer_name = malloc(sizeof(*q->issuer_name));
    3055           0 :     if (q->issuer_name == NULL)
    3056           0 :         return ENOMEM;
    3057           0 :     ret = copy_Name(issuer, q->issuer_name);
    3058           0 :     if (ret) {
    3059           0 :         free(q->issuer_name);
    3060           0 :         q->issuer_name = NULL;
    3061           0 :         return ret;
    3062             :     }
    3063           0 :     q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
    3064           0 :     return 0;
    3065             : }
    3066             : 
    3067             : /**
    3068             :  * Set the query controller to match on a friendly name
    3069             :  *
    3070             :  * @param q a hx509 query controller.
    3071             :  * @param name a friendly name to match on
    3072             :  *
    3073             :  * @return An hx509 error code, see hx509_get_error_string().
    3074             :  *
    3075             :  * @ingroup hx509_cert
    3076             :  */
    3077             : 
    3078             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3079           0 : hx509_query_match_friendly_name(hx509_query *q, const char *name)
    3080             : {
    3081           0 :     if (q->friendlyname)
    3082           0 :         free(q->friendlyname);
    3083           0 :     q->friendlyname = strdup(name);
    3084           0 :     if (q->friendlyname == NULL)
    3085           0 :         return ENOMEM;
    3086           0 :     q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
    3087           0 :     return 0;
    3088             : }
    3089             : 
    3090             : /**
    3091             :  * Set the query controller to require an one specific EKU (extended
    3092             :  * key usage). Any previous EKU matching is overwitten. If NULL is
    3093             :  * passed in as the eku, the EKU requirement is reset.
    3094             :  *
    3095             :  * @param q a hx509 query controller.
    3096             :  * @param eku an EKU to match on.
    3097             :  *
    3098             :  * @return An hx509 error code, see hx509_get_error_string().
    3099             :  *
    3100             :  * @ingroup hx509_cert
    3101             :  */
    3102             : 
    3103             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3104           0 : hx509_query_match_eku(hx509_query *q, const heim_oid *eku)
    3105             : {
    3106             :     int ret;
    3107             : 
    3108           0 :     if (eku == NULL) {
    3109           0 :         if (q->eku) {
    3110           0 :             der_free_oid(q->eku);
    3111           0 :             free(q->eku);
    3112           0 :             q->eku = NULL;
    3113             :         }
    3114           0 :         q->match &= ~HX509_QUERY_MATCH_EKU;
    3115             :     } else {
    3116           0 :         if (q->eku) {
    3117           0 :             der_free_oid(q->eku);
    3118             :         } else {
    3119           0 :             q->eku = calloc(1, sizeof(*q->eku));
    3120           0 :             if (q->eku == NULL)
    3121           0 :                 return ENOMEM;
    3122             :         }
    3123           0 :         ret = der_copy_oid(eku, q->eku);
    3124           0 :         if (ret) {
    3125           0 :             free(q->eku);
    3126           0 :             q->eku = NULL;
    3127           0 :             return ret;
    3128             :         }
    3129           0 :         q->match |= HX509_QUERY_MATCH_EKU;
    3130             :     }
    3131           0 :     return 0;
    3132             : }
    3133             : 
    3134             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3135           0 : hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
    3136             : {
    3137           0 :     if (q->expr) {
    3138           0 :         _hx509_expr_free(q->expr);
    3139           0 :         q->expr = NULL;
    3140             :     }
    3141             : 
    3142           0 :     if (expr == NULL) {
    3143           0 :         q->match &= ~HX509_QUERY_MATCH_EXPR;
    3144           0 :         return 0;
    3145             :     }
    3146             : 
    3147           0 :     q->expr = _hx509_expr_parse(expr);
    3148           0 :     if (q->expr == NULL) {
    3149           0 :         const char *reason = _hx509_expr_parse_error();
    3150             : 
    3151           0 :         hx509_set_error_string(context, 0, EINVAL,
    3152             :                                "Invalid certificate query match expression: "
    3153             :                                "%s (%s)", expr,
    3154             :                                reason ? reason : "syntax error");
    3155           0 :         return EINVAL;
    3156             :     }
    3157             : 
    3158           0 :     q->match |= HX509_QUERY_MATCH_EXPR;
    3159           0 :     return 0;
    3160             : }
    3161             : 
    3162             : /**
    3163             :  * Set the query controller to match using a specific match function.
    3164             :  *
    3165             :  * @param q a hx509 query controller.
    3166             :  * @param func function to use for matching, if the argument is NULL,
    3167             :  * the match function is removed.
    3168             :  * @param ctx context passed to the function.
    3169             :  *
    3170             :  * @return An hx509 error code, see hx509_get_error_string().
    3171             :  *
    3172             :  * @ingroup hx509_cert
    3173             :  */
    3174             : 
    3175             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3176           0 : hx509_query_match_cmp_func(hx509_query *q,
    3177             :                            int (*func)(hx509_context, hx509_cert, void *),
    3178             :                            void *ctx)
    3179             : {
    3180           0 :     if (func)
    3181           0 :         q->match |= HX509_QUERY_MATCH_FUNCTION;
    3182             :     else
    3183           0 :         q->match &= ~HX509_QUERY_MATCH_FUNCTION;
    3184           0 :     q->cmp_func = func;
    3185           0 :     q->cmp_func_ctx = ctx;
    3186           0 :     return 0;
    3187             : }
    3188             : 
    3189             : /**
    3190             :  * Free the query controller.
    3191             :  *
    3192             :  * @param context A hx509 context.
    3193             :  * @param q a pointer to the query controller.
    3194             :  *
    3195             :  * @ingroup hx509_cert
    3196             :  */
    3197             : 
    3198             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    3199          38 : hx509_query_free(hx509_context context, hx509_query *q)
    3200             : {
    3201          38 :     if (q == NULL)
    3202           0 :         return;
    3203             : 
    3204          38 :     if (q->serial) {
    3205           0 :         der_free_heim_integer(q->serial);
    3206           0 :         free(q->serial);
    3207             :     }
    3208          38 :     if (q->issuer_name) {
    3209           0 :         free_Name(q->issuer_name);
    3210           0 :         free(q->issuer_name);
    3211             :     }
    3212          38 :     if (q->eku) {
    3213           0 :         der_free_oid(q->eku);
    3214           0 :         free(q->eku);
    3215             :     }
    3216          38 :     if (q->friendlyname)
    3217           0 :         free(q->friendlyname);
    3218          38 :     if (q->expr)
    3219           0 :         _hx509_expr_free(q->expr);
    3220             : 
    3221          38 :     memset(q, 0, sizeof(*q));
    3222          38 :     free(q);
    3223             : }
    3224             : 
    3225             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3226          38 : _hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
    3227             : {
    3228          38 :     Certificate *c = _hx509_get_cert(cert);
    3229             :     int ret, diff;
    3230             : 
    3231          38 :     _hx509_query_statistic(context, 1, q);
    3232             : 
    3233          38 :     if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
    3234           0 :         _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
    3235           0 :         return 0;
    3236             : 
    3237          38 :     if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
    3238           0 :         _hx509_Certificate_cmp(q->certificate, c) != 0)
    3239           0 :         return 0;
    3240             : 
    3241          38 :     if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
    3242           0 :         && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
    3243           0 :         return 0;
    3244             : 
    3245          38 :     if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
    3246           0 :         ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
    3247           0 :         if (ret || diff)
    3248           0 :             return 0;
    3249             :     }
    3250             : 
    3251          38 :     if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
    3252           0 :         ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
    3253           0 :         if (ret || diff)
    3254           0 :             return 0;
    3255             :     }
    3256             : 
    3257          38 :     if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
    3258             :         SubjectKeyIdentifier si;
    3259             : 
    3260           0 :         ret = _hx509_find_extension_subject_key_id(c, &si);
    3261           0 :         if (ret == 0) {
    3262           0 :             if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
    3263           0 :                 ret = 1;
    3264           0 :             free_SubjectKeyIdentifier(&si);
    3265             :         }
    3266           0 :         if (ret)
    3267           0 :             return 0;
    3268             :     }
    3269          38 :     if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
    3270           0 :         return 0;
    3271          76 :     if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
    3272          38 :         _hx509_cert_private_key(cert) == NULL)
    3273           0 :         return 0;
    3274             : 
    3275             :     {
    3276          38 :         unsigned ku = 0;
    3277          38 :         if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
    3278           0 :             ku |= (1 << 0);
    3279          38 :         if (q->match & HX509_QUERY_KU_NONREPUDIATION)
    3280           0 :             ku |= (1 << 1);
    3281          38 :         if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
    3282           0 :             ku |= (1 << 2);
    3283          38 :         if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
    3284           0 :             ku |= (1 << 3);
    3285          38 :         if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
    3286           0 :             ku |= (1 << 4);
    3287          38 :         if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
    3288           0 :             ku |= (1 << 5);
    3289          38 :         if (q->match & HX509_QUERY_KU_CRLSIGN)
    3290           0 :             ku |= (1 << 6);
    3291          38 :         if (ku && check_key_usage(context, c, ku, TRUE))
    3292           0 :             return 0;
    3293             :     }
    3294          38 :     if ((q->match & HX509_QUERY_ANCHOR))
    3295           0 :         return 0;
    3296             : 
    3297          38 :     if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
    3298             :         hx509_cert_attribute a;
    3299             : 
    3300           0 :         a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
    3301           0 :         if (a == NULL)
    3302           0 :             return 0;
    3303           0 :         if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
    3304           0 :             return 0;
    3305             :     }
    3306             : 
    3307          38 :     if (q->match & HX509_QUERY_NO_MATCH_PATH) {
    3308             :         size_t i;
    3309             : 
    3310           0 :         for (i = 0; i < q->path->len; i++)
    3311           0 :             if (hx509_cert_cmp(q->path->val[i], cert) == 0)
    3312           0 :                 return 0;
    3313             :     }
    3314          38 :     if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
    3315           0 :         const char *name = hx509_cert_get_friendly_name(cert);
    3316           0 :         if (name == NULL)
    3317           0 :             return 0;
    3318           0 :         if (strcasecmp(q->friendlyname, name) != 0)
    3319           0 :             return 0;
    3320             :     }
    3321          38 :     if (q->match & HX509_QUERY_MATCH_FUNCTION) {
    3322           0 :         ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
    3323           0 :         if (ret != 0)
    3324           0 :             return 0;
    3325             :     }
    3326             : 
    3327          38 :     if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
    3328             :         heim_octet_string os;
    3329             : 
    3330           0 :         os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
    3331           0 :         os.length =
    3332           0 :             c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
    3333             : 
    3334           0 :         ret = _hx509_verify_signature(context,
    3335             :                                       NULL,
    3336             :                                       hx509_signature_sha1(),
    3337             :                                       &os,
    3338           0 :                                       q->keyhash_sha1);
    3339           0 :         if (ret != 0)
    3340           0 :             return 0;
    3341             :     }
    3342             : 
    3343          38 :     if (q->match & HX509_QUERY_MATCH_TIME) {
    3344             :         time_t t;
    3345           0 :         t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
    3346           0 :         if (t > q->timenow)
    3347           0 :             return 0;
    3348           0 :         t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
    3349           0 :         if (t < q->timenow)
    3350           0 :             return 0;
    3351             :     }
    3352             : 
    3353             :     /* If an EKU is required, check the cert for it. */
    3354          38 :     if ((q->match & HX509_QUERY_MATCH_EKU) &&
    3355           0 :         hx509_cert_check_eku(context, cert, q->eku, 0))
    3356           0 :         return 0;
    3357             : 
    3358          38 :     if ((q->match & HX509_QUERY_MATCH_EXPR)) {
    3359           0 :         hx509_env env = NULL;
    3360             : 
    3361           0 :         ret = _hx509_cert_to_env(context, cert, &env);
    3362           0 :         if (ret)
    3363           0 :             return 0;
    3364             : 
    3365           0 :         ret = _hx509_expr_eval(context, env, q->expr);
    3366           0 :         hx509_env_free(&env);
    3367           0 :         if (ret == 0)
    3368           0 :             return 0;
    3369             :     }
    3370             : 
    3371          38 :     if (q->match & ~HX509_QUERY_MASK)
    3372           0 :         return 0;
    3373             : 
    3374          38 :     return 1;
    3375             : }
    3376             : 
    3377             : /**
    3378             :  * Set a statistic file for the query statistics.
    3379             :  *
    3380             :  * @param context A hx509 context.
    3381             :  * @param fn statistics file name
    3382             :  *
    3383             :  * @ingroup hx509_cert
    3384             :  */
    3385             : 
    3386             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    3387           0 : hx509_query_statistic_file(hx509_context context, const char *fn)
    3388             : {
    3389           0 :     if (context->querystat)
    3390           0 :         free(context->querystat);
    3391           0 :     context->querystat = strdup(fn);
    3392           0 : }
    3393             : 
    3394             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    3395          76 : _hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
    3396             : {
    3397             :     FILE *f;
    3398          76 :     if (context->querystat == NULL)
    3399          76 :         return;
    3400           0 :     f = fopen(context->querystat, "a");
    3401           0 :     if (f == NULL)
    3402           0 :         return;
    3403           0 :     rk_cloexec_file(f);
    3404           0 :     fprintf(f, "%d %d\n", type, q->match);
    3405           0 :     fclose(f);
    3406             : }
    3407             : 
    3408             : static const char *statname[] = {
    3409             :     "find issuer cert",
    3410             :     "match serialnumber",
    3411             :     "match issuer name",
    3412             :     "match subject name",
    3413             :     "match subject key id",
    3414             :     "match issuer id",
    3415             :     "private key",
    3416             :     "ku encipherment",
    3417             :     "ku digitalsignature",
    3418             :     "ku keycertsign",
    3419             :     "ku crlsign",
    3420             :     "ku nonrepudiation",
    3421             :     "ku keyagreement",
    3422             :     "ku dataencipherment",
    3423             :     "anchor",
    3424             :     "match certificate",
    3425             :     "match local key id",
    3426             :     "no match path",
    3427             :     "match friendly name",
    3428             :     "match function",
    3429             :     "match key hash sha1",
    3430             :     "match time"
    3431             : };
    3432             : 
    3433             : struct stat_el {
    3434             :     unsigned long stats;
    3435             :     unsigned int index;
    3436             : };
    3437             : 
    3438             : 
    3439             : static int
    3440           0 : stat_sort(const void *a, const void *b)
    3441             : {
    3442           0 :     const struct stat_el *ae = a;
    3443           0 :     const struct stat_el *be = b;
    3444           0 :     return be->stats - ae->stats;
    3445             : }
    3446             : 
    3447             : /**
    3448             :  * Unparse the statistics file and print the result on a FILE descriptor.
    3449             :  *
    3450             :  * @param context A hx509 context.
    3451             :  * @param printtype tyep to print
    3452             :  * @param out the FILE to write the data on.
    3453             :  *
    3454             :  * @ingroup hx509_cert
    3455             :  */
    3456             : 
    3457             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    3458           0 : hx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
    3459             : {
    3460             :     rtbl_t t;
    3461             :     FILE *f;
    3462             :     int type, mask, num;
    3463             :     size_t i;
    3464           0 :     unsigned long multiqueries = 0, totalqueries = 0;
    3465             :     struct stat_el stats[32];
    3466             : 
    3467           0 :     if (context->querystat == NULL)
    3468           0 :         return;
    3469           0 :     f = fopen(context->querystat, "r");
    3470           0 :     if (f == NULL) {
    3471           0 :         fprintf(out, "No statistics file %s: %s.\n",
    3472           0 :                 context->querystat, strerror(errno));
    3473           0 :         return;
    3474             :     }
    3475           0 :     rk_cloexec_file(f);
    3476             : 
    3477           0 :     for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
    3478           0 :         stats[i].index = i;
    3479           0 :         stats[i].stats = 0;
    3480             :     }
    3481             : 
    3482           0 :     while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
    3483           0 :         if (type != printtype)
    3484           0 :             continue;
    3485           0 :         num = i = 0;
    3486           0 :         while (mask && i < sizeof(stats)/sizeof(stats[0])) {
    3487           0 :             if (mask & 1) {
    3488           0 :                 stats[i].stats++;
    3489           0 :                 num++;
    3490             :             }
    3491           0 :             mask = mask >>1 ;
    3492           0 :             i++;
    3493             :         }
    3494           0 :         if (num > 1)
    3495           0 :             multiqueries++;
    3496           0 :         totalqueries++;
    3497             :     }
    3498           0 :     fclose(f);
    3499             : 
    3500           0 :     qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
    3501             : 
    3502           0 :     t = rtbl_create();
    3503           0 :     if (t == NULL)
    3504           0 :         errx(1, "out of memory");
    3505             : 
    3506           0 :     rtbl_set_separator (t, "  ");
    3507             : 
    3508           0 :     rtbl_add_column_by_id (t, 0, "Name", 0);
    3509           0 :     rtbl_add_column_by_id (t, 1, "Counter", 0);
    3510             : 
    3511             : 
    3512           0 :     for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
    3513             :         char str[10];
    3514             : 
    3515           0 :         if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
    3516           0 :             rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
    3517             :         else {
    3518           0 :             snprintf(str, sizeof(str), "%d", stats[i].index);
    3519           0 :             rtbl_add_column_entry_by_id (t, 0, str);
    3520             :         }
    3521           0 :         snprintf(str, sizeof(str), "%lu", stats[i].stats);
    3522           0 :         rtbl_add_column_entry_by_id (t, 1, str);
    3523             :     }
    3524             : 
    3525           0 :     rtbl_format(t, out);
    3526           0 :     rtbl_destroy(t);
    3527             : 
    3528           0 :     fprintf(out, "\nQueries: multi %lu total %lu\n",
    3529             :             multiqueries, totalqueries);
    3530             : }
    3531             : 
    3532             : /**
    3533             :  * Check the extended key usage on the hx509 certificate.
    3534             :  *
    3535             :  * @param context A hx509 context.
    3536             :  * @param cert A hx509 context.
    3537             :  * @param eku the EKU to check for
    3538             :  * @param allow_any_eku if the any EKU is set, allow that to be a
    3539             :  * substitute.
    3540             :  *
    3541             :  * @return An hx509 error code, see hx509_get_error_string().
    3542             :  *
    3543             :  * @ingroup hx509_cert
    3544             :  */
    3545             : 
    3546             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3547          38 : hx509_cert_check_eku(hx509_context context, hx509_cert cert,
    3548             :                      const heim_oid *eku, int allow_any_eku)
    3549             : {
    3550             :     ExtKeyUsage e;
    3551             :     int ret;
    3552             :     size_t i;
    3553             : 
    3554          38 :     ret = find_extension_eku(_hx509_get_cert(cert), &e);
    3555          38 :     if (ret) {
    3556           0 :         hx509_clear_error_string(context);
    3557           0 :         return ret;
    3558             :     }
    3559             : 
    3560         114 :     for (i = 0; i < e.len; i++) {
    3561         114 :         if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
    3562          38 :             free_ExtKeyUsage(&e);
    3563          38 :             return 0;
    3564             :         }
    3565          76 :         if (allow_any_eku) {
    3566           0 :             if (der_heim_oid_cmp(&asn1_oid_id_x509_ce_anyExtendedKeyUsage,
    3567           0 :                                  &e.val[i]) == 0) {
    3568           0 :                 free_ExtKeyUsage(&e);
    3569           0 :                 return 0;
    3570             :             }
    3571             :         }
    3572             :     }
    3573           0 :     free_ExtKeyUsage(&e);
    3574           0 :     hx509_clear_error_string(context);
    3575           0 :     return HX509_CERTIFICATE_MISSING_EKU;
    3576             : }
    3577             : 
    3578             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3579           0 : _hx509_cert_get_keyusage(hx509_context context,
    3580             :                          hx509_cert c,
    3581             :                          KeyUsage *ku)
    3582             : {
    3583             :     Certificate *cert;
    3584             :     const Extension *e;
    3585             :     size_t size;
    3586             :     int ret;
    3587           0 :     size_t i = 0;
    3588             : 
    3589           0 :     memset(ku, 0, sizeof(*ku));
    3590             : 
    3591           0 :     cert = _hx509_get_cert(c);
    3592             : 
    3593           0 :     if (_hx509_cert_get_version(cert) < 3)
    3594           0 :         return 0;
    3595             : 
    3596           0 :     e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
    3597           0 :     if (e == NULL)
    3598           0 :         return HX509_KU_CERT_MISSING;
    3599             : 
    3600           0 :     ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
    3601           0 :     if (ret)
    3602           0 :         return ret;
    3603           0 :     return 0;
    3604             : }
    3605             : 
    3606             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3607           0 : _hx509_cert_get_eku(hx509_context context,
    3608             :                     hx509_cert cert,
    3609             :                     ExtKeyUsage *e)
    3610             : {
    3611             :     int ret;
    3612             : 
    3613           0 :     memset(e, 0, sizeof(*e));
    3614             : 
    3615           0 :     ret = find_extension_eku(_hx509_get_cert(cert), e);
    3616           0 :     if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
    3617           0 :         hx509_clear_error_string(context);
    3618           0 :         return ret;
    3619             :     }
    3620           0 :     return 0;
    3621             : }
    3622             : 
    3623             : /**
    3624             :  * Encodes the hx509 certificate as a DER encode binary.
    3625             :  *
    3626             :  * @param context A hx509 context.
    3627             :  * @param c the certificate to encode.
    3628             :  * @param os the encode certificate, set to NULL, 0 on case of
    3629             :  * error. Free the os->data with hx509_xfree().
    3630             :  *
    3631             :  * @return An hx509 error code, see hx509_get_error_string().
    3632             :  *
    3633             :  * @ingroup hx509_cert
    3634             :  */
    3635             : 
    3636             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3637           0 : hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
    3638             : {
    3639             :     size_t size;
    3640             :     int ret;
    3641             : 
    3642           0 :     os->data = NULL;
    3643           0 :     os->length = 0;
    3644             : 
    3645           0 :     ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
    3646             :                        _hx509_get_cert(c), &size, ret);
    3647           0 :     if (ret) {
    3648           0 :         os->data = NULL;
    3649           0 :         os->length = 0;
    3650           0 :         return ret;
    3651             :     }
    3652           0 :     if (os->length != size)
    3653           0 :         _hx509_abort("internal ASN.1 encoder error");
    3654           0 :     return ret;
    3655             : }
    3656             : 
    3657             : /*
    3658             :  * Last to avoid lost __attribute__s due to #undef.
    3659             :  */
    3660             : 
    3661             : #undef __attribute__
    3662             : #define __attribute__(X)
    3663             : 
    3664             : HX509_LIB_NORETURN_FUNCTION void HX509_LIB_CALL
    3665           0 : _hx509_abort(const char *fmt, ...)
    3666             :      __attribute__ ((__noreturn__, __format__ (__printf__, 1, 2)))
    3667             : {
    3668             :     va_list ap;
    3669           0 :     va_start(ap, fmt);
    3670           0 :     vprintf(fmt, ap);
    3671           0 :     va_end(ap);
    3672           0 :     printf("\n");
    3673           0 :     fflush(stdout);
    3674           0 :     abort();
    3675             : }
    3676             : 
    3677             : /**
    3678             :  * Free a data element allocated in the library.
    3679             :  *
    3680             :  * @param ptr data to be freed.
    3681             :  *
    3682             :  * @ingroup hx509_misc
    3683             :  */
    3684             : 
    3685             : HX509_LIB_FUNCTION void HX509_LIB_CALL
    3686           0 : hx509_xfree(void *ptr)
    3687             : {
    3688           0 :     free(ptr);
    3689           0 : }
    3690             : 
    3691             : /**
    3692             :  *
    3693             :  */
    3694             : 
    3695             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3696           0 : _hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
    3697             : {
    3698             :     ExtKeyUsage eku;
    3699             :     hx509_name name;
    3700             :     char *buf;
    3701             :     int ret;
    3702           0 :     hx509_env envcert = NULL;
    3703             : 
    3704           0 :     *env = NULL;
    3705             : 
    3706             :     /* version */
    3707           0 :     ret = asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
    3708           0 :     if (ret == -1)
    3709           0 :         goto out;
    3710           0 :     ret = hx509_env_add(context, &envcert, "version", buf);
    3711           0 :     free(buf);
    3712           0 :     if (ret)
    3713           0 :         goto out;
    3714             : 
    3715             :     /* subject */
    3716           0 :     ret = hx509_cert_get_subject(cert, &name);
    3717           0 :     if (ret)
    3718           0 :         goto out;
    3719             : 
    3720           0 :     ret = hx509_name_to_string(name, &buf);
    3721           0 :     hx509_name_free(&name);
    3722           0 :     if (ret)
    3723           0 :         goto out;
    3724             : 
    3725           0 :     ret = hx509_env_add(context, &envcert, "subject", buf);
    3726           0 :     hx509_xfree(buf);
    3727           0 :     if (ret)
    3728           0 :         goto out;
    3729             : 
    3730             :     /* issuer */
    3731           0 :     ret = hx509_cert_get_issuer(cert, &name);
    3732           0 :     if (ret)
    3733           0 :         goto out;
    3734             : 
    3735           0 :     ret = hx509_name_to_string(name, &buf);
    3736           0 :     hx509_name_free(&name);
    3737           0 :     if (ret)
    3738           0 :         goto out;
    3739             : 
    3740           0 :     ret = hx509_env_add(context, &envcert, "issuer", buf);
    3741           0 :     hx509_xfree(buf);
    3742           0 :     if (ret)
    3743           0 :         goto out;
    3744             : 
    3745             :     /* eku */
    3746             : 
    3747           0 :     ret = _hx509_cert_get_eku(context, cert, &eku);
    3748           0 :     if (ret == HX509_EXTENSION_NOT_FOUND)
    3749             :         ;
    3750           0 :     else if (ret != 0)
    3751           0 :         goto out;
    3752             :     else {
    3753             :         size_t i;
    3754           0 :         hx509_env enveku = NULL;
    3755             : 
    3756           0 :         for (i = 0; i < eku.len; i++) {
    3757             : 
    3758           0 :             ret = der_print_heim_oid(&eku.val[i], '.', &buf);
    3759           0 :             if (ret) {
    3760           0 :                 free_ExtKeyUsage(&eku);
    3761           0 :                 hx509_env_free(&enveku);
    3762           0 :                 goto out;
    3763             :             }
    3764           0 :             ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
    3765           0 :             free(buf);
    3766           0 :             if (ret) {
    3767           0 :                 free_ExtKeyUsage(&eku);
    3768           0 :                 hx509_env_free(&enveku);
    3769           0 :                 goto out;
    3770             :             }
    3771             :         }
    3772           0 :         free_ExtKeyUsage(&eku);
    3773             : 
    3774           0 :         ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
    3775           0 :         if (ret) {
    3776           0 :             hx509_env_free(&enveku);
    3777           0 :             goto out;
    3778             :         }
    3779             :     }
    3780             : 
    3781             :     {
    3782           0 :         Certificate *c = _hx509_get_cert(cert);
    3783             :         heim_octet_string os, sig;
    3784           0 :         hx509_env envhash = NULL;
    3785             : 
    3786           0 :         os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
    3787           0 :         os.length =
    3788           0 :           c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
    3789             : 
    3790           0 :         ret = _hx509_create_signature(context,
    3791             :                                       NULL,
    3792             :                                       hx509_signature_sha1(),
    3793             :                                       &os,
    3794             :                                       NULL,
    3795             :                                       &sig);
    3796           0 :         if (ret != 0)
    3797           0 :             goto out;
    3798             : 
    3799           0 :         ret = hex_encode(sig.data, sig.length, &buf);
    3800           0 :         der_free_octet_string(&sig);
    3801           0 :         if (ret < 0) {
    3802           0 :             ret = ENOMEM;
    3803           0 :             hx509_set_error_string(context, 0, ret,
    3804             :                                    "Out of memory");
    3805           0 :             goto out;
    3806             :         }
    3807             : 
    3808           0 :         ret = hx509_env_add(context, &envhash, "sha1", buf);
    3809           0 :         free(buf);
    3810           0 :         if (ret)
    3811           0 :             goto out;
    3812             : 
    3813           0 :         ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
    3814           0 :         if (ret) {
    3815           0 :           hx509_env_free(&envhash);
    3816           0 :           goto out;
    3817             :         }
    3818             :     }
    3819             : 
    3820           0 :     ret = hx509_env_add_binding(context, env, "certificate", envcert);
    3821           0 :     if (ret)
    3822           0 :         goto out;
    3823             : 
    3824           0 :     return 0;
    3825             : 
    3826           0 : out:
    3827           0 :     hx509_env_free(&envcert);
    3828           0 :     return ret;
    3829             : }
    3830             : 
    3831             : /**
    3832             :  * Print a simple representation of a certificate
    3833             :  *
    3834             :  * @param context A hx509 context, can be NULL
    3835             :  * @param cert certificate to print
    3836             :  * @param out the stdio output stream, if NULL, stdout is used
    3837             :  *
    3838             :  * @return An hx509 error code
    3839             :  *
    3840             :  * @ingroup hx509_cert
    3841             :  */
    3842             : 
    3843             : HX509_LIB_FUNCTION int HX509_LIB_CALL
    3844           0 : hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
    3845             : {
    3846             :     hx509_name name;
    3847             :     char *str;
    3848             :     int ret;
    3849             : 
    3850           0 :     if (out == NULL)
    3851           0 :         out = stderr;
    3852             : 
    3853           0 :     ret = hx509_cert_get_issuer(cert, &name);
    3854           0 :     if (ret)
    3855           0 :         return ret;
    3856           0 :     hx509_name_to_string(name, &str);
    3857           0 :     hx509_name_free(&name);
    3858           0 :     fprintf(out, "    issuer:  \"%s\"\n", str);
    3859           0 :     free(str);
    3860             : 
    3861           0 :     ret = hx509_cert_get_subject(cert, &name);
    3862           0 :     if (ret)
    3863           0 :         return ret;
    3864           0 :     hx509_name_to_string(name, &str);
    3865           0 :     hx509_name_free(&name);
    3866           0 :     fprintf(out, "    subject: \"%s\"\n", str);
    3867           0 :     free(str);
    3868             : 
    3869             :     {
    3870             :         heim_integer serialNumber;
    3871             : 
    3872           0 :         ret = hx509_cert_get_serialnumber(cert, &serialNumber);
    3873           0 :         if (ret)
    3874           0 :             return ret;
    3875           0 :         ret = der_print_hex_heim_integer(&serialNumber, &str);
    3876           0 :         if (ret)
    3877           0 :             return ret;
    3878           0 :         der_free_heim_integer(&serialNumber);
    3879           0 :         fprintf(out, "    serial: %s\n", str);
    3880           0 :         free(str);
    3881             :     }
    3882             : 
    3883           0 :     fprintf(out, "    keyusage: ");
    3884           0 :     ret = hx509_cert_keyusage_print(context, cert, &str);
    3885           0 :     if (ret == 0) {
    3886           0 :         fprintf(out, "%s\n", str);
    3887           0 :         free(str);
    3888             :     } else
    3889           0 :         fprintf(out, "no");
    3890             : 
    3891           0 :     return 0;
    3892             : }

Generated by: LCOV version 1.13