1178825Sdfr/*
2178825Sdfr * Copyright (c) 2004 - 2007 Kungliga Tekniska H�gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825SdfrRCSID("$Id: cert.c 22450 2008-01-15 19:39:14Z lha $");
36178825Sdfr#include "crypto-headers.h"
37178825Sdfr#include <rtbl.h>
38178825Sdfr
39178825Sdfr/**
40178825Sdfr * @page page_cert The basic certificate
41178825Sdfr *
42178825Sdfr * The basic hx509 cerificate object in hx509 is hx509_cert. The
43178825Sdfr * hx509_cert object is representing one X509/PKIX certificate and
44178825Sdfr * associated attributes; like private key, friendly name, etc.
45178825Sdfr *
46178825Sdfr * A hx509_cert object is usully found via the keyset interfaces (@ref
47178825Sdfr * page_keyset), but its also possible to create a certificate
48178825Sdfr * directly from a parsed object with hx509_cert_init() and
49178825Sdfr * hx509_cert_init_data().
50178825Sdfr *
51178825Sdfr * See the library functions here: @ref hx509_cert
52178825Sdfr */
53178825Sdfr
54178825Sdfrstruct hx509_verify_ctx_data {
55178825Sdfr    hx509_certs trust_anchors;
56178825Sdfr    int flags;
57178825Sdfr#define HX509_VERIFY_CTX_F_TIME_SET			1
58178825Sdfr#define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE	2
59178825Sdfr#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280		4
60178825Sdfr#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS		8
61178825Sdfr#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS		16
62178825Sdfr    time_t time_now;
63178825Sdfr    unsigned int max_depth;
64178825Sdfr#define HX509_VERIFY_MAX_DEPTH 30
65178825Sdfr    hx509_revoke_ctx revoke_ctx;
66178825Sdfr};
67178825Sdfr
68178825Sdfr#define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280)
69178825Sdfr#define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS)
70178825Sdfr#define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0)
71178825Sdfr
72178825Sdfrstruct _hx509_cert_attrs {
73178825Sdfr    size_t len;
74178825Sdfr    hx509_cert_attribute *val;
75178825Sdfr};
76178825Sdfr
77178825Sdfrstruct hx509_cert_data {
78178825Sdfr    unsigned int ref;
79178825Sdfr    char *friendlyname;
80178825Sdfr    Certificate *data;
81178825Sdfr    hx509_private_key private_key;
82178825Sdfr    struct _hx509_cert_attrs attrs;
83178825Sdfr    hx509_name basename;
84178825Sdfr    _hx509_cert_release_func release;
85178825Sdfr    void *ctx;
86178825Sdfr};
87178825Sdfr
88178825Sdfrtypedef struct hx509_name_constraints {
89178825Sdfr    NameConstraints *val;
90178825Sdfr    size_t len;
91178825Sdfr} hx509_name_constraints;
92178825Sdfr
93178825Sdfr#define GeneralSubtrees_SET(g,var) \
94178825Sdfr	(g)->len = (var)->len, (g)->val = (var)->val;
95178825Sdfr
96178825Sdfr/**
97178825Sdfr * Creates a hx509 context that most functions in the library
98178825Sdfr * uses. The context is only allowed to be used by one thread at each
99178825Sdfr * moment. Free the context with hx509_context_free().
100178825Sdfr *
101178825Sdfr * @param context Returns a pointer to new hx509 context.
102178825Sdfr *
103178825Sdfr * @return Returns an hx509 error code.
104178825Sdfr *
105178825Sdfr * @ingroup hx509
106178825Sdfr */
107178825Sdfr
108178825Sdfrint
109178825Sdfrhx509_context_init(hx509_context *context)
110178825Sdfr{
111178825Sdfr    *context = calloc(1, sizeof(**context));
112178825Sdfr    if (*context == NULL)
113178825Sdfr	return ENOMEM;
114178825Sdfr
115178825Sdfr    _hx509_ks_null_register(*context);
116178825Sdfr    _hx509_ks_mem_register(*context);
117178825Sdfr    _hx509_ks_file_register(*context);
118178825Sdfr    _hx509_ks_pkcs12_register(*context);
119178825Sdfr    _hx509_ks_pkcs11_register(*context);
120178825Sdfr    _hx509_ks_dir_register(*context);
121178825Sdfr    _hx509_ks_keychain_register(*context);
122178825Sdfr
123178825Sdfr    ENGINE_add_conf_module();
124178825Sdfr    OpenSSL_add_all_algorithms();
125178825Sdfr
126178825Sdfr    (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF;
127178825Sdfr
128178825Sdfr    initialize_hx_error_table_r(&(*context)->et_list);
129178825Sdfr    initialize_asn1_error_table_r(&(*context)->et_list);
130178825Sdfr
131178825Sdfr#ifdef HX509_DEFAULT_ANCHORS
132178825Sdfr    (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0,
133178825Sdfr			   NULL, &(*context)->default_trust_anchors);
134178825Sdfr#endif
135178825Sdfr
136178825Sdfr    return 0;
137178825Sdfr}
138178825Sdfr
139178825Sdfr/**
140178825Sdfr * Selects if the hx509_revoke_verify() function is going to require
141178825Sdfr * the existans of a revokation method (OSCP, CRL) or not. Note that
142178825Sdfr * hx509_verify_path(), hx509_cms_verify_signed(), and other function
143178825Sdfr * call hx509_revoke_verify().
144178825Sdfr *
145178825Sdfr * @param context hx509 context to change the flag for.
146178825Sdfr * @param flag zero, revokation method required, non zero missing
147178825Sdfr * revokation method ok
148178825Sdfr *
149178825Sdfr * @ingroup hx509_verify
150178825Sdfr */
151178825Sdfr
152178825Sdfrvoid
153178825Sdfrhx509_context_set_missing_revoke(hx509_context context, int flag)
154178825Sdfr{
155178825Sdfr    if (flag)
156178825Sdfr	context->flags |= HX509_CTX_VERIFY_MISSING_OK;
157178825Sdfr    else
158178825Sdfr	context->flags &= ~HX509_CTX_VERIFY_MISSING_OK;
159178825Sdfr}
160178825Sdfr
161178825Sdfr/**
162178825Sdfr * Free the context allocated by hx509_context_init().
163178825Sdfr *
164178825Sdfr * @param context context to be freed.
165178825Sdfr *
166178825Sdfr * @ingroup hx509
167178825Sdfr */
168178825Sdfr
169178825Sdfrvoid
170178825Sdfrhx509_context_free(hx509_context *context)
171178825Sdfr{
172178825Sdfr    hx509_clear_error_string(*context);
173178825Sdfr    if ((*context)->ks_ops) {
174178825Sdfr	free((*context)->ks_ops);
175178825Sdfr	(*context)->ks_ops = NULL;
176178825Sdfr    }
177178825Sdfr    (*context)->ks_num_ops = 0;
178178825Sdfr    free_error_table ((*context)->et_list);
179178825Sdfr    if ((*context)->querystat)
180178825Sdfr	free((*context)->querystat);
181178825Sdfr    memset(*context, 0, sizeof(**context));
182178825Sdfr    free(*context);
183178825Sdfr    *context = NULL;
184178825Sdfr}
185178825Sdfr
186178825Sdfr/*
187178825Sdfr *
188178825Sdfr */
189178825Sdfr
190178825SdfrCertificate *
191178825Sdfr_hx509_get_cert(hx509_cert cert)
192178825Sdfr{
193178825Sdfr    return cert->data;
194178825Sdfr}
195178825Sdfr
196178825Sdfr/*
197178825Sdfr *
198178825Sdfr */
199178825Sdfr
200178825Sdfrint
201178825Sdfr_hx509_cert_get_version(const Certificate *t)
202178825Sdfr{
203178825Sdfr    return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1;
204178825Sdfr}
205178825Sdfr
206178825Sdfr/**
207178825Sdfr * Allocate and init an hx509 certificate object from the decoded
208178825Sdfr * certificate `c�.
209178825Sdfr *
210178825Sdfr * @param context A hx509 context.
211178825Sdfr * @param c
212178825Sdfr * @param cert
213178825Sdfr *
214178825Sdfr * @return Returns an hx509 error code.
215178825Sdfr *
216178825Sdfr * @ingroup hx509_cert
217178825Sdfr */
218178825Sdfr
219178825Sdfrint
220178825Sdfrhx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert)
221178825Sdfr{
222178825Sdfr    int ret;
223178825Sdfr
224178825Sdfr    *cert = malloc(sizeof(**cert));
225178825Sdfr    if (*cert == NULL)
226178825Sdfr	return ENOMEM;
227178825Sdfr    (*cert)->ref = 1;
228178825Sdfr    (*cert)->friendlyname = NULL;
229178825Sdfr    (*cert)->attrs.len = 0;
230178825Sdfr    (*cert)->attrs.val = NULL;
231178825Sdfr    (*cert)->private_key = NULL;
232178825Sdfr    (*cert)->basename = NULL;
233178825Sdfr    (*cert)->release = NULL;
234178825Sdfr    (*cert)->ctx = NULL;
235178825Sdfr
236178825Sdfr    (*cert)->data = calloc(1, sizeof(*(*cert)->data));
237178825Sdfr    if ((*cert)->data == NULL) {
238178825Sdfr	free(*cert);
239178825Sdfr	return ENOMEM;
240178825Sdfr    }
241178825Sdfr    ret = copy_Certificate(c, (*cert)->data);
242178825Sdfr    if (ret) {
243178825Sdfr	free((*cert)->data);
244178825Sdfr	free(*cert);
245178825Sdfr	*cert = NULL;
246178825Sdfr    }
247178825Sdfr    return ret;
248178825Sdfr}
249178825Sdfr
250178825Sdfr/**
251178825Sdfr * Just like hx509_cert_init(), but instead of a decode certificate
252178825Sdfr * takes an pointer and length to a memory region that contains a
253178825Sdfr * DER/BER encoded certificate.
254178825Sdfr *
255178825Sdfr * If the memory region doesn't contain just the certificate and
256178825Sdfr * nothing more the function will fail with
257178825Sdfr * HX509_EXTRA_DATA_AFTER_STRUCTURE.
258178825Sdfr *
259178825Sdfr * @param context A hx509 context.
260178825Sdfr * @param ptr pointer to memory region containing encoded certificate.
261178825Sdfr * @param len length of memory region.
262178825Sdfr * @param cert a return pointer to a hx509 certificate object, will
263178825Sdfr * contain NULL on error.
264178825Sdfr *
265178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
266178825Sdfr *
267178825Sdfr * @ingroup hx509_cert
268178825Sdfr */
269178825Sdfr
270178825Sdfrint
271178825Sdfrhx509_cert_init_data(hx509_context context,
272178825Sdfr		     const void *ptr,
273178825Sdfr		     size_t len,
274178825Sdfr		     hx509_cert *cert)
275178825Sdfr{
276178825Sdfr    Certificate t;
277178825Sdfr    size_t size;
278178825Sdfr    int ret;
279178825Sdfr
280178825Sdfr    ret = decode_Certificate(ptr, len, &t, &size);
281178825Sdfr    if (ret) {
282178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed to decode certificate");
283178825Sdfr	return ret;
284178825Sdfr    }
285178825Sdfr    if (size != len) {
286178825Sdfr	hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
287178825Sdfr			       "Extra data after certificate");
288178825Sdfr	return HX509_EXTRA_DATA_AFTER_STRUCTURE;
289178825Sdfr    }
290178825Sdfr
291178825Sdfr    ret = hx509_cert_init(context, &t, cert);
292178825Sdfr    free_Certificate(&t);
293178825Sdfr    return ret;
294178825Sdfr}
295178825Sdfr
296178825Sdfrvoid
297178825Sdfr_hx509_cert_set_release(hx509_cert cert,
298178825Sdfr			_hx509_cert_release_func release,
299178825Sdfr			void *ctx)
300178825Sdfr{
301178825Sdfr    cert->release = release;
302178825Sdfr    cert->ctx = ctx;
303178825Sdfr}
304178825Sdfr
305178825Sdfr
306178825Sdfr/* Doesn't make a copy of `private_key'. */
307178825Sdfr
308178825Sdfrint
309178825Sdfr_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
310178825Sdfr{
311178825Sdfr    if (cert->private_key)
312178825Sdfr	_hx509_private_key_free(&cert->private_key);
313178825Sdfr    cert->private_key = _hx509_private_key_ref(private_key);
314178825Sdfr    return 0;
315178825Sdfr}
316178825Sdfr
317178825Sdfr/**
318178825Sdfr * Free reference to the hx509 certificate object, if the refcounter
319178825Sdfr * reaches 0, the object if freed. Its allowed to pass in NULL.
320178825Sdfr *
321178825Sdfr * @param cert the cert to free.
322178825Sdfr *
323178825Sdfr * @ingroup hx509_cert
324178825Sdfr */
325178825Sdfr
326178825Sdfrvoid
327178825Sdfrhx509_cert_free(hx509_cert cert)
328178825Sdfr{
329178825Sdfr    int i;
330178825Sdfr
331178825Sdfr    if (cert == NULL)
332178825Sdfr	return;
333178825Sdfr
334178825Sdfr    if (cert->ref <= 0)
335178825Sdfr	_hx509_abort("cert refcount <= 0 on free");
336178825Sdfr    if (--cert->ref > 0)
337178825Sdfr	return;
338178825Sdfr
339178825Sdfr    if (cert->release)
340178825Sdfr	(cert->release)(cert, cert->ctx);
341178825Sdfr
342178825Sdfr    if (cert->private_key)
343178825Sdfr	_hx509_private_key_free(&cert->private_key);
344178825Sdfr
345178825Sdfr    free_Certificate(cert->data);
346178825Sdfr    free(cert->data);
347178825Sdfr
348178825Sdfr    for (i = 0; i < cert->attrs.len; i++) {
349178825Sdfr	der_free_octet_string(&cert->attrs.val[i]->data);
350178825Sdfr	der_free_oid(&cert->attrs.val[i]->oid);
351178825Sdfr	free(cert->attrs.val[i]);
352178825Sdfr    }
353178825Sdfr    free(cert->attrs.val);
354178825Sdfr    free(cert->friendlyname);
355178825Sdfr    if (cert->basename)
356178825Sdfr	hx509_name_free(&cert->basename);
357178825Sdfr    memset(cert, 0, sizeof(cert));
358178825Sdfr    free(cert);
359178825Sdfr}
360178825Sdfr
361178825Sdfr/**
362178825Sdfr * Add a reference to a hx509 certificate object.
363178825Sdfr *
364178825Sdfr * @param cert a pointer to an hx509 certificate object.
365178825Sdfr *
366178825Sdfr * @return the same object as is passed in.
367178825Sdfr *
368178825Sdfr * @ingroup hx509_cert
369178825Sdfr */
370178825Sdfr
371178825Sdfrhx509_cert
372178825Sdfrhx509_cert_ref(hx509_cert cert)
373178825Sdfr{
374178825Sdfr    if (cert == NULL)
375178825Sdfr	return NULL;
376178825Sdfr    if (cert->ref <= 0)
377178825Sdfr	_hx509_abort("cert refcount <= 0");
378178825Sdfr    cert->ref++;
379178825Sdfr    if (cert->ref == 0)
380178825Sdfr	_hx509_abort("cert refcount == 0");
381178825Sdfr    return cert;
382178825Sdfr}
383178825Sdfr
384178825Sdfr/**
385178825Sdfr * Allocate an verification context that is used fo control the
386178825Sdfr * verification process.
387178825Sdfr *
388178825Sdfr * @param context A hx509 context.
389178825Sdfr * @param ctx returns a pointer to a hx509_verify_ctx object.
390178825Sdfr *
391178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
392178825Sdfr *
393178825Sdfr * @ingroup hx509_verify
394178825Sdfr */
395178825Sdfr
396178825Sdfrint
397178825Sdfrhx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
398178825Sdfr{
399178825Sdfr    hx509_verify_ctx c;
400178825Sdfr
401178825Sdfr    c = calloc(1, sizeof(*c));
402178825Sdfr    if (c == NULL)
403178825Sdfr	return ENOMEM;
404178825Sdfr
405178825Sdfr    c->max_depth = HX509_VERIFY_MAX_DEPTH;
406178825Sdfr
407178825Sdfr    *ctx = c;
408178825Sdfr
409178825Sdfr    return 0;
410178825Sdfr}
411178825Sdfr
412178825Sdfr/**
413178825Sdfr * Free an hx509 verification context.
414178825Sdfr *
415178825Sdfr * @param ctx the context to be freed.
416178825Sdfr *
417178825Sdfr * @ingroup hx509_verify
418178825Sdfr */
419178825Sdfr
420178825Sdfrvoid
421178825Sdfrhx509_verify_destroy_ctx(hx509_verify_ctx ctx)
422178825Sdfr{
423178825Sdfr    if (ctx) {
424178825Sdfr	hx509_certs_free(&ctx->trust_anchors);
425178825Sdfr	hx509_revoke_free(&ctx->revoke_ctx);
426178825Sdfr	memset(ctx, 0, sizeof(*ctx));
427178825Sdfr    }
428178825Sdfr    free(ctx);
429178825Sdfr}
430178825Sdfr
431178825Sdfr/**
432178825Sdfr * Set the trust anchors in the verification context, makes an
433178825Sdfr * reference to the keyset, so the consumer can free the keyset
434178825Sdfr * independent of the destruction of the verification context (ctx).
435178825Sdfr *
436178825Sdfr * @param ctx a verification context
437178825Sdfr * @param set a keyset containing the trust anchors.
438178825Sdfr *
439178825Sdfr * @ingroup hx509_verify
440178825Sdfr */
441178825Sdfr
442178825Sdfrvoid
443178825Sdfrhx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
444178825Sdfr{
445178825Sdfr    ctx->trust_anchors = _hx509_certs_ref(set);
446178825Sdfr}
447178825Sdfr
448178825Sdfr/**
449178825Sdfr * Attach an revocation context to the verfication context, , makes an
450178825Sdfr * reference to the revoke context, so the consumer can free the
451178825Sdfr * revoke context independent of the destruction of the verification
452178825Sdfr * context. If there is no revoke context, the verification process is
453178825Sdfr * NOT going to check any verification status.
454178825Sdfr *
455178825Sdfr * @param ctx a verification context.
456178825Sdfr * @param revoke_ctx a revoke context.
457178825Sdfr *
458178825Sdfr * @ingroup hx509_verify
459178825Sdfr */
460178825Sdfr
461178825Sdfrvoid
462178825Sdfrhx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
463178825Sdfr{
464178825Sdfr    if (ctx->revoke_ctx)
465178825Sdfr	hx509_revoke_free(&ctx->revoke_ctx);
466178825Sdfr    ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
467178825Sdfr}
468178825Sdfr
469178825Sdfr/**
470178825Sdfr * Set the clock time the the verification process is going to
471178825Sdfr * use. Used to check certificate in the past and future time. If not
472178825Sdfr * set the current time will be used.
473178825Sdfr *
474178825Sdfr * @param ctx a verification context.
475178825Sdfr * @param t the time the verifiation is using.
476178825Sdfr *
477178825Sdfr *
478178825Sdfr * @ingroup hx509_verify
479178825Sdfr */
480178825Sdfr
481178825Sdfrvoid
482178825Sdfrhx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
483178825Sdfr{
484178825Sdfr    ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
485178825Sdfr    ctx->time_now = t;
486178825Sdfr}
487178825Sdfr
488178825Sdfr/**
489178825Sdfr * Set the maximum depth of the certificate chain that the path
490178825Sdfr * builder is going to try.
491178825Sdfr *
492178825Sdfr * @param ctx a verification context
493178825Sdfr * @param max_depth maxium depth of the certificate chain, include
494178825Sdfr * trust anchor.
495178825Sdfr *
496178825Sdfr * @ingroup hx509_verify
497178825Sdfr */
498178825Sdfr
499178825Sdfrvoid
500178825Sdfrhx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
501178825Sdfr{
502178825Sdfr    ctx->max_depth = max_depth;
503178825Sdfr}
504178825Sdfr
505178825Sdfr/**
506178825Sdfr * Allow or deny the use of proxy certificates
507178825Sdfr *
508178825Sdfr * @param ctx a verification context
509178825Sdfr * @param boolean if non zero, allow proxy certificates.
510178825Sdfr *
511178825Sdfr * @ingroup hx509_verify
512178825Sdfr */
513178825Sdfr
514178825Sdfrvoid
515178825Sdfrhx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
516178825Sdfr{
517178825Sdfr    if (boolean)
518178825Sdfr	ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
519178825Sdfr    else
520178825Sdfr	ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
521178825Sdfr}
522178825Sdfr
523178825Sdfr/**
524178825Sdfr * Select strict RFC3280 verification of certificiates. This means
525178825Sdfr * checking key usage on CA certificates, this will make version 1
526178825Sdfr * certificiates unuseable.
527178825Sdfr *
528178825Sdfr * @param ctx a verification context
529178825Sdfr * @param boolean if non zero, use strict verification.
530178825Sdfr *
531178825Sdfr * @ingroup hx509_verify
532178825Sdfr */
533178825Sdfr
534178825Sdfrvoid
535178825Sdfrhx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
536178825Sdfr{
537178825Sdfr    if (boolean)
538178825Sdfr	ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
539178825Sdfr    else
540178825Sdfr	ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
541178825Sdfr}
542178825Sdfr
543178825Sdfr/**
544178825Sdfr * Allow using the operating system builtin trust anchors if no other
545178825Sdfr * trust anchors are configured.
546178825Sdfr *
547178825Sdfr * @param ctx a verification context
548178825Sdfr * @param boolean if non zero, useing the operating systems builtin
549178825Sdfr * trust anchors.
550178825Sdfr *
551178825Sdfr *
552178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
553178825Sdfr *
554178825Sdfr * @ingroup hx509_cert
555178825Sdfr */
556178825Sdfr
557178825Sdfrvoid
558178825Sdfrhx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
559178825Sdfr{
560178825Sdfr    if (boolean)
561178825Sdfr	ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
562178825Sdfr    else
563178825Sdfr	ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
564178825Sdfr}
565178825Sdfr
566178825Sdfrstatic const Extension *
567178825Sdfrfind_extension(const Certificate *cert, const heim_oid *oid, int *idx)
568178825Sdfr{
569178825Sdfr    const TBSCertificate *c = &cert->tbsCertificate;
570178825Sdfr
571178825Sdfr    if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
572178825Sdfr	return NULL;
573178825Sdfr
574178825Sdfr    for (;*idx < c->extensions->len; (*idx)++) {
575178825Sdfr	if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
576178825Sdfr	    return &c->extensions->val[(*idx)++];
577178825Sdfr    }
578178825Sdfr    return NULL;
579178825Sdfr}
580178825Sdfr
581178825Sdfrstatic int
582178825Sdfrfind_extension_auth_key_id(const Certificate *subject,
583178825Sdfr			   AuthorityKeyIdentifier *ai)
584178825Sdfr{
585178825Sdfr    const Extension *e;
586178825Sdfr    size_t size;
587178825Sdfr    int i = 0;
588178825Sdfr
589178825Sdfr    memset(ai, 0, sizeof(*ai));
590178825Sdfr
591178825Sdfr    e = find_extension(subject, oid_id_x509_ce_authorityKeyIdentifier(), &i);
592178825Sdfr    if (e == NULL)
593178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
594178825Sdfr
595178825Sdfr    return decode_AuthorityKeyIdentifier(e->extnValue.data,
596178825Sdfr					 e->extnValue.length,
597178825Sdfr					 ai, &size);
598178825Sdfr}
599178825Sdfr
600178825Sdfrint
601178825Sdfr_hx509_find_extension_subject_key_id(const Certificate *issuer,
602178825Sdfr				     SubjectKeyIdentifier *si)
603178825Sdfr{
604178825Sdfr    const Extension *e;
605178825Sdfr    size_t size;
606178825Sdfr    int i = 0;
607178825Sdfr
608178825Sdfr    memset(si, 0, sizeof(*si));
609178825Sdfr
610178825Sdfr    e = find_extension(issuer, oid_id_x509_ce_subjectKeyIdentifier(), &i);
611178825Sdfr    if (e == NULL)
612178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
613178825Sdfr
614178825Sdfr    return decode_SubjectKeyIdentifier(e->extnValue.data,
615178825Sdfr				       e->extnValue.length,
616178825Sdfr				       si, &size);
617178825Sdfr}
618178825Sdfr
619178825Sdfrstatic int
620178825Sdfrfind_extension_name_constraints(const Certificate *subject,
621178825Sdfr				NameConstraints *nc)
622178825Sdfr{
623178825Sdfr    const Extension *e;
624178825Sdfr    size_t size;
625178825Sdfr    int i = 0;
626178825Sdfr
627178825Sdfr    memset(nc, 0, sizeof(*nc));
628178825Sdfr
629178825Sdfr    e = find_extension(subject, oid_id_x509_ce_nameConstraints(), &i);
630178825Sdfr    if (e == NULL)
631178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
632178825Sdfr
633178825Sdfr    return decode_NameConstraints(e->extnValue.data,
634178825Sdfr				  e->extnValue.length,
635178825Sdfr				  nc, &size);
636178825Sdfr}
637178825Sdfr
638178825Sdfrstatic int
639178825Sdfrfind_extension_subject_alt_name(const Certificate *cert, int *i,
640178825Sdfr				GeneralNames *sa)
641178825Sdfr{
642178825Sdfr    const Extension *e;
643178825Sdfr    size_t size;
644178825Sdfr
645178825Sdfr    memset(sa, 0, sizeof(*sa));
646178825Sdfr
647178825Sdfr    e = find_extension(cert, oid_id_x509_ce_subjectAltName(), i);
648178825Sdfr    if (e == NULL)
649178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
650178825Sdfr
651178825Sdfr    return decode_GeneralNames(e->extnValue.data,
652178825Sdfr			       e->extnValue.length,
653178825Sdfr			       sa, &size);
654178825Sdfr}
655178825Sdfr
656178825Sdfrstatic int
657178825Sdfrfind_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
658178825Sdfr{
659178825Sdfr    const Extension *e;
660178825Sdfr    size_t size;
661178825Sdfr    int i = 0;
662178825Sdfr
663178825Sdfr    memset(eku, 0, sizeof(*eku));
664178825Sdfr
665178825Sdfr    e = find_extension(cert, oid_id_x509_ce_extKeyUsage(), &i);
666178825Sdfr    if (e == NULL)
667178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
668178825Sdfr
669178825Sdfr    return decode_ExtKeyUsage(e->extnValue.data,
670178825Sdfr			      e->extnValue.length,
671178825Sdfr			      eku, &size);
672178825Sdfr}
673178825Sdfr
674178825Sdfrstatic int
675178825Sdfradd_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
676178825Sdfr{
677178825Sdfr    void *p;
678178825Sdfr    int ret;
679178825Sdfr
680178825Sdfr    p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
681178825Sdfr    if (p == NULL)
682178825Sdfr	return ENOMEM;
683178825Sdfr    list->val = p;
684178825Sdfr    ret = der_copy_octet_string(entry, &list->val[list->len]);
685178825Sdfr    if (ret)
686178825Sdfr	return ret;
687178825Sdfr    list->len++;
688178825Sdfr    return 0;
689178825Sdfr}
690178825Sdfr
691178825Sdfr/**
692178825Sdfr * Free a list of octet strings returned by another hx509 library
693178825Sdfr * function.
694178825Sdfr *
695178825Sdfr * @param list list to be freed.
696178825Sdfr *
697178825Sdfr * @ingroup hx509_misc
698178825Sdfr */
699178825Sdfr
700178825Sdfrvoid
701178825Sdfrhx509_free_octet_string_list(hx509_octet_string_list *list)
702178825Sdfr{
703178825Sdfr    int i;
704178825Sdfr    for (i = 0; i < list->len; i++)
705178825Sdfr	der_free_octet_string(&list->val[i]);
706178825Sdfr    free(list->val);
707178825Sdfr    list->val = NULL;
708178825Sdfr    list->len = 0;
709178825Sdfr}
710178825Sdfr
711178825Sdfr/**
712178825Sdfr * Return a list of subjectAltNames specified by oid in the
713178825Sdfr * certificate. On error the
714178825Sdfr *
715178825Sdfr * The returned list of octet string should be freed with
716178825Sdfr * hx509_free_octet_string_list().
717178825Sdfr *
718178825Sdfr * @param context A hx509 context.
719178825Sdfr * @param cert a hx509 certificate object.
720178825Sdfr * @param oid an oid to for SubjectAltName.
721178825Sdfr * @param list list of matching SubjectAltName.
722178825Sdfr *
723178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
724178825Sdfr *
725178825Sdfr * @ingroup hx509_cert
726178825Sdfr */
727178825Sdfr
728178825Sdfrint
729178825Sdfrhx509_cert_find_subjectAltName_otherName(hx509_context context,
730178825Sdfr					 hx509_cert cert,
731178825Sdfr					 const heim_oid *oid,
732178825Sdfr					 hx509_octet_string_list *list)
733178825Sdfr{
734178825Sdfr    GeneralNames sa;
735178825Sdfr    int ret, i, j;
736178825Sdfr
737178825Sdfr    list->val = NULL;
738178825Sdfr    list->len = 0;
739178825Sdfr
740178825Sdfr    i = 0;
741178825Sdfr    while (1) {
742178825Sdfr	ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
743178825Sdfr	i++;
744178825Sdfr	if (ret == HX509_EXTENSION_NOT_FOUND) {
745178825Sdfr	    ret = 0;
746178825Sdfr	    break;
747178825Sdfr	} else if (ret != 0) {
748178825Sdfr	    hx509_set_error_string(context, 0, ret, "Error searching for SAN");
749178825Sdfr	    hx509_free_octet_string_list(list);
750178825Sdfr	    return ret;
751178825Sdfr	}
752178825Sdfr
753178825Sdfr	for (j = 0; j < sa.len; j++) {
754178825Sdfr	    if (sa.val[j].element == choice_GeneralName_otherName &&
755178825Sdfr		der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
756178825Sdfr	    {
757178825Sdfr		ret = add_to_list(list, &sa.val[j].u.otherName.value);
758178825Sdfr		if (ret) {
759178825Sdfr		    hx509_set_error_string(context, 0, ret,
760178825Sdfr					   "Error adding an exra SAN to "
761178825Sdfr					   "return list");
762178825Sdfr		    hx509_free_octet_string_list(list);
763178825Sdfr		    free_GeneralNames(&sa);
764178825Sdfr		    return ret;
765178825Sdfr		}
766178825Sdfr	    }
767178825Sdfr	}
768178825Sdfr	free_GeneralNames(&sa);
769178825Sdfr    }
770178825Sdfr    return 0;
771178825Sdfr}
772178825Sdfr
773178825Sdfr
774178825Sdfrstatic int
775178825Sdfrcheck_key_usage(hx509_context context, const Certificate *cert,
776178825Sdfr		unsigned flags, int req_present)
777178825Sdfr{
778178825Sdfr    const Extension *e;
779178825Sdfr    KeyUsage ku;
780178825Sdfr    size_t size;
781178825Sdfr    int ret, i = 0;
782178825Sdfr    unsigned ku_flags;
783178825Sdfr
784178825Sdfr    if (_hx509_cert_get_version(cert) < 3)
785178825Sdfr	return 0;
786178825Sdfr
787178825Sdfr    e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
788178825Sdfr    if (e == NULL) {
789178825Sdfr	if (req_present) {
790178825Sdfr	    hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
791178825Sdfr				   "Required extension key "
792178825Sdfr				   "usage missing from certifiate");
793178825Sdfr	    return HX509_KU_CERT_MISSING;
794178825Sdfr	}
795178825Sdfr	return 0;
796178825Sdfr    }
797178825Sdfr
798178825Sdfr    ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
799178825Sdfr    if (ret)
800178825Sdfr	return ret;
801178825Sdfr    ku_flags = KeyUsage2int(ku);
802178825Sdfr    if ((ku_flags & flags) != flags) {
803178825Sdfr	unsigned missing = (~ku_flags) & flags;
804178825Sdfr	char buf[256], *name;
805178825Sdfr
806178825Sdfr	unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
807178825Sdfr	_hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
808178825Sdfr	hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
809178825Sdfr			       "Key usage %s required but missing "
810178825Sdfr			       "from certifiate %s", buf, name);
811178825Sdfr	free(name);
812178825Sdfr	return HX509_KU_CERT_MISSING;
813178825Sdfr    }
814178825Sdfr    return 0;
815178825Sdfr}
816178825Sdfr
817178825Sdfr/*
818178825Sdfr * Return 0 on matching key usage 'flags' for 'cert', otherwise return
819178825Sdfr * an error code. If 'req_present' the existance is required of the
820178825Sdfr * KeyUsage extension.
821178825Sdfr */
822178825Sdfr
823178825Sdfrint
824178825Sdfr_hx509_check_key_usage(hx509_context context, hx509_cert cert,
825178825Sdfr		       unsigned flags, int req_present)
826178825Sdfr{
827178825Sdfr    return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
828178825Sdfr}
829178825Sdfr
830178825Sdfrenum certtype { PROXY_CERT, EE_CERT, CA_CERT };
831178825Sdfr
832178825Sdfrstatic int
833178825Sdfrcheck_basic_constraints(hx509_context context, const Certificate *cert,
834178825Sdfr			enum certtype type, int depth)
835178825Sdfr{
836178825Sdfr    BasicConstraints bc;
837178825Sdfr    const Extension *e;
838178825Sdfr    size_t size;
839178825Sdfr    int ret, i = 0;
840178825Sdfr
841178825Sdfr    if (_hx509_cert_get_version(cert) < 3)
842178825Sdfr	return 0;
843178825Sdfr
844178825Sdfr    e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i);
845178825Sdfr    if (e == NULL) {
846178825Sdfr	switch(type) {
847178825Sdfr	case PROXY_CERT:
848178825Sdfr	case EE_CERT:
849178825Sdfr	    return 0;
850178825Sdfr	case CA_CERT: {
851178825Sdfr	    char *name;
852178825Sdfr	    ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
853178825Sdfr	    assert(ret == 0);
854178825Sdfr	    hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
855178825Sdfr				   "basicConstraints missing from "
856178825Sdfr				   "CA certifiacte %s", name);
857178825Sdfr	    free(name);
858178825Sdfr	    return HX509_EXTENSION_NOT_FOUND;
859178825Sdfr	}
860178825Sdfr	}
861178825Sdfr    }
862178825Sdfr
863178825Sdfr    ret = decode_BasicConstraints(e->extnValue.data,
864178825Sdfr				  e->extnValue.length, &bc,
865178825Sdfr				  &size);
866178825Sdfr    if (ret)
867178825Sdfr	return ret;
868178825Sdfr    switch(type) {
869178825Sdfr    case PROXY_CERT:
870178825Sdfr	if (bc.cA != NULL && *bc.cA)
871178825Sdfr	    ret = HX509_PARENT_IS_CA;
872178825Sdfr	break;
873178825Sdfr    case EE_CERT:
874178825Sdfr	ret = 0;
875178825Sdfr	break;
876178825Sdfr    case CA_CERT:
877178825Sdfr	if (bc.cA == NULL || !*bc.cA)
878178825Sdfr	    ret = HX509_PARENT_NOT_CA;
879178825Sdfr	else if (bc.pathLenConstraint)
880178825Sdfr	    if (depth - 1 > *bc.pathLenConstraint)
881178825Sdfr		ret = HX509_CA_PATH_TOO_DEEP;
882178825Sdfr	break;
883178825Sdfr    }
884178825Sdfr    free_BasicConstraints(&bc);
885178825Sdfr    return ret;
886178825Sdfr}
887178825Sdfr
888178825Sdfrint
889178825Sdfr_hx509_cert_is_parent_cmp(const Certificate *subject,
890178825Sdfr			  const Certificate *issuer,
891178825Sdfr			  int allow_self_signed)
892178825Sdfr{
893178825Sdfr    int diff;
894178825Sdfr    AuthorityKeyIdentifier ai;
895178825Sdfr    SubjectKeyIdentifier si;
896178825Sdfr    int ret_ai, ret_si;
897178825Sdfr
898178825Sdfr    diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
899178825Sdfr			   &subject->tbsCertificate.issuer);
900178825Sdfr    if (diff)
901178825Sdfr	return diff;
902178825Sdfr
903178825Sdfr    memset(&ai, 0, sizeof(ai));
904178825Sdfr    memset(&si, 0, sizeof(si));
905178825Sdfr
906178825Sdfr    /*
907178825Sdfr     * Try to find AuthorityKeyIdentifier, if it's not present in the
908178825Sdfr     * subject certificate nor the parent.
909178825Sdfr     */
910178825Sdfr
911178825Sdfr    ret_ai = find_extension_auth_key_id(subject, &ai);
912178825Sdfr    if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
913178825Sdfr	return 1;
914178825Sdfr    ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
915178825Sdfr    if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
916178825Sdfr	return -1;
917178825Sdfr
918178825Sdfr    if (ret_si && ret_ai)
919178825Sdfr	goto out;
920178825Sdfr    if (ret_ai)
921178825Sdfr	goto out;
922178825Sdfr    if (ret_si) {
923178825Sdfr	if (allow_self_signed) {
924178825Sdfr	    diff = 0;
925178825Sdfr	    goto out;
926178825Sdfr	} else if (ai.keyIdentifier) {
927178825Sdfr	    diff = -1;
928178825Sdfr	    goto out;
929178825Sdfr	}
930178825Sdfr    }
931178825Sdfr
932178825Sdfr    if (ai.keyIdentifier == NULL) {
933178825Sdfr	Name name;
934178825Sdfr
935178825Sdfr	if (ai.authorityCertIssuer == NULL)
936178825Sdfr	    return -1;
937178825Sdfr	if (ai.authorityCertSerialNumber == NULL)
938178825Sdfr	    return -1;
939178825Sdfr
940178825Sdfr	diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
941178825Sdfr				    &issuer->tbsCertificate.serialNumber);
942178825Sdfr	if (diff)
943178825Sdfr	    return diff;
944178825Sdfr	if (ai.authorityCertIssuer->len != 1)
945178825Sdfr	    return -1;
946178825Sdfr	if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
947178825Sdfr	    return -1;
948178825Sdfr
949178825Sdfr	name.element =
950178825Sdfr	    ai.authorityCertIssuer->val[0].u.directoryName.element;
951178825Sdfr	name.u.rdnSequence =
952178825Sdfr	    ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
953178825Sdfr
954178825Sdfr	diff = _hx509_name_cmp(&issuer->tbsCertificate.subject,
955178825Sdfr			       &name);
956178825Sdfr	if (diff)
957178825Sdfr	    return diff;
958178825Sdfr	diff = 0;
959178825Sdfr    } else
960178825Sdfr	diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
961178825Sdfr    if (diff)
962178825Sdfr	goto out;
963178825Sdfr
964178825Sdfr out:
965178825Sdfr    free_AuthorityKeyIdentifier(&ai);
966178825Sdfr    free_SubjectKeyIdentifier(&si);
967178825Sdfr    return diff;
968178825Sdfr}
969178825Sdfr
970178825Sdfrstatic int
971178825Sdfrcertificate_is_anchor(hx509_context context,
972178825Sdfr		      hx509_certs trust_anchors,
973178825Sdfr		      const hx509_cert cert)
974178825Sdfr{
975178825Sdfr    hx509_query q;
976178825Sdfr    hx509_cert c;
977178825Sdfr    int ret;
978178825Sdfr
979178825Sdfr    if (trust_anchors == NULL)
980178825Sdfr	return 0;
981178825Sdfr
982178825Sdfr    _hx509_query_clear(&q);
983178825Sdfr
984178825Sdfr    q.match = HX509_QUERY_MATCH_CERTIFICATE;
985178825Sdfr    q.certificate = _hx509_get_cert(cert);
986178825Sdfr
987178825Sdfr    ret = hx509_certs_find(context, trust_anchors, &q, &c);
988178825Sdfr    if (ret == 0)
989178825Sdfr	hx509_cert_free(c);
990178825Sdfr    return ret == 0;
991178825Sdfr}
992178825Sdfr
993178825Sdfrstatic int
994178825Sdfrcertificate_is_self_signed(const Certificate *cert)
995178825Sdfr{
996178825Sdfr    return _hx509_name_cmp(&cert->tbsCertificate.subject,
997178825Sdfr			   &cert->tbsCertificate.issuer) == 0;
998178825Sdfr}
999178825Sdfr
1000178825Sdfr/*
1001178825Sdfr * The subjectName is "null" when it's empty set of relative DBs.
1002178825Sdfr */
1003178825Sdfr
1004178825Sdfrstatic int
1005178825Sdfrsubject_null_p(const Certificate *c)
1006178825Sdfr{
1007178825Sdfr    return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1008178825Sdfr}
1009178825Sdfr
1010178825Sdfr
1011178825Sdfrstatic int
1012178825Sdfrfind_parent(hx509_context context,
1013178825Sdfr	    time_t time_now,
1014178825Sdfr	    hx509_certs trust_anchors,
1015178825Sdfr	    hx509_path *path,
1016178825Sdfr	    hx509_certs pool,
1017178825Sdfr	    hx509_cert current,
1018178825Sdfr	    hx509_cert *parent)
1019178825Sdfr{
1020178825Sdfr    AuthorityKeyIdentifier ai;
1021178825Sdfr    hx509_query q;
1022178825Sdfr    int ret;
1023178825Sdfr
1024178825Sdfr    *parent = NULL;
1025178825Sdfr    memset(&ai, 0, sizeof(ai));
1026178825Sdfr
1027178825Sdfr    _hx509_query_clear(&q);
1028178825Sdfr
1029178825Sdfr    if (!subject_null_p(current->data)) {
1030178825Sdfr	q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1031178825Sdfr	q.subject = _hx509_get_cert(current);
1032178825Sdfr    } else {
1033178825Sdfr	ret = find_extension_auth_key_id(current->data, &ai);
1034178825Sdfr	if (ret) {
1035178825Sdfr	    hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1036178825Sdfr				   "Subjectless certificate missing AuthKeyID");
1037178825Sdfr	    return HX509_CERTIFICATE_MALFORMED;
1038178825Sdfr	}
1039178825Sdfr
1040178825Sdfr	if (ai.keyIdentifier == NULL) {
1041178825Sdfr	    free_AuthorityKeyIdentifier(&ai);
1042178825Sdfr	    hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1043178825Sdfr				   "Subjectless certificate missing keyIdentifier "
1044178825Sdfr				   "inside AuthKeyID");
1045178825Sdfr	    return HX509_CERTIFICATE_MALFORMED;
1046178825Sdfr	}
1047178825Sdfr
1048178825Sdfr	q.subject_id = ai.keyIdentifier;
1049178825Sdfr	q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1050178825Sdfr    }
1051178825Sdfr
1052178825Sdfr    q.path = path;
1053178825Sdfr    q.match |= HX509_QUERY_NO_MATCH_PATH;
1054178825Sdfr
1055178825Sdfr    if (pool) {
1056178825Sdfr	q.timenow = time_now;
1057178825Sdfr	q.match |= HX509_QUERY_MATCH_TIME;
1058178825Sdfr
1059178825Sdfr	ret = hx509_certs_find(context, pool, &q, parent);
1060178825Sdfr	if (ret == 0) {
1061178825Sdfr	    free_AuthorityKeyIdentifier(&ai);
1062178825Sdfr	    return 0;
1063178825Sdfr	}
1064178825Sdfr	q.match &= ~HX509_QUERY_MATCH_TIME;
1065178825Sdfr    }
1066178825Sdfr
1067178825Sdfr    if (trust_anchors) {
1068178825Sdfr	ret = hx509_certs_find(context, trust_anchors, &q, parent);
1069178825Sdfr	if (ret == 0) {
1070178825Sdfr	    free_AuthorityKeyIdentifier(&ai);
1071178825Sdfr	    return ret;
1072178825Sdfr	}
1073178825Sdfr    }
1074178825Sdfr    free_AuthorityKeyIdentifier(&ai);
1075178825Sdfr
1076178825Sdfr    {
1077178825Sdfr	hx509_name name;
1078178825Sdfr	char *str;
1079178825Sdfr
1080178825Sdfr	ret = hx509_cert_get_subject(current, &name);
1081178825Sdfr	if (ret) {
1082178825Sdfr	    hx509_clear_error_string(context);
1083178825Sdfr	    return HX509_ISSUER_NOT_FOUND;
1084178825Sdfr	}
1085178825Sdfr	ret = hx509_name_to_string(name, &str);
1086178825Sdfr	hx509_name_free(&name);
1087178825Sdfr	if (ret) {
1088178825Sdfr	    hx509_clear_error_string(context);
1089178825Sdfr	    return HX509_ISSUER_NOT_FOUND;
1090178825Sdfr	}
1091178825Sdfr
1092178825Sdfr	hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1093178825Sdfr			       "Failed to find issuer for "
1094178825Sdfr			       "certificate with subject: '%s'", str);
1095178825Sdfr	free(str);
1096178825Sdfr    }
1097178825Sdfr    return HX509_ISSUER_NOT_FOUND;
1098178825Sdfr}
1099178825Sdfr
1100178825Sdfr/*
1101178825Sdfr *
1102178825Sdfr */
1103178825Sdfr
1104178825Sdfrstatic int
1105178825Sdfris_proxy_cert(hx509_context context,
1106178825Sdfr	      const Certificate *cert,
1107178825Sdfr	      ProxyCertInfo *rinfo)
1108178825Sdfr{
1109178825Sdfr    ProxyCertInfo info;
1110178825Sdfr    const Extension *e;
1111178825Sdfr    size_t size;
1112178825Sdfr    int ret, i = 0;
1113178825Sdfr
1114178825Sdfr    if (rinfo)
1115178825Sdfr	memset(rinfo, 0, sizeof(*rinfo));
1116178825Sdfr
1117178825Sdfr    e = find_extension(cert, oid_id_pkix_pe_proxyCertInfo(), &i);
1118178825Sdfr    if (e == NULL) {
1119178825Sdfr	hx509_clear_error_string(context);
1120178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
1121178825Sdfr    }
1122178825Sdfr
1123178825Sdfr    ret = decode_ProxyCertInfo(e->extnValue.data,
1124178825Sdfr			       e->extnValue.length,
1125178825Sdfr			       &info,
1126178825Sdfr			       &size);
1127178825Sdfr    if (ret) {
1128178825Sdfr	hx509_clear_error_string(context);
1129178825Sdfr	return ret;
1130178825Sdfr    }
1131178825Sdfr    if (size != e->extnValue.length) {
1132178825Sdfr	free_ProxyCertInfo(&info);
1133178825Sdfr	hx509_clear_error_string(context);
1134178825Sdfr	return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1135178825Sdfr    }
1136178825Sdfr    if (rinfo == NULL)
1137178825Sdfr	free_ProxyCertInfo(&info);
1138178825Sdfr    else
1139178825Sdfr	*rinfo = info;
1140178825Sdfr
1141178825Sdfr    return 0;
1142178825Sdfr}
1143178825Sdfr
1144178825Sdfr/*
1145178825Sdfr * Path operations are like MEMORY based keyset, but with exposed
1146178825Sdfr * internal so we can do easy searches.
1147178825Sdfr */
1148178825Sdfr
1149178825Sdfrint
1150178825Sdfr_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1151178825Sdfr{
1152178825Sdfr    hx509_cert *val;
1153178825Sdfr    val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1154178825Sdfr    if (val == NULL) {
1155178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1156178825Sdfr	return ENOMEM;
1157178825Sdfr    }
1158178825Sdfr
1159178825Sdfr    path->val = val;
1160178825Sdfr    path->val[path->len] = hx509_cert_ref(cert);
1161178825Sdfr    path->len++;
1162178825Sdfr
1163178825Sdfr    return 0;
1164178825Sdfr}
1165178825Sdfr
1166178825Sdfrvoid
1167178825Sdfr_hx509_path_free(hx509_path *path)
1168178825Sdfr{
1169178825Sdfr    unsigned i;
1170178825Sdfr
1171178825Sdfr    for (i = 0; i < path->len; i++)
1172178825Sdfr	hx509_cert_free(path->val[i]);
1173178825Sdfr    free(path->val);
1174178825Sdfr    path->val = NULL;
1175178825Sdfr    path->len = 0;
1176178825Sdfr}
1177178825Sdfr
1178178825Sdfr/*
1179178825Sdfr * Find path by looking up issuer for the top certificate and continue
1180178825Sdfr * until an anchor certificate is found or max limit is found. A
1181178825Sdfr * certificate never included twice in the path.
1182178825Sdfr *
1183178825Sdfr * If the trust anchors are not given, calculate optimistic path, just
1184178825Sdfr * follow the chain upward until we no longer find a parent or we hit
1185178825Sdfr * the max path limit. In this case, a failure will always be returned
1186178825Sdfr * depending on what error condition is hit first.
1187178825Sdfr *
1188178825Sdfr * The path includes a path from the top certificate to the anchor
1189178825Sdfr * certificate.
1190178825Sdfr *
1191178825Sdfr * The caller needs to free `path� both on successful built path and
1192178825Sdfr * failure.
1193178825Sdfr */
1194178825Sdfr
1195178825Sdfrint
1196178825Sdfr_hx509_calculate_path(hx509_context context,
1197178825Sdfr		      int flags,
1198178825Sdfr		      time_t time_now,
1199178825Sdfr		      hx509_certs anchors,
1200178825Sdfr		      unsigned int max_depth,
1201178825Sdfr		      hx509_cert cert,
1202178825Sdfr		      hx509_certs pool,
1203178825Sdfr		      hx509_path *path)
1204178825Sdfr{
1205178825Sdfr    hx509_cert parent, current;
1206178825Sdfr    int ret;
1207178825Sdfr
1208178825Sdfr    if (max_depth == 0)
1209178825Sdfr	max_depth = HX509_VERIFY_MAX_DEPTH;
1210178825Sdfr
1211178825Sdfr    ret = _hx509_path_append(context, path, cert);
1212178825Sdfr    if (ret)
1213178825Sdfr	return ret;
1214178825Sdfr
1215178825Sdfr    current = hx509_cert_ref(cert);
1216178825Sdfr
1217178825Sdfr    while (!certificate_is_anchor(context, anchors, current)) {
1218178825Sdfr
1219178825Sdfr	ret = find_parent(context, time_now, anchors, path,
1220178825Sdfr			  pool, current, &parent);
1221178825Sdfr	hx509_cert_free(current);
1222178825Sdfr	if (ret)
1223178825Sdfr	    return ret;
1224178825Sdfr
1225178825Sdfr	ret = _hx509_path_append(context, path, parent);
1226178825Sdfr	if (ret)
1227178825Sdfr	    return ret;
1228178825Sdfr	current = parent;
1229178825Sdfr
1230178825Sdfr	if (path->len > max_depth) {
1231178825Sdfr	    hx509_cert_free(current);
1232178825Sdfr	    hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1233178825Sdfr				   "Path too long while bulding "
1234178825Sdfr				   "certificate chain");
1235178825Sdfr	    return HX509_PATH_TOO_LONG;
1236178825Sdfr	}
1237178825Sdfr    }
1238178825Sdfr
1239178825Sdfr    if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1240178825Sdfr	path->len > 0 &&
1241178825Sdfr	certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1242178825Sdfr    {
1243178825Sdfr	hx509_cert_free(path->val[path->len - 1]);
1244178825Sdfr	path->len--;
1245178825Sdfr    }
1246178825Sdfr
1247178825Sdfr    hx509_cert_free(current);
1248178825Sdfr    return 0;
1249178825Sdfr}
1250178825Sdfr
1251178825Sdfrint
1252178825Sdfr_hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1253178825Sdfr			       const AlgorithmIdentifier *q)
1254178825Sdfr{
1255178825Sdfr    int diff;
1256178825Sdfr    diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1257178825Sdfr    if (diff)
1258178825Sdfr	return diff;
1259178825Sdfr    if (p->parameters) {
1260178825Sdfr	if (q->parameters)
1261178825Sdfr	    return heim_any_cmp(p->parameters,
1262178825Sdfr				q->parameters);
1263178825Sdfr	else
1264178825Sdfr	    return 1;
1265178825Sdfr    } else {
1266178825Sdfr	if (q->parameters)
1267178825Sdfr	    return -1;
1268178825Sdfr	else
1269178825Sdfr	    return 0;
1270178825Sdfr    }
1271178825Sdfr}
1272178825Sdfr
1273178825Sdfrint
1274178825Sdfr_hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1275178825Sdfr{
1276178825Sdfr    int diff;
1277178825Sdfr    diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1278178825Sdfr    if (diff)
1279178825Sdfr	return diff;
1280178825Sdfr    diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1281178825Sdfr					  &q->signatureAlgorithm);
1282178825Sdfr    if (diff)
1283178825Sdfr	return diff;
1284178825Sdfr    diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1285178825Sdfr				     &q->tbsCertificate._save);
1286178825Sdfr    return diff;
1287178825Sdfr}
1288178825Sdfr
1289178825Sdfr/**
1290178825Sdfr * Compare to hx509 certificate object, useful for sorting.
1291178825Sdfr *
1292178825Sdfr * @param p a hx509 certificate object.
1293178825Sdfr * @param q a hx509 certificate object.
1294178825Sdfr *
1295178825Sdfr * @return 0 the objects are the same, returns > 0 is p is "larger"
1296178825Sdfr * then q, < 0 if p is "smaller" then q.
1297178825Sdfr *
1298178825Sdfr * @ingroup hx509_cert
1299178825Sdfr */
1300178825Sdfr
1301178825Sdfrint
1302178825Sdfrhx509_cert_cmp(hx509_cert p, hx509_cert q)
1303178825Sdfr{
1304178825Sdfr    return _hx509_Certificate_cmp(p->data, q->data);
1305178825Sdfr}
1306178825Sdfr
1307178825Sdfr/**
1308178825Sdfr * Return the name of the issuer of the hx509 certificate.
1309178825Sdfr *
1310178825Sdfr * @param p a hx509 certificate object.
1311178825Sdfr * @param name a pointer to a hx509 name, should be freed by
1312178825Sdfr * hx509_name_free().
1313178825Sdfr *
1314178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1315178825Sdfr *
1316178825Sdfr * @ingroup hx509_cert
1317178825Sdfr */
1318178825Sdfr
1319178825Sdfrint
1320178825Sdfrhx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1321178825Sdfr{
1322178825Sdfr    return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1323178825Sdfr}
1324178825Sdfr
1325178825Sdfr/**
1326178825Sdfr * Return the name of the subject of the hx509 certificate.
1327178825Sdfr *
1328178825Sdfr * @param p a hx509 certificate object.
1329178825Sdfr * @param name a pointer to a hx509 name, should be freed by
1330178825Sdfr * hx509_name_free(). See also hx509_cert_get_base_subject().
1331178825Sdfr *
1332178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1333178825Sdfr *
1334178825Sdfr * @ingroup hx509_cert
1335178825Sdfr */
1336178825Sdfr
1337178825Sdfrint
1338178825Sdfrhx509_cert_get_subject(hx509_cert p, hx509_name *name)
1339178825Sdfr{
1340178825Sdfr    return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1341178825Sdfr}
1342178825Sdfr
1343178825Sdfr/**
1344178825Sdfr * Return the name of the base subject of the hx509 certificate. If
1345178825Sdfr * the certiicate is a verified proxy certificate, the this function
1346178825Sdfr * return the base certificate (root of the proxy chain). If the proxy
1347178825Sdfr * certificate is not verified with the base certificate
1348178825Sdfr * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1349178825Sdfr *
1350178825Sdfr * @param context a hx509 context.
1351178825Sdfr * @param c a hx509 certificate object.
1352178825Sdfr * @param name a pointer to a hx509 name, should be freed by
1353178825Sdfr * hx509_name_free(). See also hx509_cert_get_subject().
1354178825Sdfr *
1355178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1356178825Sdfr *
1357178825Sdfr * @ingroup hx509_cert
1358178825Sdfr */
1359178825Sdfr
1360178825Sdfrint
1361178825Sdfrhx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1362178825Sdfr			    hx509_name *name)
1363178825Sdfr{
1364178825Sdfr    if (c->basename)
1365178825Sdfr	return hx509_name_copy(context, c->basename, name);
1366178825Sdfr    if (is_proxy_cert(context, c->data, NULL) == 0) {
1367178825Sdfr	int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1368178825Sdfr	hx509_set_error_string(context, 0, ret,
1369178825Sdfr			       "Proxy certificate have not been "
1370178825Sdfr			       "canonicalize yet, no base name");
1371178825Sdfr	return ret;
1372178825Sdfr    }
1373178825Sdfr    return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1374178825Sdfr}
1375178825Sdfr
1376178825Sdfr/**
1377178825Sdfr * Get serial number of the certificate.
1378178825Sdfr *
1379178825Sdfr * @param p a hx509 certificate object.
1380178825Sdfr * @param i serial number, should be freed ith der_free_heim_integer().
1381178825Sdfr *
1382178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1383178825Sdfr *
1384178825Sdfr * @ingroup hx509_cert
1385178825Sdfr */
1386178825Sdfr
1387178825Sdfrint
1388178825Sdfrhx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1389178825Sdfr{
1390178825Sdfr    return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1391178825Sdfr}
1392178825Sdfr
1393178825Sdfr/**
1394178825Sdfr * Get notBefore time of the certificate.
1395178825Sdfr *
1396178825Sdfr * @param p a hx509 certificate object.
1397178825Sdfr *
1398178825Sdfr * @return return not before time
1399178825Sdfr *
1400178825Sdfr * @ingroup hx509_cert
1401178825Sdfr */
1402178825Sdfr
1403178825Sdfrtime_t
1404178825Sdfrhx509_cert_get_notBefore(hx509_cert p)
1405178825Sdfr{
1406178825Sdfr    return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1407178825Sdfr}
1408178825Sdfr
1409178825Sdfr/**
1410178825Sdfr * Get notAfter time of the certificate.
1411178825Sdfr *
1412178825Sdfr * @param p a hx509 certificate object.
1413178825Sdfr *
1414178825Sdfr * @return return not after time.
1415178825Sdfr *
1416178825Sdfr * @ingroup hx509_cert
1417178825Sdfr */
1418178825Sdfr
1419178825Sdfrtime_t
1420178825Sdfrhx509_cert_get_notAfter(hx509_cert p)
1421178825Sdfr{
1422178825Sdfr    return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1423178825Sdfr}
1424178825Sdfr
1425178825Sdfr/**
1426178825Sdfr * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1427178825Sdfr *
1428178825Sdfr * @param context a hx509 context.
1429178825Sdfr * @param p a hx509 certificate object.
1430178825Sdfr * @param spki SubjectPublicKeyInfo, should be freed with
1431178825Sdfr * free_SubjectPublicKeyInfo().
1432178825Sdfr *
1433178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1434178825Sdfr *
1435178825Sdfr * @ingroup hx509_cert
1436178825Sdfr */
1437178825Sdfr
1438178825Sdfrint
1439178825Sdfrhx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1440178825Sdfr{
1441178825Sdfr    int ret;
1442178825Sdfr
1443178825Sdfr    ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1444178825Sdfr    if (ret)
1445178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1446178825Sdfr    return ret;
1447178825Sdfr}
1448178825Sdfr
1449178825Sdfr/**
1450178825Sdfr * Get the AlgorithmIdentifier from the hx509 certificate.
1451178825Sdfr *
1452178825Sdfr * @param context a hx509 context.
1453178825Sdfr * @param p a hx509 certificate object.
1454178825Sdfr * @param alg AlgorithmIdentifier, should be freed with
1455178825Sdfr * free_AlgorithmIdentifier().
1456178825Sdfr *
1457178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1458178825Sdfr *
1459178825Sdfr * @ingroup hx509_cert
1460178825Sdfr */
1461178825Sdfr
1462178825Sdfrint
1463178825Sdfrhx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1464178825Sdfr					hx509_cert p,
1465178825Sdfr					AlgorithmIdentifier *alg)
1466178825Sdfr{
1467178825Sdfr    int ret;
1468178825Sdfr
1469178825Sdfr    ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1470178825Sdfr    if (ret)
1471178825Sdfr	hx509_set_error_string(context, 0, ret,
1472178825Sdfr			       "Failed to copy SPKI AlgorithmIdentifier");
1473178825Sdfr    return ret;
1474178825Sdfr}
1475178825Sdfr
1476178825Sdfr
1477178825Sdfrhx509_private_key
1478178825Sdfr_hx509_cert_private_key(hx509_cert p)
1479178825Sdfr{
1480178825Sdfr    return p->private_key;
1481178825Sdfr}
1482178825Sdfr
1483178825Sdfrint
1484178825Sdfrhx509_cert_have_private_key(hx509_cert p)
1485178825Sdfr{
1486178825Sdfr    return p->private_key ? 1 : 0;
1487178825Sdfr}
1488178825Sdfr
1489178825Sdfr
1490178825Sdfrint
1491178825Sdfr_hx509_cert_private_key_exportable(hx509_cert p)
1492178825Sdfr{
1493178825Sdfr    if (p->private_key == NULL)
1494178825Sdfr	return 0;
1495178825Sdfr    return _hx509_private_key_exportable(p->private_key);
1496178825Sdfr}
1497178825Sdfr
1498178825Sdfrint
1499178825Sdfr_hx509_cert_private_decrypt(hx509_context context,
1500178825Sdfr			    const heim_octet_string *ciphertext,
1501178825Sdfr			    const heim_oid *encryption_oid,
1502178825Sdfr			    hx509_cert p,
1503178825Sdfr			    heim_octet_string *cleartext)
1504178825Sdfr{
1505178825Sdfr    cleartext->data = NULL;
1506178825Sdfr    cleartext->length = 0;
1507178825Sdfr
1508178825Sdfr    if (p->private_key == NULL) {
1509178825Sdfr	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1510178825Sdfr			       "Private key missing");
1511178825Sdfr	return HX509_PRIVATE_KEY_MISSING;
1512178825Sdfr    }
1513178825Sdfr
1514178825Sdfr    return _hx509_private_key_private_decrypt(context,
1515178825Sdfr					      ciphertext,
1516178825Sdfr					      encryption_oid,
1517178825Sdfr					      p->private_key,
1518178825Sdfr					      cleartext);
1519178825Sdfr}
1520178825Sdfr
1521178825Sdfrint
1522178825Sdfr_hx509_cert_public_encrypt(hx509_context context,
1523178825Sdfr			   const heim_octet_string *cleartext,
1524178825Sdfr			   const hx509_cert p,
1525178825Sdfr			   heim_oid *encryption_oid,
1526178825Sdfr			   heim_octet_string *ciphertext)
1527178825Sdfr{
1528178825Sdfr    return _hx509_public_encrypt(context,
1529178825Sdfr				 cleartext, p->data,
1530178825Sdfr				 encryption_oid, ciphertext);
1531178825Sdfr}
1532178825Sdfr
1533178825Sdfr/*
1534178825Sdfr *
1535178825Sdfr */
1536178825Sdfr
1537178825Sdfrtime_t
1538178825Sdfr_hx509_Time2time_t(const Time *t)
1539178825Sdfr{
1540178825Sdfr    switch(t->element) {
1541178825Sdfr    case choice_Time_utcTime:
1542178825Sdfr	return t->u.utcTime;
1543178825Sdfr    case choice_Time_generalTime:
1544178825Sdfr	return t->u.generalTime;
1545178825Sdfr    }
1546178825Sdfr    return 0;
1547178825Sdfr}
1548178825Sdfr
1549178825Sdfr/*
1550178825Sdfr *
1551178825Sdfr */
1552178825Sdfr
1553178825Sdfrstatic int
1554178825Sdfrinit_name_constraints(hx509_name_constraints *nc)
1555178825Sdfr{
1556178825Sdfr    memset(nc, 0, sizeof(*nc));
1557178825Sdfr    return 0;
1558178825Sdfr}
1559178825Sdfr
1560178825Sdfrstatic int
1561178825Sdfradd_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1562178825Sdfr		     hx509_name_constraints *nc)
1563178825Sdfr{
1564178825Sdfr    NameConstraints tnc;
1565178825Sdfr    int ret;
1566178825Sdfr
1567178825Sdfr    ret = find_extension_name_constraints(c, &tnc);
1568178825Sdfr    if (ret == HX509_EXTENSION_NOT_FOUND)
1569178825Sdfr	return 0;
1570178825Sdfr    else if (ret) {
1571178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1572178825Sdfr	return ret;
1573178825Sdfr    } else if (not_ca) {
1574178825Sdfr	ret = HX509_VERIFY_CONSTRAINTS;
1575178825Sdfr	hx509_set_error_string(context, 0, ret, "Not a CA and "
1576178825Sdfr			       "have NameConstraints");
1577178825Sdfr    } else {
1578178825Sdfr	NameConstraints *val;
1579178825Sdfr	val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1580178825Sdfr	if (val == NULL) {
1581178825Sdfr	    hx509_clear_error_string(context);
1582178825Sdfr	    ret = ENOMEM;
1583178825Sdfr	    goto out;
1584178825Sdfr	}
1585178825Sdfr	nc->val = val;
1586178825Sdfr	ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1587178825Sdfr	if (ret) {
1588178825Sdfr	    hx509_clear_error_string(context);
1589178825Sdfr	    goto out;
1590178825Sdfr	}
1591178825Sdfr	nc->len += 1;
1592178825Sdfr    }
1593178825Sdfrout:
1594178825Sdfr    free_NameConstraints(&tnc);
1595178825Sdfr    return ret;
1596178825Sdfr}
1597178825Sdfr
1598178825Sdfrstatic int
1599178825Sdfrmatch_RDN(const RelativeDistinguishedName *c,
1600178825Sdfr	  const RelativeDistinguishedName *n)
1601178825Sdfr{
1602178825Sdfr    int i;
1603178825Sdfr
1604178825Sdfr    if (c->len != n->len)
1605178825Sdfr	return HX509_NAME_CONSTRAINT_ERROR;
1606178825Sdfr
1607178825Sdfr    for (i = 0; i < n->len; i++) {
1608178825Sdfr	if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1609178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1610178825Sdfr	if (_hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value) != 0)
1611178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1612178825Sdfr    }
1613178825Sdfr    return 0;
1614178825Sdfr}
1615178825Sdfr
1616178825Sdfrstatic int
1617178825Sdfrmatch_X501Name(const Name *c, const Name *n)
1618178825Sdfr{
1619178825Sdfr    int i, ret;
1620178825Sdfr
1621178825Sdfr    if (c->element != choice_Name_rdnSequence
1622178825Sdfr	|| n->element != choice_Name_rdnSequence)
1623178825Sdfr	return 0;
1624178825Sdfr    if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1625178825Sdfr	return HX509_NAME_CONSTRAINT_ERROR;
1626178825Sdfr    for (i = 0; i < c->u.rdnSequence.len; i++) {
1627178825Sdfr	ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1628178825Sdfr	if (ret)
1629178825Sdfr	    return ret;
1630178825Sdfr    }
1631178825Sdfr    return 0;
1632178825Sdfr}
1633178825Sdfr
1634178825Sdfr
1635178825Sdfrstatic int
1636178825Sdfrmatch_general_name(const GeneralName *c, const GeneralName *n, int *match)
1637178825Sdfr{
1638178825Sdfr    /*
1639178825Sdfr     * Name constraints only apply to the same name type, see RFC3280,
1640178825Sdfr     * 4.2.1.11.
1641178825Sdfr     */
1642178825Sdfr    assert(c->element == n->element);
1643178825Sdfr
1644178825Sdfr    switch(c->element) {
1645178825Sdfr    case choice_GeneralName_otherName:
1646178825Sdfr	if (der_heim_oid_cmp(&c->u.otherName.type_id,
1647178825Sdfr			 &n->u.otherName.type_id) != 0)
1648178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1649178825Sdfr	if (heim_any_cmp(&c->u.otherName.value,
1650178825Sdfr			 &n->u.otherName.value) != 0)
1651178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1652178825Sdfr	*match = 1;
1653178825Sdfr	return 0;
1654178825Sdfr    case choice_GeneralName_rfc822Name: {
1655178825Sdfr	const char *s;
1656178825Sdfr	size_t len1, len2;
1657178825Sdfr	s = strchr(c->u.rfc822Name, '@');
1658178825Sdfr	if (s) {
1659178825Sdfr	    if (strcasecmp(c->u.rfc822Name, n->u.rfc822Name) != 0)
1660178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1661178825Sdfr	} else {
1662178825Sdfr	    s = strchr(n->u.rfc822Name, '@');
1663178825Sdfr	    if (s == NULL)
1664178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1665178825Sdfr	    len1 = strlen(c->u.rfc822Name);
1666178825Sdfr	    len2 = strlen(s + 1);
1667178825Sdfr	    if (len1 > len2)
1668178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1669178825Sdfr	    if (strcasecmp(s + 1 + len2 - len1, c->u.rfc822Name) != 0)
1670178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1671178825Sdfr	    if (len1 < len2 && s[len2 - len1 + 1] != '.')
1672178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1673178825Sdfr	}
1674178825Sdfr	*match = 1;
1675178825Sdfr	return 0;
1676178825Sdfr    }
1677178825Sdfr    case choice_GeneralName_dNSName: {
1678178825Sdfr	size_t lenc, lenn;
1679178825Sdfr
1680178825Sdfr	lenc = strlen(c->u.dNSName);
1681178825Sdfr	lenn = strlen(n->u.dNSName);
1682178825Sdfr	if (lenc > lenn)
1683178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1684178825Sdfr	if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0)
1685178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1686178825Sdfr	if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.')
1687178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1688178825Sdfr	*match = 1;
1689178825Sdfr	return 0;
1690178825Sdfr    }
1691178825Sdfr    case choice_GeneralName_directoryName: {
1692178825Sdfr	Name c_name, n_name;
1693178825Sdfr	int ret;
1694178825Sdfr
1695178825Sdfr	c_name._save.data = NULL;
1696178825Sdfr	c_name._save.length = 0;
1697178825Sdfr	c_name.element = c->u.directoryName.element;
1698178825Sdfr	c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1699178825Sdfr
1700178825Sdfr	n_name._save.data = NULL;
1701178825Sdfr	n_name._save.length = 0;
1702178825Sdfr	n_name.element = n->u.directoryName.element;
1703178825Sdfr	n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1704178825Sdfr
1705178825Sdfr	ret = match_X501Name(&c_name, &n_name);
1706178825Sdfr	if (ret == 0)
1707178825Sdfr	    *match = 1;
1708178825Sdfr	return ret;
1709178825Sdfr    }
1710178825Sdfr    case choice_GeneralName_uniformResourceIdentifier:
1711178825Sdfr    case choice_GeneralName_iPAddress:
1712178825Sdfr    case choice_GeneralName_registeredID:
1713178825Sdfr    default:
1714178825Sdfr	return HX509_NAME_CONSTRAINT_ERROR;
1715178825Sdfr    }
1716178825Sdfr}
1717178825Sdfr
1718178825Sdfrstatic int
1719178825Sdfrmatch_alt_name(const GeneralName *n, const Certificate *c,
1720178825Sdfr	       int *same, int *match)
1721178825Sdfr{
1722178825Sdfr    GeneralNames sa;
1723178825Sdfr    int ret, i, j;
1724178825Sdfr
1725178825Sdfr    i = 0;
1726178825Sdfr    do {
1727178825Sdfr	ret = find_extension_subject_alt_name(c, &i, &sa);
1728178825Sdfr	if (ret == HX509_EXTENSION_NOT_FOUND) {
1729178825Sdfr	    ret = 0;
1730178825Sdfr	    break;
1731178825Sdfr	} else if (ret != 0)
1732178825Sdfr	    break;
1733178825Sdfr
1734178825Sdfr	for (j = 0; j < sa.len; j++) {
1735178825Sdfr	    if (n->element == sa.val[j].element) {
1736178825Sdfr		*same = 1;
1737178825Sdfr		ret = match_general_name(n, &sa.val[j], match);
1738178825Sdfr	    }
1739178825Sdfr	}
1740178825Sdfr	free_GeneralNames(&sa);
1741178825Sdfr    } while (1);
1742178825Sdfr    return ret;
1743178825Sdfr}
1744178825Sdfr
1745178825Sdfr
1746178825Sdfrstatic int
1747178825Sdfrmatch_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1748178825Sdfr{
1749178825Sdfr    int name, alt_name, same;
1750178825Sdfr    unsigned int i;
1751178825Sdfr    int ret = 0;
1752178825Sdfr
1753178825Sdfr    name = alt_name = same = *match = 0;
1754178825Sdfr    for (i = 0; i < t->len; i++) {
1755178825Sdfr	if (t->val[i].minimum && t->val[i].maximum)
1756178825Sdfr	    return HX509_RANGE;
1757178825Sdfr
1758178825Sdfr	/*
1759178825Sdfr	 * If the constraint apply to directoryNames, test is with
1760178825Sdfr	 * subjectName of the certificate if the certificate have a
1761178825Sdfr	 * non-null (empty) subjectName.
1762178825Sdfr	 */
1763178825Sdfr
1764178825Sdfr	if (t->val[i].base.element == choice_GeneralName_directoryName
1765178825Sdfr	    && !subject_null_p(c))
1766178825Sdfr	{
1767178825Sdfr	    GeneralName certname;
1768178825Sdfr
1769178825Sdfr	    memset(&certname, 0, sizeof(certname));
1770178825Sdfr	    certname.element = choice_GeneralName_directoryName;
1771178825Sdfr	    certname.u.directoryName.element =
1772178825Sdfr		c->tbsCertificate.subject.element;
1773178825Sdfr	    certname.u.directoryName.u.rdnSequence =
1774178825Sdfr		c->tbsCertificate.subject.u.rdnSequence;
1775178825Sdfr
1776178825Sdfr	    ret = match_general_name(&t->val[i].base, &certname, &name);
1777178825Sdfr	}
1778178825Sdfr
1779178825Sdfr	/* Handle subjectAltNames, this is icky since they
1780178825Sdfr	 * restrictions only apply if the subjectAltName is of the
1781178825Sdfr	 * same type. So if there have been a match of type, require
1782178825Sdfr	 * altname to be set.
1783178825Sdfr	 */
1784178825Sdfr	ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1785178825Sdfr    }
1786178825Sdfr    if (name && (!same || alt_name))
1787178825Sdfr	*match = 1;
1788178825Sdfr    return ret;
1789178825Sdfr}
1790178825Sdfr
1791178825Sdfrstatic int
1792178825Sdfrcheck_name_constraints(hx509_context context,
1793178825Sdfr		       const hx509_name_constraints *nc,
1794178825Sdfr		       const Certificate *c)
1795178825Sdfr{
1796178825Sdfr    int match, ret;
1797178825Sdfr    int i;
1798178825Sdfr
1799178825Sdfr    for (i = 0 ; i < nc->len; i++) {
1800178825Sdfr	GeneralSubtrees gs;
1801178825Sdfr
1802178825Sdfr	if (nc->val[i].permittedSubtrees) {
1803178825Sdfr	    GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1804178825Sdfr	    ret = match_tree(&gs, c, &match);
1805178825Sdfr	    if (ret) {
1806178825Sdfr		hx509_clear_error_string(context);
1807178825Sdfr		return ret;
1808178825Sdfr	    }
1809178825Sdfr	    /* allow null subjectNames, they wont matches anything */
1810178825Sdfr	    if (match == 0 && !subject_null_p(c)) {
1811178825Sdfr		hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1812178825Sdfr				       "Error verify constraints, "
1813178825Sdfr				       "certificate didn't match any "
1814178825Sdfr				       "permitted subtree");
1815178825Sdfr		return HX509_VERIFY_CONSTRAINTS;
1816178825Sdfr	    }
1817178825Sdfr	}
1818178825Sdfr	if (nc->val[i].excludedSubtrees) {
1819178825Sdfr	    GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1820178825Sdfr	    ret = match_tree(&gs, c, &match);
1821178825Sdfr	    if (ret) {
1822178825Sdfr		hx509_clear_error_string(context);
1823178825Sdfr		return ret;
1824178825Sdfr	    }
1825178825Sdfr	    if (match) {
1826178825Sdfr		hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1827178825Sdfr				       "Error verify constraints, "
1828178825Sdfr				       "certificate included in excluded "
1829178825Sdfr				       "subtree");
1830178825Sdfr		return HX509_VERIFY_CONSTRAINTS;
1831178825Sdfr	    }
1832178825Sdfr	}
1833178825Sdfr    }
1834178825Sdfr    return 0;
1835178825Sdfr}
1836178825Sdfr
1837178825Sdfrstatic void
1838178825Sdfrfree_name_constraints(hx509_name_constraints *nc)
1839178825Sdfr{
1840178825Sdfr    int i;
1841178825Sdfr
1842178825Sdfr    for (i = 0 ; i < nc->len; i++)
1843178825Sdfr	free_NameConstraints(&nc->val[i]);
1844178825Sdfr    free(nc->val);
1845178825Sdfr}
1846178825Sdfr
1847178825Sdfr/**
1848178825Sdfr * Build and verify the path for the certificate to the trust anchor
1849178825Sdfr * specified in the verify context. The path is constructed from the
1850178825Sdfr * certificate, the pool and the trust anchors.
1851178825Sdfr *
1852178825Sdfr * @param context A hx509 context.
1853178825Sdfr * @param ctx A hx509 verification context.
1854178825Sdfr * @param cert the certificate to build the path from.
1855178825Sdfr * @param pool A keyset of certificates to build the chain from.
1856178825Sdfr *
1857178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1858178825Sdfr *
1859178825Sdfr * @ingroup hx509_verify
1860178825Sdfr */
1861178825Sdfr
1862178825Sdfrint
1863178825Sdfrhx509_verify_path(hx509_context context,
1864178825Sdfr		  hx509_verify_ctx ctx,
1865178825Sdfr		  hx509_cert cert,
1866178825Sdfr		  hx509_certs pool)
1867178825Sdfr{
1868178825Sdfr    hx509_name_constraints nc;
1869178825Sdfr    hx509_path path;
1870178825Sdfr#if 0
1871178825Sdfr    const AlgorithmIdentifier *alg_id;
1872178825Sdfr#endif
1873178825Sdfr    int ret, i, proxy_cert_depth, selfsigned_depth;
1874178825Sdfr    enum certtype type;
1875178825Sdfr    Name proxy_issuer;
1876178825Sdfr    hx509_certs anchors = NULL;
1877178825Sdfr
1878178825Sdfr    memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1879178825Sdfr
1880178825Sdfr    ret = init_name_constraints(&nc);
1881178825Sdfr    if (ret)
1882178825Sdfr	return ret;
1883178825Sdfr
1884178825Sdfr    path.val = NULL;
1885178825Sdfr    path.len = 0;
1886178825Sdfr
1887178825Sdfr    if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1888178825Sdfr	ctx->time_now = time(NULL);
1889178825Sdfr
1890178825Sdfr    /*
1891178825Sdfr     *
1892178825Sdfr     */
1893178825Sdfr    if (ctx->trust_anchors)
1894178825Sdfr	anchors = _hx509_certs_ref(ctx->trust_anchors);
1895178825Sdfr    else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
1896178825Sdfr	anchors = _hx509_certs_ref(context->default_trust_anchors);
1897178825Sdfr    else {
1898178825Sdfr	ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
1899178825Sdfr	if (ret)
1900178825Sdfr	    goto out;
1901178825Sdfr    }
1902178825Sdfr
1903178825Sdfr    /*
1904178825Sdfr     * Calculate the path from the certificate user presented to the
1905178825Sdfr     * to an anchor.
1906178825Sdfr     */
1907178825Sdfr    ret = _hx509_calculate_path(context, 0, ctx->time_now,
1908178825Sdfr				anchors, ctx->max_depth,
1909178825Sdfr				cert, pool, &path);
1910178825Sdfr    if (ret)
1911178825Sdfr	goto out;
1912178825Sdfr
1913178825Sdfr#if 0
1914178825Sdfr    alg_id = path.val[path->len - 1]->data->tbsCertificate.signature;
1915178825Sdfr#endif
1916178825Sdfr
1917178825Sdfr    /*
1918178825Sdfr     * Check CA and proxy certificate chain from the top of the
1919178825Sdfr     * certificate chain. Also check certificate is valid with respect
1920178825Sdfr     * to the current time.
1921178825Sdfr     *
1922178825Sdfr     */
1923178825Sdfr
1924178825Sdfr    proxy_cert_depth = 0;
1925178825Sdfr    selfsigned_depth = 0;
1926178825Sdfr
1927178825Sdfr    if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
1928178825Sdfr	type = PROXY_CERT;
1929178825Sdfr    else
1930178825Sdfr	type = EE_CERT;
1931178825Sdfr
1932178825Sdfr    for (i = 0; i < path.len; i++) {
1933178825Sdfr	Certificate *c;
1934178825Sdfr	time_t t;
1935178825Sdfr
1936178825Sdfr	c = _hx509_get_cert(path.val[i]);
1937178825Sdfr
1938178825Sdfr	/*
1939178825Sdfr	 * Lets do some basic check on issuer like
1940178825Sdfr	 * keyUsage.keyCertSign and basicConstraints.cA bit depending
1941178825Sdfr	 * on what type of certificate this is.
1942178825Sdfr	 */
1943178825Sdfr
1944178825Sdfr	switch (type) {
1945178825Sdfr	case CA_CERT:
1946178825Sdfr	    /* XXX make constants for keyusage */
1947178825Sdfr	    ret = check_key_usage(context, c, 1 << 5,
1948178825Sdfr				  REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
1949178825Sdfr	    if (ret) {
1950178825Sdfr		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1951178825Sdfr				       "Key usage missing from CA certificate");
1952178825Sdfr		goto out;
1953178825Sdfr	    }
1954178825Sdfr
1955178825Sdfr	    if (i + 1 != path.len && certificate_is_self_signed(c))
1956178825Sdfr		selfsigned_depth++;
1957178825Sdfr
1958178825Sdfr	    break;
1959178825Sdfr	case PROXY_CERT: {
1960178825Sdfr	    ProxyCertInfo info;
1961178825Sdfr
1962178825Sdfr	    if (is_proxy_cert(context, c, &info) == 0) {
1963178825Sdfr		int j;
1964178825Sdfr
1965178825Sdfr		if (info.pCPathLenConstraint != NULL &&
1966178825Sdfr		    *info.pCPathLenConstraint < i)
1967178825Sdfr		{
1968178825Sdfr		    free_ProxyCertInfo(&info);
1969178825Sdfr		    ret = HX509_PATH_TOO_LONG;
1970178825Sdfr		    hx509_set_error_string(context, 0, ret,
1971178825Sdfr					   "Proxy certificate chain "
1972178825Sdfr					   "longer then allowed");
1973178825Sdfr		    goto out;
1974178825Sdfr		}
1975178825Sdfr		/* XXX MUST check info.proxyPolicy */
1976178825Sdfr		free_ProxyCertInfo(&info);
1977178825Sdfr
1978178825Sdfr		j = 0;
1979178825Sdfr		if (find_extension(c, oid_id_x509_ce_subjectAltName(), &j)) {
1980178825Sdfr		    ret = HX509_PROXY_CERT_INVALID;
1981178825Sdfr		    hx509_set_error_string(context, 0, ret,
1982178825Sdfr					   "Proxy certificate have explicity "
1983178825Sdfr					   "forbidden subjectAltName");
1984178825Sdfr		    goto out;
1985178825Sdfr		}
1986178825Sdfr
1987178825Sdfr		j = 0;
1988178825Sdfr		if (find_extension(c, oid_id_x509_ce_issuerAltName(), &j)) {
1989178825Sdfr		    ret = HX509_PROXY_CERT_INVALID;
1990178825Sdfr		    hx509_set_error_string(context, 0, ret,
1991178825Sdfr					   "Proxy certificate have explicity "
1992178825Sdfr					   "forbidden issuerAltName");
1993178825Sdfr		    goto out;
1994178825Sdfr		}
1995178825Sdfr
1996178825Sdfr		/*
1997178825Sdfr		 * The subject name of the proxy certificate should be
1998178825Sdfr		 * CN=XXX,<proxy issuer>, prune of CN and check if its
1999178825Sdfr		 * the same over the whole chain of proxy certs and
2000178825Sdfr		 * then check with the EE cert when we get to it.
2001178825Sdfr		 */
2002178825Sdfr
2003178825Sdfr		if (proxy_cert_depth) {
2004178825Sdfr		    ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject);
2005178825Sdfr		    if (ret) {
2006178825Sdfr			ret = HX509_PROXY_CERT_NAME_WRONG;
2007178825Sdfr			hx509_set_error_string(context, 0, ret,
2008178825Sdfr					       "Base proxy name not right");
2009178825Sdfr			goto out;
2010178825Sdfr		    }
2011178825Sdfr		}
2012178825Sdfr
2013178825Sdfr		free_Name(&proxy_issuer);
2014178825Sdfr
2015178825Sdfr		ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2016178825Sdfr		if (ret) {
2017178825Sdfr		    hx509_clear_error_string(context);
2018178825Sdfr		    goto out;
2019178825Sdfr		}
2020178825Sdfr
2021178825Sdfr		j = proxy_issuer.u.rdnSequence.len;
2022178825Sdfr		if (proxy_issuer.u.rdnSequence.len < 2
2023178825Sdfr		    || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2024178825Sdfr		    || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2025178825Sdfr					oid_id_at_commonName()))
2026178825Sdfr		{
2027178825Sdfr		    ret = HX509_PROXY_CERT_NAME_WRONG;
2028178825Sdfr		    hx509_set_error_string(context, 0, ret,
2029178825Sdfr					   "Proxy name too short or "
2030178825Sdfr					   "does not have Common name "
2031178825Sdfr					   "at the top");
2032178825Sdfr		    goto out;
2033178825Sdfr		}
2034178825Sdfr
2035178825Sdfr		free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2036178825Sdfr		proxy_issuer.u.rdnSequence.len -= 1;
2037178825Sdfr
2038178825Sdfr		ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer);
2039178825Sdfr		if (ret != 0) {
2040178825Sdfr		    ret = HX509_PROXY_CERT_NAME_WRONG;
2041178825Sdfr		    hx509_set_error_string(context, 0, ret,
2042178825Sdfr					   "Proxy issuer name not as expected");
2043178825Sdfr		    goto out;
2044178825Sdfr		}
2045178825Sdfr
2046178825Sdfr		break;
2047178825Sdfr	    } else {
2048178825Sdfr		/*
2049178825Sdfr		 * Now we are done with the proxy certificates, this
2050178825Sdfr		 * cert was an EE cert and we we will fall though to
2051178825Sdfr		 * EE checking below.
2052178825Sdfr		 */
2053178825Sdfr		type = EE_CERT;
2054178825Sdfr		/* FALLTHOUGH */
2055178825Sdfr	    }
2056178825Sdfr	}
2057178825Sdfr	case EE_CERT:
2058178825Sdfr	    /*
2059178825Sdfr	     * If there where any proxy certificates in the chain
2060178825Sdfr	     * (proxy_cert_depth > 0), check that the proxy issuer
2061178825Sdfr	     * matched proxy certificates "base" subject.
2062178825Sdfr	     */
2063178825Sdfr	    if (proxy_cert_depth) {
2064178825Sdfr
2065178825Sdfr		ret = _hx509_name_cmp(&proxy_issuer,
2066178825Sdfr				      &c->tbsCertificate.subject);
2067178825Sdfr		if (ret) {
2068178825Sdfr		    ret = HX509_PROXY_CERT_NAME_WRONG;
2069178825Sdfr		    hx509_clear_error_string(context);
2070178825Sdfr		    goto out;
2071178825Sdfr		}
2072178825Sdfr		if (cert->basename)
2073178825Sdfr		    hx509_name_free(&cert->basename);
2074178825Sdfr
2075178825Sdfr		ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2076178825Sdfr		if (ret) {
2077178825Sdfr		    hx509_clear_error_string(context);
2078178825Sdfr		    goto out;
2079178825Sdfr		}
2080178825Sdfr	    }
2081178825Sdfr
2082178825Sdfr	    break;
2083178825Sdfr	}
2084178825Sdfr
2085178825Sdfr	ret = check_basic_constraints(context, c, type,
2086178825Sdfr				      i - proxy_cert_depth - selfsigned_depth);
2087178825Sdfr	if (ret)
2088178825Sdfr	    goto out;
2089178825Sdfr
2090178825Sdfr	/*
2091178825Sdfr	 * Don't check the trust anchors expiration time since they
2092178825Sdfr	 * are transported out of band, from RFC3820.
2093178825Sdfr	 */
2094178825Sdfr	if (i + 1 != path.len || CHECK_TA(ctx)) {
2095178825Sdfr
2096178825Sdfr	    t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2097178825Sdfr	    if (t > ctx->time_now) {
2098178825Sdfr		ret = HX509_CERT_USED_BEFORE_TIME;
2099178825Sdfr		hx509_clear_error_string(context);
2100178825Sdfr		goto out;
2101178825Sdfr	    }
2102178825Sdfr	    t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2103178825Sdfr	    if (t < ctx->time_now) {
2104178825Sdfr		ret = HX509_CERT_USED_AFTER_TIME;
2105178825Sdfr		hx509_clear_error_string(context);
2106178825Sdfr		goto out;
2107178825Sdfr	    }
2108178825Sdfr	}
2109178825Sdfr
2110178825Sdfr	if (type == EE_CERT)
2111178825Sdfr	    type = CA_CERT;
2112178825Sdfr	else if (type == PROXY_CERT)
2113178825Sdfr	    proxy_cert_depth++;
2114178825Sdfr    }
2115178825Sdfr
2116178825Sdfr    /*
2117178825Sdfr     * Verify constraints, do this backward so path constraints are
2118178825Sdfr     * checked in the right order.
2119178825Sdfr     */
2120178825Sdfr
2121178825Sdfr    for (ret = 0, i = path.len - 1; i >= 0; i--) {
2122178825Sdfr	Certificate *c;
2123178825Sdfr
2124178825Sdfr	c = _hx509_get_cert(path.val[i]);
2125178825Sdfr
2126178825Sdfr	/* verify name constraints, not for selfsigned and anchor */
2127178825Sdfr	if (!certificate_is_self_signed(c) || i + 1 != path.len) {
2128178825Sdfr	    ret = check_name_constraints(context, &nc, c);
2129178825Sdfr	    if (ret) {
2130178825Sdfr		goto out;
2131178825Sdfr	    }
2132178825Sdfr	}
2133178825Sdfr	ret = add_name_constraints(context, c, i == 0, &nc);
2134178825Sdfr	if (ret)
2135178825Sdfr	    goto out;
2136178825Sdfr
2137178825Sdfr	/* XXX verify all other silly constraints */
2138178825Sdfr
2139178825Sdfr    }
2140178825Sdfr
2141178825Sdfr    /*
2142178825Sdfr     * Verify that no certificates has been revoked.
2143178825Sdfr     */
2144178825Sdfr
2145178825Sdfr    if (ctx->revoke_ctx) {
2146178825Sdfr	hx509_certs certs;
2147178825Sdfr
2148178825Sdfr	ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2149178825Sdfr			       NULL, &certs);
2150178825Sdfr	if (ret)
2151178825Sdfr	    goto out;
2152178825Sdfr
2153178825Sdfr	for (i = 0; i < path.len; i++) {
2154178825Sdfr	    ret = hx509_certs_add(context, certs, path.val[i]);
2155178825Sdfr	    if (ret) {
2156178825Sdfr		hx509_certs_free(&certs);
2157178825Sdfr		goto out;
2158178825Sdfr	    }
2159178825Sdfr	}
2160178825Sdfr	ret = hx509_certs_merge(context, certs, pool);
2161178825Sdfr	if (ret) {
2162178825Sdfr	    hx509_certs_free(&certs);
2163178825Sdfr	    goto out;
2164178825Sdfr	}
2165178825Sdfr
2166178825Sdfr	for (i = 0; i < path.len - 1; i++) {
2167178825Sdfr	    int parent = (i < path.len - 1) ? i + 1 : i;
2168178825Sdfr
2169178825Sdfr	    ret = hx509_revoke_verify(context,
2170178825Sdfr				      ctx->revoke_ctx,
2171178825Sdfr				      certs,
2172178825Sdfr				      ctx->time_now,
2173178825Sdfr				      path.val[i],
2174178825Sdfr				      path.val[parent]);
2175178825Sdfr	    if (ret) {
2176178825Sdfr		hx509_certs_free(&certs);
2177178825Sdfr		goto out;
2178178825Sdfr	    }
2179178825Sdfr	}
2180178825Sdfr	hx509_certs_free(&certs);
2181178825Sdfr    }
2182178825Sdfr
2183178825Sdfr    /*
2184178825Sdfr     * Verify signatures, do this backward so public key working
2185178825Sdfr     * parameter is passed up from the anchor up though the chain.
2186178825Sdfr     */
2187178825Sdfr
2188178825Sdfr    for (i = path.len - 1; i >= 0; i--) {
2189178825Sdfr	Certificate *signer, *c;
2190178825Sdfr
2191178825Sdfr	c = _hx509_get_cert(path.val[i]);
2192178825Sdfr
2193178825Sdfr	/* is last in chain (trust anchor) */
2194178825Sdfr	if (i + 1 == path.len) {
2195178825Sdfr	    signer = path.val[i]->data;
2196178825Sdfr
2197178825Sdfr	    /* if trust anchor is not self signed, don't check sig */
2198178825Sdfr	    if (!certificate_is_self_signed(signer))
2199178825Sdfr		continue;
2200178825Sdfr	} else {
2201178825Sdfr	    /* take next certificate in chain */
2202178825Sdfr	    signer = path.val[i + 1]->data;
2203178825Sdfr	}
2204178825Sdfr
2205178825Sdfr	/* verify signatureValue */
2206178825Sdfr	ret = _hx509_verify_signature_bitstring(context,
2207178825Sdfr						signer,
2208178825Sdfr						&c->signatureAlgorithm,
2209178825Sdfr						&c->tbsCertificate._save,
2210178825Sdfr						&c->signatureValue);
2211178825Sdfr	if (ret) {
2212178825Sdfr	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2213178825Sdfr				   "Failed to verify signature of certificate");
2214178825Sdfr	    goto out;
2215178825Sdfr	}
2216178825Sdfr    }
2217178825Sdfr
2218178825Sdfrout:
2219178825Sdfr    hx509_certs_free(&anchors);
2220178825Sdfr    free_Name(&proxy_issuer);
2221178825Sdfr    free_name_constraints(&nc);
2222178825Sdfr    _hx509_path_free(&path);
2223178825Sdfr
2224178825Sdfr    return ret;
2225178825Sdfr}
2226178825Sdfr
2227178825Sdfr/**
2228178825Sdfr * Verify a signature made using the private key of an certificate.
2229178825Sdfr *
2230178825Sdfr * @param context A hx509 context.
2231178825Sdfr * @param signer the certificate that made the signature.
2232178825Sdfr * @param alg algorthm that was used to sign the data.
2233178825Sdfr * @param data the data that was signed.
2234178825Sdfr * @param sig the sigature to verify.
2235178825Sdfr *
2236178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2237178825Sdfr *
2238178825Sdfr * @ingroup hx509_crypto
2239178825Sdfr */
2240178825Sdfr
2241178825Sdfrint
2242178825Sdfrhx509_verify_signature(hx509_context context,
2243178825Sdfr		       const hx509_cert signer,
2244178825Sdfr		       const AlgorithmIdentifier *alg,
2245178825Sdfr		       const heim_octet_string *data,
2246178825Sdfr		       const heim_octet_string *sig)
2247178825Sdfr{
2248178825Sdfr    return _hx509_verify_signature(context, signer->data, alg, data, sig);
2249178825Sdfr}
2250178825Sdfr
2251178825Sdfr
2252178825Sdfr/**
2253178825Sdfr * Verify that the certificate is allowed to be used for the hostname
2254178825Sdfr * and address.
2255178825Sdfr *
2256178825Sdfr * @param context A hx509 context.
2257178825Sdfr * @param cert the certificate to match with
2258178825Sdfr * @param flags Flags to modify the behavior:
2259178825Sdfr * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2260178825Sdfr * @param type type of hostname:
2261178825Sdfr * - HX509_HN_HOSTNAME for plain hostname.
2262178825Sdfr * - HX509_HN_DNSSRV for DNS SRV names.
2263178825Sdfr * @param hostname the hostname to check
2264178825Sdfr * @param sa address of the host
2265178825Sdfr * @param sa_size length of address
2266178825Sdfr *
2267178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2268178825Sdfr *
2269178825Sdfr * @ingroup hx509_cert
2270178825Sdfr */
2271178825Sdfr
2272178825Sdfrint
2273178825Sdfrhx509_verify_hostname(hx509_context context,
2274178825Sdfr		      const hx509_cert cert,
2275178825Sdfr		      int flags,
2276178825Sdfr		      hx509_hostname_type type,
2277178825Sdfr		      const char *hostname,
2278178825Sdfr		      const struct sockaddr *sa,
2279178825Sdfr		      /* XXX krb5_socklen_t */ int sa_size)
2280178825Sdfr{
2281178825Sdfr    GeneralNames san;
2282178825Sdfr    int ret, i, j;
2283178825Sdfr
2284178825Sdfr    if (sa && sa_size <= 0)
2285178825Sdfr	return EINVAL;
2286178825Sdfr
2287178825Sdfr    memset(&san, 0, sizeof(san));
2288178825Sdfr
2289178825Sdfr    i = 0;
2290178825Sdfr    do {
2291178825Sdfr	ret = find_extension_subject_alt_name(cert->data, &i, &san);
2292178825Sdfr	if (ret == HX509_EXTENSION_NOT_FOUND) {
2293178825Sdfr	    ret = 0;
2294178825Sdfr	    break;
2295178825Sdfr	} else if (ret != 0)
2296178825Sdfr	    break;
2297178825Sdfr
2298178825Sdfr	for (j = 0; j < san.len; j++) {
2299178825Sdfr	    switch (san.val[j].element) {
2300178825Sdfr	    case choice_GeneralName_dNSName:
2301178825Sdfr		if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) {
2302178825Sdfr		    free_GeneralNames(&san);
2303178825Sdfr		    return 0;
2304178825Sdfr		}
2305178825Sdfr		break;
2306178825Sdfr	    default:
2307178825Sdfr		break;
2308178825Sdfr	    }
2309178825Sdfr	}
2310178825Sdfr	free_GeneralNames(&san);
2311178825Sdfr    } while (1);
2312178825Sdfr
2313178825Sdfr    {
2314178825Sdfr	Name *name = &cert->data->tbsCertificate.subject;
2315178825Sdfr
2316178825Sdfr	/* match if first component is a CN= */
2317178825Sdfr	if (name->u.rdnSequence.len > 0
2318178825Sdfr	    && name->u.rdnSequence.val[0].len == 1
2319178825Sdfr	    && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type,
2320178825Sdfr				oid_id_at_commonName()) == 0)
2321178825Sdfr	{
2322178825Sdfr	    DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value;
2323178825Sdfr
2324178825Sdfr	    switch (ds->element) {
2325178825Sdfr	    case choice_DirectoryString_printableString:
2326178825Sdfr		if (strcasecmp(ds->u.printableString, hostname) == 0)
2327178825Sdfr		    return 0;
2328178825Sdfr		break;
2329178825Sdfr	    case choice_DirectoryString_ia5String:
2330178825Sdfr		if (strcasecmp(ds->u.ia5String, hostname) == 0)
2331178825Sdfr		    return 0;
2332178825Sdfr		break;
2333178825Sdfr	    case choice_DirectoryString_utf8String:
2334178825Sdfr		if (strcasecmp(ds->u.utf8String, hostname) == 0)
2335178825Sdfr		    return 0;
2336178825Sdfr	    default:
2337178825Sdfr		break;
2338178825Sdfr	    }
2339178825Sdfr	}
2340178825Sdfr    }
2341178825Sdfr
2342178825Sdfr    if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2343178825Sdfr	ret = HX509_NAME_CONSTRAINT_ERROR;
2344178825Sdfr
2345178825Sdfr    return ret;
2346178825Sdfr}
2347178825Sdfr
2348178825Sdfrint
2349178825Sdfr_hx509_set_cert_attribute(hx509_context context,
2350178825Sdfr			  hx509_cert cert,
2351178825Sdfr			  const heim_oid *oid,
2352178825Sdfr			  const heim_octet_string *attr)
2353178825Sdfr{
2354178825Sdfr    hx509_cert_attribute a;
2355178825Sdfr    void *d;
2356178825Sdfr
2357178825Sdfr    if (hx509_cert_get_attribute(cert, oid) != NULL)
2358178825Sdfr	return 0;
2359178825Sdfr
2360178825Sdfr    d = realloc(cert->attrs.val,
2361178825Sdfr		sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2362178825Sdfr    if (d == NULL) {
2363178825Sdfr	hx509_clear_error_string(context);
2364178825Sdfr	return ENOMEM;
2365178825Sdfr    }
2366178825Sdfr    cert->attrs.val = d;
2367178825Sdfr
2368178825Sdfr    a = malloc(sizeof(*a));
2369178825Sdfr    if (a == NULL)
2370178825Sdfr	return ENOMEM;
2371178825Sdfr
2372178825Sdfr    der_copy_octet_string(attr, &a->data);
2373178825Sdfr    der_copy_oid(oid, &a->oid);
2374178825Sdfr
2375178825Sdfr    cert->attrs.val[cert->attrs.len] = a;
2376178825Sdfr    cert->attrs.len++;
2377178825Sdfr
2378178825Sdfr    return 0;
2379178825Sdfr}
2380178825Sdfr
2381178825Sdfr/**
2382178825Sdfr * Get an external attribute for the certificate, examples are
2383178825Sdfr * friendly name and id.
2384178825Sdfr *
2385178825Sdfr * @param cert hx509 certificate object to search
2386178825Sdfr * @param oid an oid to search for.
2387178825Sdfr *
2388178825Sdfr * @return an hx509_cert_attribute, only valid as long as the
2389178825Sdfr * certificate is referenced.
2390178825Sdfr *
2391178825Sdfr * @ingroup hx509_cert
2392178825Sdfr */
2393178825Sdfr
2394178825Sdfrhx509_cert_attribute
2395178825Sdfrhx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2396178825Sdfr{
2397178825Sdfr    int i;
2398178825Sdfr    for (i = 0; i < cert->attrs.len; i++)
2399178825Sdfr	if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2400178825Sdfr	    return cert->attrs.val[i];
2401178825Sdfr    return NULL;
2402178825Sdfr}
2403178825Sdfr
2404178825Sdfr/**
2405178825Sdfr * Set the friendly name on the certificate.
2406178825Sdfr *
2407178825Sdfr * @param cert The certificate to set the friendly name on
2408178825Sdfr * @param name Friendly name.
2409178825Sdfr *
2410178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2411178825Sdfr *
2412178825Sdfr * @ingroup hx509_cert
2413178825Sdfr */
2414178825Sdfr
2415178825Sdfrint
2416178825Sdfrhx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2417178825Sdfr{
2418178825Sdfr    if (cert->friendlyname)
2419178825Sdfr	free(cert->friendlyname);
2420178825Sdfr    cert->friendlyname = strdup(name);
2421178825Sdfr    if (cert->friendlyname == NULL)
2422178825Sdfr	return ENOMEM;
2423178825Sdfr    return 0;
2424178825Sdfr}
2425178825Sdfr
2426178825Sdfr/**
2427178825Sdfr * Get friendly name of the certificate.
2428178825Sdfr *
2429178825Sdfr * @param cert cert to get the friendly name from.
2430178825Sdfr *
2431178825Sdfr * @return an friendly name or NULL if there is. The friendly name is
2432178825Sdfr * only valid as long as the certificate is referenced.
2433178825Sdfr *
2434178825Sdfr * @ingroup hx509_cert
2435178825Sdfr */
2436178825Sdfr
2437178825Sdfrconst char *
2438178825Sdfrhx509_cert_get_friendly_name(hx509_cert cert)
2439178825Sdfr{
2440178825Sdfr    hx509_cert_attribute a;
2441178825Sdfr    PKCS9_friendlyName n;
2442178825Sdfr    size_t sz;
2443178825Sdfr    int ret, i;
2444178825Sdfr
2445178825Sdfr    if (cert->friendlyname)
2446178825Sdfr	return cert->friendlyname;
2447178825Sdfr
2448178825Sdfr    a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_friendlyName());
2449178825Sdfr    if (a == NULL) {
2450178825Sdfr	/* XXX use subject name ? */
2451178825Sdfr	return NULL;
2452178825Sdfr    }
2453178825Sdfr
2454178825Sdfr    ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2455178825Sdfr    if (ret)
2456178825Sdfr	return NULL;
2457178825Sdfr
2458178825Sdfr    if (n.len != 1) {
2459178825Sdfr	free_PKCS9_friendlyName(&n);
2460178825Sdfr	return NULL;
2461178825Sdfr    }
2462178825Sdfr
2463178825Sdfr    cert->friendlyname = malloc(n.val[0].length + 1);
2464178825Sdfr    if (cert->friendlyname == NULL) {
2465178825Sdfr	free_PKCS9_friendlyName(&n);
2466178825Sdfr	return NULL;
2467178825Sdfr    }
2468178825Sdfr
2469178825Sdfr    for (i = 0; i < n.val[0].length; i++) {
2470178825Sdfr	if (n.val[0].data[i] <= 0xff)
2471178825Sdfr	    cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2472178825Sdfr	else
2473178825Sdfr	    cert->friendlyname[i] = 'X';
2474178825Sdfr    }
2475178825Sdfr    cert->friendlyname[i] = '\0';
2476178825Sdfr    free_PKCS9_friendlyName(&n);
2477178825Sdfr
2478178825Sdfr    return cert->friendlyname;
2479178825Sdfr}
2480178825Sdfr
2481178825Sdfrvoid
2482178825Sdfr_hx509_query_clear(hx509_query *q)
2483178825Sdfr{
2484178825Sdfr    memset(q, 0, sizeof(*q));
2485178825Sdfr}
2486178825Sdfr
2487178825Sdfr/**
2488178825Sdfr * Allocate an query controller. Free using hx509_query_free().
2489178825Sdfr *
2490178825Sdfr * @param context A hx509 context.
2491178825Sdfr * @param q return pointer to a hx509_query.
2492178825Sdfr *
2493178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2494178825Sdfr *
2495178825Sdfr * @ingroup hx509_cert
2496178825Sdfr */
2497178825Sdfr
2498178825Sdfrint
2499178825Sdfrhx509_query_alloc(hx509_context context, hx509_query **q)
2500178825Sdfr{
2501178825Sdfr    *q = calloc(1, sizeof(**q));
2502178825Sdfr    if (*q == NULL)
2503178825Sdfr	return ENOMEM;
2504178825Sdfr    return 0;
2505178825Sdfr}
2506178825Sdfr
2507178825Sdfr/**
2508178825Sdfr * Set match options for the hx509 query controller.
2509178825Sdfr *
2510178825Sdfr * @param q query controller.
2511178825Sdfr * @param option options to control the query controller.
2512178825Sdfr *
2513178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2514178825Sdfr *
2515178825Sdfr * @ingroup hx509_cert
2516178825Sdfr */
2517178825Sdfr
2518178825Sdfrvoid
2519178825Sdfrhx509_query_match_option(hx509_query *q, hx509_query_option option)
2520178825Sdfr{
2521178825Sdfr    switch(option) {
2522178825Sdfr    case HX509_QUERY_OPTION_PRIVATE_KEY:
2523178825Sdfr	q->match |= HX509_QUERY_PRIVATE_KEY;
2524178825Sdfr	break;
2525178825Sdfr    case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2526178825Sdfr	q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2527178825Sdfr	break;
2528178825Sdfr    case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2529178825Sdfr	q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2530178825Sdfr	break;
2531178825Sdfr    case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2532178825Sdfr	q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2533178825Sdfr	break;
2534178825Sdfr    case HX509_QUERY_OPTION_END:
2535178825Sdfr    default:
2536178825Sdfr	break;
2537178825Sdfr    }
2538178825Sdfr}
2539178825Sdfr
2540178825Sdfr/**
2541178825Sdfr * Set the issuer and serial number of match in the query
2542178825Sdfr * controller. The function make copies of the isser and serial number.
2543178825Sdfr *
2544178825Sdfr * @param q a hx509 query controller
2545178825Sdfr * @param issuer issuer to search for
2546178825Sdfr * @param serialNumber the serialNumber of the issuer.
2547178825Sdfr *
2548178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2549178825Sdfr *
2550178825Sdfr * @ingroup hx509_cert
2551178825Sdfr */
2552178825Sdfr
2553178825Sdfrint
2554178825Sdfrhx509_query_match_issuer_serial(hx509_query *q,
2555178825Sdfr				const Name *issuer,
2556178825Sdfr				const heim_integer *serialNumber)
2557178825Sdfr{
2558178825Sdfr    int ret;
2559178825Sdfr    if (q->serial) {
2560178825Sdfr	der_free_heim_integer(q->serial);
2561178825Sdfr	free(q->serial);
2562178825Sdfr    }
2563178825Sdfr    q->serial = malloc(sizeof(*q->serial));
2564178825Sdfr    if (q->serial == NULL)
2565178825Sdfr	return ENOMEM;
2566178825Sdfr    ret = der_copy_heim_integer(serialNumber, q->serial);
2567178825Sdfr    if (ret) {
2568178825Sdfr	free(q->serial);
2569178825Sdfr	q->serial = NULL;
2570178825Sdfr	return ret;
2571178825Sdfr    }
2572178825Sdfr    if (q->issuer_name) {
2573178825Sdfr	free_Name(q->issuer_name);
2574178825Sdfr	free(q->issuer_name);
2575178825Sdfr    }
2576178825Sdfr    q->issuer_name = malloc(sizeof(*q->issuer_name));
2577178825Sdfr    if (q->issuer_name == NULL)
2578178825Sdfr	return ENOMEM;
2579178825Sdfr    ret = copy_Name(issuer, q->issuer_name);
2580178825Sdfr    if (ret) {
2581178825Sdfr	free(q->issuer_name);
2582178825Sdfr	q->issuer_name = NULL;
2583178825Sdfr	return ret;
2584178825Sdfr    }
2585178825Sdfr    q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2586178825Sdfr    return 0;
2587178825Sdfr}
2588178825Sdfr
2589178825Sdfr/**
2590178825Sdfr * Set the query controller to match on a friendly name
2591178825Sdfr *
2592178825Sdfr * @param q a hx509 query controller.
2593178825Sdfr * @param name a friendly name to match on
2594178825Sdfr *
2595178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2596178825Sdfr *
2597178825Sdfr * @ingroup hx509_cert
2598178825Sdfr */
2599178825Sdfr
2600178825Sdfrint
2601178825Sdfrhx509_query_match_friendly_name(hx509_query *q, const char *name)
2602178825Sdfr{
2603178825Sdfr    if (q->friendlyname)
2604178825Sdfr	free(q->friendlyname);
2605178825Sdfr    q->friendlyname = strdup(name);
2606178825Sdfr    if (q->friendlyname == NULL)
2607178825Sdfr	return ENOMEM;
2608178825Sdfr    q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2609178825Sdfr    return 0;
2610178825Sdfr}
2611178825Sdfr
2612178825Sdfr/**
2613178825Sdfr * Set the query controller to match using a specific match function.
2614178825Sdfr *
2615178825Sdfr * @param q a hx509 query controller.
2616178825Sdfr * @param func function to use for matching, if the argument is NULL,
2617178825Sdfr * the match function is removed.
2618178825Sdfr * @param ctx context passed to the function.
2619178825Sdfr *
2620178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2621178825Sdfr *
2622178825Sdfr * @ingroup hx509_cert
2623178825Sdfr */
2624178825Sdfr
2625178825Sdfrint
2626178825Sdfrhx509_query_match_cmp_func(hx509_query *q,
2627178825Sdfr			   int (*func)(void *, hx509_cert),
2628178825Sdfr			   void *ctx)
2629178825Sdfr{
2630178825Sdfr    if (func)
2631178825Sdfr	q->match |= HX509_QUERY_MATCH_FUNCTION;
2632178825Sdfr    else
2633178825Sdfr	q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2634178825Sdfr    q->cmp_func = func;
2635178825Sdfr    q->cmp_func_ctx = ctx;
2636178825Sdfr    return 0;
2637178825Sdfr}
2638178825Sdfr
2639178825Sdfr/**
2640178825Sdfr * Free the query controller.
2641178825Sdfr *
2642178825Sdfr * @param context A hx509 context.
2643178825Sdfr * @param q a pointer to the query controller.
2644178825Sdfr *
2645178825Sdfr * @ingroup hx509_cert
2646178825Sdfr */
2647178825Sdfr
2648178825Sdfrvoid
2649178825Sdfrhx509_query_free(hx509_context context, hx509_query *q)
2650178825Sdfr{
2651178825Sdfr    if (q->serial) {
2652178825Sdfr	der_free_heim_integer(q->serial);
2653178825Sdfr	free(q->serial);
2654178825Sdfr	q->serial = NULL;
2655178825Sdfr    }
2656178825Sdfr    if (q->issuer_name) {
2657178825Sdfr	free_Name(q->issuer_name);
2658178825Sdfr	free(q->issuer_name);
2659178825Sdfr	q->issuer_name = NULL;
2660178825Sdfr    }
2661178825Sdfr    if (q) {
2662178825Sdfr	free(q->friendlyname);
2663178825Sdfr	memset(q, 0, sizeof(*q));
2664178825Sdfr    }
2665178825Sdfr    free(q);
2666178825Sdfr}
2667178825Sdfr
2668178825Sdfrint
2669178825Sdfr_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2670178825Sdfr{
2671178825Sdfr    Certificate *c = _hx509_get_cert(cert);
2672178825Sdfr
2673178825Sdfr    _hx509_query_statistic(context, 1, q);
2674178825Sdfr
2675178825Sdfr    if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2676178825Sdfr	_hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2677178825Sdfr	return 0;
2678178825Sdfr
2679178825Sdfr    if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2680178825Sdfr	_hx509_Certificate_cmp(q->certificate, c) != 0)
2681178825Sdfr	return 0;
2682178825Sdfr
2683178825Sdfr    if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2684178825Sdfr	&& der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2685178825Sdfr	return 0;
2686178825Sdfr
2687178825Sdfr    if ((q->match & HX509_QUERY_MATCH_ISSUER_NAME)
2688178825Sdfr	&& _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name) != 0)
2689178825Sdfr	return 0;
2690178825Sdfr
2691178825Sdfr    if ((q->match & HX509_QUERY_MATCH_SUBJECT_NAME)
2692178825Sdfr	&& _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name) != 0)
2693178825Sdfr	return 0;
2694178825Sdfr
2695178825Sdfr    if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2696178825Sdfr	SubjectKeyIdentifier si;
2697178825Sdfr	int ret;
2698178825Sdfr
2699178825Sdfr	ret = _hx509_find_extension_subject_key_id(c, &si);
2700178825Sdfr	if (ret == 0) {
2701178825Sdfr	    if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2702178825Sdfr		ret = 1;
2703178825Sdfr	    free_SubjectKeyIdentifier(&si);
2704178825Sdfr	}
2705178825Sdfr	if (ret)
2706178825Sdfr	    return 0;
2707178825Sdfr    }
2708178825Sdfr    if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2709178825Sdfr	return 0;
2710178825Sdfr    if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2711178825Sdfr	_hx509_cert_private_key(cert) == NULL)
2712178825Sdfr	return 0;
2713178825Sdfr
2714178825Sdfr    {
2715178825Sdfr	unsigned ku = 0;
2716178825Sdfr	if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2717178825Sdfr	    ku |= (1 << 0);
2718178825Sdfr	if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2719178825Sdfr	    ku |= (1 << 1);
2720178825Sdfr	if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
2721178825Sdfr	    ku |= (1 << 2);
2722178825Sdfr	if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
2723178825Sdfr	    ku |= (1 << 3);
2724178825Sdfr	if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
2725178825Sdfr	    ku |= (1 << 4);
2726178825Sdfr	if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
2727178825Sdfr	    ku |= (1 << 5);
2728178825Sdfr	if (q->match & HX509_QUERY_KU_CRLSIGN)
2729178825Sdfr	    ku |= (1 << 6);
2730178825Sdfr	if (ku && check_key_usage(context, c, ku, TRUE))
2731178825Sdfr	    return 0;
2732178825Sdfr    }
2733178825Sdfr    if ((q->match & HX509_QUERY_ANCHOR))
2734178825Sdfr	return 0;
2735178825Sdfr
2736178825Sdfr    if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
2737178825Sdfr	hx509_cert_attribute a;
2738178825Sdfr
2739178825Sdfr	a = hx509_cert_get_attribute(cert, oid_id_pkcs_9_at_localKeyId());
2740178825Sdfr	if (a == NULL)
2741178825Sdfr	    return 0;
2742178825Sdfr	if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
2743178825Sdfr	    return 0;
2744178825Sdfr    }
2745178825Sdfr
2746178825Sdfr    if (q->match & HX509_QUERY_NO_MATCH_PATH) {
2747178825Sdfr	size_t i;
2748178825Sdfr
2749178825Sdfr	for (i = 0; i < q->path->len; i++)
2750178825Sdfr	    if (hx509_cert_cmp(q->path->val[i], cert) == 0)
2751178825Sdfr		return 0;
2752178825Sdfr    }
2753178825Sdfr    if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
2754178825Sdfr	const char *name = hx509_cert_get_friendly_name(cert);
2755178825Sdfr	if (name == NULL)
2756178825Sdfr	    return 0;
2757178825Sdfr	if (strcasecmp(q->friendlyname, name) != 0)
2758178825Sdfr	    return 0;
2759178825Sdfr    }
2760178825Sdfr    if (q->match & HX509_QUERY_MATCH_FUNCTION) {
2761178825Sdfr	int ret = (*q->cmp_func)(q->cmp_func_ctx, cert);
2762178825Sdfr	if (ret != 0)
2763178825Sdfr	    return 0;
2764178825Sdfr    }
2765178825Sdfr
2766178825Sdfr    if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
2767178825Sdfr	heim_octet_string os;
2768178825Sdfr	int ret;
2769178825Sdfr
2770178825Sdfr	os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
2771178825Sdfr	os.length =
2772178825Sdfr	    c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
2773178825Sdfr
2774178825Sdfr	ret = _hx509_verify_signature(context,
2775178825Sdfr				      NULL,
2776178825Sdfr				      hx509_signature_sha1(),
2777178825Sdfr				      &os,
2778178825Sdfr				      q->keyhash_sha1);
2779178825Sdfr	if (ret != 0)
2780178825Sdfr	    return 0;
2781178825Sdfr    }
2782178825Sdfr
2783178825Sdfr    if (q->match & HX509_QUERY_MATCH_TIME) {
2784178825Sdfr	time_t t;
2785178825Sdfr	t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2786178825Sdfr	if (t > q->timenow)
2787178825Sdfr	    return 0;
2788178825Sdfr	t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2789178825Sdfr	if (t < q->timenow)
2790178825Sdfr	    return 0;
2791178825Sdfr    }
2792178825Sdfr
2793178825Sdfr    if (q->match & ~HX509_QUERY_MASK)
2794178825Sdfr	return 0;
2795178825Sdfr
2796178825Sdfr    return 1;
2797178825Sdfr}
2798178825Sdfr
2799178825Sdfr/**
2800178825Sdfr * Set a statistic file for the query statistics.
2801178825Sdfr *
2802178825Sdfr * @param context A hx509 context.
2803178825Sdfr * @param fn statistics file name
2804178825Sdfr *
2805178825Sdfr * @ingroup hx509_cert
2806178825Sdfr */
2807178825Sdfr
2808178825Sdfrvoid
2809178825Sdfrhx509_query_statistic_file(hx509_context context, const char *fn)
2810178825Sdfr{
2811178825Sdfr    if (context->querystat)
2812178825Sdfr	free(context->querystat);
2813178825Sdfr    context->querystat = strdup(fn);
2814178825Sdfr}
2815178825Sdfr
2816178825Sdfrvoid
2817178825Sdfr_hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
2818178825Sdfr{
2819178825Sdfr    FILE *f;
2820178825Sdfr    if (context->querystat == NULL)
2821178825Sdfr	return;
2822178825Sdfr    f = fopen(context->querystat, "a");
2823178825Sdfr    if (f == NULL)
2824178825Sdfr	return;
2825178825Sdfr    fprintf(f, "%d %d\n", type, q->match);
2826178825Sdfr    fclose(f);
2827178825Sdfr}
2828178825Sdfr
2829178825Sdfrstatic const char *statname[] = {
2830178825Sdfr    "find issuer cert",
2831178825Sdfr    "match serialnumber",
2832178825Sdfr    "match issuer name",
2833178825Sdfr    "match subject name",
2834178825Sdfr    "match subject key id",
2835178825Sdfr    "match issuer id",
2836178825Sdfr    "private key",
2837178825Sdfr    "ku encipherment",
2838178825Sdfr    "ku digitalsignature",
2839178825Sdfr    "ku keycertsign",
2840178825Sdfr    "ku crlsign",
2841178825Sdfr    "ku nonrepudiation",
2842178825Sdfr    "ku keyagreement",
2843178825Sdfr    "ku dataencipherment",
2844178825Sdfr    "anchor",
2845178825Sdfr    "match certificate",
2846178825Sdfr    "match local key id",
2847178825Sdfr    "no match path",
2848178825Sdfr    "match friendly name",
2849178825Sdfr    "match function",
2850178825Sdfr    "match key hash sha1",
2851178825Sdfr    "match time"
2852178825Sdfr};
2853178825Sdfr
2854178825Sdfrstruct stat_el {
2855178825Sdfr    unsigned long stats;
2856178825Sdfr    unsigned int index;
2857178825Sdfr};
2858178825Sdfr
2859178825Sdfr
2860178825Sdfrstatic int
2861178825Sdfrstat_sort(const void *a, const void *b)
2862178825Sdfr{
2863178825Sdfr    const struct stat_el *ae = a;
2864178825Sdfr    const struct stat_el *be = b;
2865178825Sdfr    return be->stats - ae->stats;
2866178825Sdfr}
2867178825Sdfr
2868178825Sdfr/**
2869178825Sdfr * Unparse the statistics file and print the result on a FILE descriptor.
2870178825Sdfr *
2871178825Sdfr * @param context A hx509 context.
2872178825Sdfr * @param printtype tyep to print
2873178825Sdfr * @param out the FILE to write the data on.
2874178825Sdfr *
2875178825Sdfr * @ingroup hx509_cert
2876178825Sdfr */
2877178825Sdfr
2878178825Sdfrvoid
2879178825Sdfrhx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
2880178825Sdfr{
2881178825Sdfr    rtbl_t t;
2882178825Sdfr    FILE *f;
2883178825Sdfr    int type, mask, i, num;
2884178825Sdfr    unsigned long multiqueries = 0, totalqueries = 0;
2885178825Sdfr    struct stat_el stats[32];
2886178825Sdfr
2887178825Sdfr    if (context->querystat == NULL)
2888178825Sdfr	return;
2889178825Sdfr    f = fopen(context->querystat, "r");
2890178825Sdfr    if (f == NULL) {
2891178825Sdfr	fprintf(out, "No statistic file %s: %s.\n",
2892178825Sdfr		context->querystat, strerror(errno));
2893178825Sdfr	return;
2894178825Sdfr    }
2895178825Sdfr
2896178825Sdfr    for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2897178825Sdfr	stats[i].index = i;
2898178825Sdfr	stats[i].stats = 0;
2899178825Sdfr    }
2900178825Sdfr
2901178825Sdfr    while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
2902178825Sdfr	if (type != printtype)
2903178825Sdfr	    continue;
2904178825Sdfr	num = i = 0;
2905178825Sdfr	while (mask && i < sizeof(stats)/sizeof(stats[0])) {
2906178825Sdfr	    if (mask & 1) {
2907178825Sdfr		stats[i].stats++;
2908178825Sdfr		num++;
2909178825Sdfr	    }
2910178825Sdfr	    mask = mask >>1 ;
2911178825Sdfr	    i++;
2912178825Sdfr	}
2913178825Sdfr	if (num > 1)
2914178825Sdfr	    multiqueries++;
2915178825Sdfr	totalqueries++;
2916178825Sdfr    }
2917178825Sdfr    fclose(f);
2918178825Sdfr
2919178825Sdfr    qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
2920178825Sdfr
2921178825Sdfr    t = rtbl_create();
2922178825Sdfr    if (t == NULL)
2923178825Sdfr	errx(1, "out of memory");
2924178825Sdfr
2925178825Sdfr    rtbl_set_separator (t, "  ");
2926178825Sdfr
2927178825Sdfr    rtbl_add_column_by_id (t, 0, "Name", 0);
2928178825Sdfr    rtbl_add_column_by_id (t, 1, "Counter", 0);
2929178825Sdfr
2930178825Sdfr
2931178825Sdfr    for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
2932178825Sdfr	char str[10];
2933178825Sdfr
2934178825Sdfr	if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
2935178825Sdfr	    rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
2936178825Sdfr	else {
2937178825Sdfr	    snprintf(str, sizeof(str), "%d", stats[i].index);
2938178825Sdfr	    rtbl_add_column_entry_by_id (t, 0, str);
2939178825Sdfr	}
2940178825Sdfr	snprintf(str, sizeof(str), "%lu", stats[i].stats);
2941178825Sdfr	rtbl_add_column_entry_by_id (t, 1, str);
2942178825Sdfr    }
2943178825Sdfr
2944178825Sdfr    rtbl_format(t, out);
2945178825Sdfr    rtbl_destroy(t);
2946178825Sdfr
2947178825Sdfr    fprintf(out, "\nQueries: multi %lu total %lu\n",
2948178825Sdfr	    multiqueries, totalqueries);
2949178825Sdfr}
2950178825Sdfr
2951178825Sdfr/**
2952178825Sdfr * Check the extended key usage on the hx509 certificate.
2953178825Sdfr *
2954178825Sdfr * @param context A hx509 context.
2955178825Sdfr * @param cert A hx509 context.
2956178825Sdfr * @param eku the EKU to check for
2957178825Sdfr * @param allow_any_eku if the any EKU is set, allow that to be a
2958178825Sdfr * substitute.
2959178825Sdfr *
2960178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2961178825Sdfr *
2962178825Sdfr * @ingroup hx509_cert
2963178825Sdfr */
2964178825Sdfr
2965178825Sdfrint
2966178825Sdfrhx509_cert_check_eku(hx509_context context, hx509_cert cert,
2967178825Sdfr		     const heim_oid *eku, int allow_any_eku)
2968178825Sdfr{
2969178825Sdfr    ExtKeyUsage e;
2970178825Sdfr    int ret, i;
2971178825Sdfr
2972178825Sdfr    ret = find_extension_eku(_hx509_get_cert(cert), &e);
2973178825Sdfr    if (ret) {
2974178825Sdfr	hx509_clear_error_string(context);
2975178825Sdfr	return ret;
2976178825Sdfr    }
2977178825Sdfr
2978178825Sdfr    for (i = 0; i < e.len; i++) {
2979178825Sdfr	if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
2980178825Sdfr	    free_ExtKeyUsage(&e);
2981178825Sdfr	    return 0;
2982178825Sdfr	}
2983178825Sdfr	if (allow_any_eku) {
2984178825Sdfr#if 0
2985178825Sdfr	    if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
2986178825Sdfr		free_ExtKeyUsage(&e);
2987178825Sdfr		return 0;
2988178825Sdfr	    }
2989178825Sdfr#endif
2990178825Sdfr	}
2991178825Sdfr    }
2992178825Sdfr    free_ExtKeyUsage(&e);
2993178825Sdfr    hx509_clear_error_string(context);
2994178825Sdfr    return HX509_CERTIFICATE_MISSING_EKU;
2995178825Sdfr}
2996178825Sdfr
2997178825Sdfrint
2998178825Sdfr_hx509_cert_get_keyusage(hx509_context context,
2999178825Sdfr			 hx509_cert c,
3000178825Sdfr			 KeyUsage *ku)
3001178825Sdfr{
3002178825Sdfr    Certificate *cert;
3003178825Sdfr    const Extension *e;
3004178825Sdfr    size_t size;
3005178825Sdfr    int ret, i = 0;
3006178825Sdfr
3007178825Sdfr    memset(ku, 0, sizeof(*ku));
3008178825Sdfr
3009178825Sdfr    cert = _hx509_get_cert(c);
3010178825Sdfr
3011178825Sdfr    if (_hx509_cert_get_version(cert) < 3)
3012178825Sdfr	return 0;
3013178825Sdfr
3014178825Sdfr    e = find_extension(cert, oid_id_x509_ce_keyUsage(), &i);
3015178825Sdfr    if (e == NULL)
3016178825Sdfr	return HX509_KU_CERT_MISSING;
3017178825Sdfr
3018178825Sdfr    ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3019178825Sdfr    if (ret)
3020178825Sdfr	return ret;
3021178825Sdfr    return 0;
3022178825Sdfr}
3023178825Sdfr
3024178825Sdfrint
3025178825Sdfr_hx509_cert_get_eku(hx509_context context,
3026178825Sdfr		    hx509_cert cert,
3027178825Sdfr		    ExtKeyUsage *e)
3028178825Sdfr{
3029178825Sdfr    int ret;
3030178825Sdfr
3031178825Sdfr    memset(e, 0, sizeof(*e));
3032178825Sdfr
3033178825Sdfr    ret = find_extension_eku(_hx509_get_cert(cert), e);
3034178825Sdfr    if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3035178825Sdfr	hx509_clear_error_string(context);
3036178825Sdfr	return ret;
3037178825Sdfr    }
3038178825Sdfr    return 0;
3039178825Sdfr}
3040178825Sdfr
3041178825Sdfr/**
3042178825Sdfr * Encodes the hx509 certificate as a DER encode binary.
3043178825Sdfr *
3044178825Sdfr * @param context A hx509 context.
3045178825Sdfr * @param c the certificate to encode.
3046178825Sdfr * @param os the encode certificate, set to NULL, 0 on case of
3047178825Sdfr * error. Free the returned structure with hx509_xfree().
3048178825Sdfr *
3049178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
3050178825Sdfr *
3051178825Sdfr * @ingroup hx509_cert
3052178825Sdfr */
3053178825Sdfr
3054178825Sdfrint
3055178825Sdfrhx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3056178825Sdfr{
3057178825Sdfr    size_t size;
3058178825Sdfr    int ret;
3059178825Sdfr
3060178825Sdfr    os->data = NULL;
3061178825Sdfr    os->length = 0;
3062178825Sdfr
3063178825Sdfr    ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3064178825Sdfr		       _hx509_get_cert(c), &size, ret);
3065178825Sdfr    if (ret) {
3066178825Sdfr	os->data = NULL;
3067178825Sdfr	os->length = 0;
3068178825Sdfr	return ret;
3069178825Sdfr    }
3070178825Sdfr    if (os->length != size)
3071178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
3072178825Sdfr
3073178825Sdfr    return ret;
3074178825Sdfr}
3075178825Sdfr
3076178825Sdfr/*
3077178825Sdfr * Last to avoid lost __attribute__s due to #undef.
3078178825Sdfr */
3079178825Sdfr
3080178825Sdfr#undef __attribute__
3081178825Sdfr#define __attribute__(X)
3082178825Sdfr
3083178825Sdfrvoid
3084178825Sdfr_hx509_abort(const char *fmt, ...)
3085178825Sdfr     __attribute__ ((noreturn, format (printf, 1, 2)))
3086178825Sdfr{
3087178825Sdfr    va_list ap;
3088178825Sdfr    va_start(ap, fmt);
3089178825Sdfr    vprintf(fmt, ap);
3090178825Sdfr    va_end(ap);
3091178825Sdfr    printf("\n");
3092178825Sdfr    fflush(stdout);
3093178825Sdfr    abort();
3094178825Sdfr}
3095178825Sdfr
3096178825Sdfr/**
3097178825Sdfr * Free a data element allocated in the library.
3098178825Sdfr *
3099178825Sdfr * @param ptr data to be freed.
3100178825Sdfr *
3101178825Sdfr * @ingroup hx509_misc
3102178825Sdfr */
3103178825Sdfr
3104178825Sdfrvoid
3105178825Sdfrhx509_xfree(void *ptr)
3106178825Sdfr{
3107178825Sdfr    free(ptr);
3108178825Sdfr}
3109