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