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