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