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