1178825Sdfr/*
2233294Sstas * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr#include "crypto-headers.h"
36178825Sdfr#include <rtbl.h>
37178825Sdfr
38178825Sdfr/**
39178825Sdfr * @page page_cert The basic certificate
40178825Sdfr *
41178825Sdfr * The basic hx509 cerificate object in hx509 is hx509_cert. The
42178825Sdfr * hx509_cert object is representing one X509/PKIX certificate and
43178825Sdfr * associated attributes; like private key, friendly name, etc.
44178825Sdfr *
45178825Sdfr * A hx509_cert object is usully found via the keyset interfaces (@ref
46178825Sdfr * page_keyset), but its also possible to create a certificate
47178825Sdfr * directly from a parsed object with hx509_cert_init() and
48178825Sdfr * hx509_cert_init_data().
49178825Sdfr *
50178825Sdfr * See the library functions here: @ref hx509_cert
51178825Sdfr */
52178825Sdfr
53178825Sdfrstruct hx509_verify_ctx_data {
54178825Sdfr    hx509_certs trust_anchors;
55178825Sdfr    int flags;
56178825Sdfr#define HX509_VERIFY_CTX_F_TIME_SET			1
57178825Sdfr#define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE	2
58178825Sdfr#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280		4
59178825Sdfr#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS		8
60178825Sdfr#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS		16
61233294Sstas#define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK		32
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
141233294Sstas * the existans of a revokation method (OCSP, CRL) or not. Note that
142178825Sdfr * hx509_verify_path(), hx509_cms_verify_signed(), and other function
143178825Sdfr * call hx509_revoke_verify().
144233294Sstas *
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().
163233294Sstas *
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
208233294Sstas * 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
271233294Sstashx509_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) {
286233294Sstas	free_Certificate(&t);
287178825Sdfr	hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE,
288178825Sdfr			       "Extra data after certificate");
289178825Sdfr	return HX509_EXTRA_DATA_AFTER_STRUCTURE;
290178825Sdfr    }
291178825Sdfr
292178825Sdfr    ret = hx509_cert_init(context, &t, cert);
293178825Sdfr    free_Certificate(&t);
294178825Sdfr    return ret;
295178825Sdfr}
296178825Sdfr
297178825Sdfrvoid
298233294Sstas_hx509_cert_set_release(hx509_cert cert,
299178825Sdfr			_hx509_cert_release_func release,
300178825Sdfr			void *ctx)
301178825Sdfr{
302178825Sdfr    cert->release = release;
303178825Sdfr    cert->ctx = ctx;
304178825Sdfr}
305178825Sdfr
306178825Sdfr
307178825Sdfr/* Doesn't make a copy of `private_key'. */
308178825Sdfr
309178825Sdfrint
310178825Sdfr_hx509_cert_assign_key(hx509_cert cert, hx509_private_key private_key)
311178825Sdfr{
312178825Sdfr    if (cert->private_key)
313233294Sstas	hx509_private_key_free(&cert->private_key);
314178825Sdfr    cert->private_key = _hx509_private_key_ref(private_key);
315178825Sdfr    return 0;
316178825Sdfr}
317178825Sdfr
318178825Sdfr/**
319178825Sdfr * Free reference to the hx509 certificate object, if the refcounter
320178825Sdfr * reaches 0, the object if freed. Its allowed to pass in NULL.
321178825Sdfr *
322178825Sdfr * @param cert the cert to free.
323178825Sdfr *
324178825Sdfr * @ingroup hx509_cert
325178825Sdfr */
326178825Sdfr
327178825Sdfrvoid
328178825Sdfrhx509_cert_free(hx509_cert cert)
329178825Sdfr{
330233294Sstas    size_t i;
331178825Sdfr
332178825Sdfr    if (cert == NULL)
333178825Sdfr	return;
334178825Sdfr
335178825Sdfr    if (cert->ref <= 0)
336178825Sdfr	_hx509_abort("cert refcount <= 0 on free");
337178825Sdfr    if (--cert->ref > 0)
338178825Sdfr	return;
339178825Sdfr
340178825Sdfr    if (cert->release)
341178825Sdfr	(cert->release)(cert, cert->ctx);
342178825Sdfr
343178825Sdfr    if (cert->private_key)
344233294Sstas	hx509_private_key_free(&cert->private_key);
345178825Sdfr
346178825Sdfr    free_Certificate(cert->data);
347178825Sdfr    free(cert->data);
348178825Sdfr
349178825Sdfr    for (i = 0; i < cert->attrs.len; i++) {
350178825Sdfr	der_free_octet_string(&cert->attrs.val[i]->data);
351178825Sdfr	der_free_oid(&cert->attrs.val[i]->oid);
352178825Sdfr	free(cert->attrs.val[i]);
353178825Sdfr    }
354178825Sdfr    free(cert->attrs.val);
355178825Sdfr    free(cert->friendlyname);
356178825Sdfr    if (cert->basename)
357178825Sdfr	hx509_name_free(&cert->basename);
358233294Sstas    memset(cert, 0, sizeof(*cert));
359178825Sdfr    free(cert);
360178825Sdfr}
361178825Sdfr
362178825Sdfr/**
363178825Sdfr * Add a reference to a hx509 certificate object.
364178825Sdfr *
365178825Sdfr * @param cert a pointer to an hx509 certificate object.
366178825Sdfr *
367178825Sdfr * @return the same object as is passed in.
368178825Sdfr *
369178825Sdfr * @ingroup hx509_cert
370178825Sdfr */
371178825Sdfr
372178825Sdfrhx509_cert
373178825Sdfrhx509_cert_ref(hx509_cert cert)
374178825Sdfr{
375178825Sdfr    if (cert == NULL)
376178825Sdfr	return NULL;
377178825Sdfr    if (cert->ref <= 0)
378178825Sdfr	_hx509_abort("cert refcount <= 0");
379178825Sdfr    cert->ref++;
380178825Sdfr    if (cert->ref == 0)
381178825Sdfr	_hx509_abort("cert refcount == 0");
382178825Sdfr    return cert;
383178825Sdfr}
384178825Sdfr
385178825Sdfr/**
386178825Sdfr * Allocate an verification context that is used fo control the
387233294Sstas * verification process.
388178825Sdfr *
389178825Sdfr * @param context A hx509 context.
390178825Sdfr * @param ctx returns a pointer to a hx509_verify_ctx object.
391178825Sdfr *
392178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
393178825Sdfr *
394178825Sdfr * @ingroup hx509_verify
395178825Sdfr */
396178825Sdfr
397178825Sdfrint
398178825Sdfrhx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx)
399178825Sdfr{
400178825Sdfr    hx509_verify_ctx c;
401178825Sdfr
402178825Sdfr    c = calloc(1, sizeof(*c));
403178825Sdfr    if (c == NULL)
404178825Sdfr	return ENOMEM;
405178825Sdfr
406178825Sdfr    c->max_depth = HX509_VERIFY_MAX_DEPTH;
407178825Sdfr
408178825Sdfr    *ctx = c;
409233294Sstas
410178825Sdfr    return 0;
411178825Sdfr}
412178825Sdfr
413178825Sdfr/**
414178825Sdfr * Free an hx509 verification context.
415178825Sdfr *
416178825Sdfr * @param ctx the context to be freed.
417178825Sdfr *
418178825Sdfr * @ingroup hx509_verify
419178825Sdfr */
420178825Sdfr
421178825Sdfrvoid
422178825Sdfrhx509_verify_destroy_ctx(hx509_verify_ctx ctx)
423178825Sdfr{
424178825Sdfr    if (ctx) {
425178825Sdfr	hx509_certs_free(&ctx->trust_anchors);
426178825Sdfr	hx509_revoke_free(&ctx->revoke_ctx);
427178825Sdfr	memset(ctx, 0, sizeof(*ctx));
428178825Sdfr    }
429178825Sdfr    free(ctx);
430178825Sdfr}
431178825Sdfr
432178825Sdfr/**
433178825Sdfr * Set the trust anchors in the verification context, makes an
434178825Sdfr * reference to the keyset, so the consumer can free the keyset
435178825Sdfr * independent of the destruction of the verification context (ctx).
436233294Sstas * If there already is a keyset attached, it's released.
437178825Sdfr *
438178825Sdfr * @param ctx a verification context
439178825Sdfr * @param set a keyset containing the trust anchors.
440178825Sdfr *
441178825Sdfr * @ingroup hx509_verify
442178825Sdfr */
443178825Sdfr
444178825Sdfrvoid
445178825Sdfrhx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set)
446178825Sdfr{
447233294Sstas    if (ctx->trust_anchors)
448233294Sstas	hx509_certs_free(&ctx->trust_anchors);
449233294Sstas    ctx->trust_anchors = hx509_certs_ref(set);
450178825Sdfr}
451178825Sdfr
452178825Sdfr/**
453178825Sdfr * Attach an revocation context to the verfication context, , makes an
454178825Sdfr * reference to the revoke context, so the consumer can free the
455178825Sdfr * revoke context independent of the destruction of the verification
456178825Sdfr * context. If there is no revoke context, the verification process is
457178825Sdfr * NOT going to check any verification status.
458178825Sdfr *
459178825Sdfr * @param ctx a verification context.
460178825Sdfr * @param revoke_ctx a revoke context.
461178825Sdfr *
462178825Sdfr * @ingroup hx509_verify
463178825Sdfr */
464178825Sdfr
465178825Sdfrvoid
466178825Sdfrhx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx)
467178825Sdfr{
468178825Sdfr    if (ctx->revoke_ctx)
469178825Sdfr	hx509_revoke_free(&ctx->revoke_ctx);
470178825Sdfr    ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx);
471178825Sdfr}
472178825Sdfr
473178825Sdfr/**
474178825Sdfr * Set the clock time the the verification process is going to
475178825Sdfr * use. Used to check certificate in the past and future time. If not
476178825Sdfr * set the current time will be used.
477178825Sdfr *
478178825Sdfr * @param ctx a verification context.
479178825Sdfr * @param t the time the verifiation is using.
480178825Sdfr *
481178825Sdfr *
482178825Sdfr * @ingroup hx509_verify
483178825Sdfr */
484178825Sdfr
485178825Sdfrvoid
486178825Sdfrhx509_verify_set_time(hx509_verify_ctx ctx, time_t t)
487178825Sdfr{
488178825Sdfr    ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET;
489178825Sdfr    ctx->time_now = t;
490178825Sdfr}
491178825Sdfr
492233294Sstastime_t
493233294Sstas_hx509_verify_get_time(hx509_verify_ctx ctx)
494233294Sstas{
495233294Sstas    return ctx->time_now;
496233294Sstas}
497233294Sstas
498178825Sdfr/**
499178825Sdfr * Set the maximum depth of the certificate chain that the path
500178825Sdfr * builder is going to try.
501178825Sdfr *
502178825Sdfr * @param ctx a verification context
503178825Sdfr * @param max_depth maxium depth of the certificate chain, include
504178825Sdfr * trust anchor.
505178825Sdfr *
506178825Sdfr * @ingroup hx509_verify
507178825Sdfr */
508178825Sdfr
509178825Sdfrvoid
510178825Sdfrhx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth)
511178825Sdfr{
512178825Sdfr    ctx->max_depth = max_depth;
513178825Sdfr}
514178825Sdfr
515178825Sdfr/**
516178825Sdfr * Allow or deny the use of proxy certificates
517178825Sdfr *
518178825Sdfr * @param ctx a verification context
519178825Sdfr * @param boolean if non zero, allow proxy certificates.
520178825Sdfr *
521178825Sdfr * @ingroup hx509_verify
522178825Sdfr */
523178825Sdfr
524178825Sdfrvoid
525178825Sdfrhx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean)
526178825Sdfr{
527178825Sdfr    if (boolean)
528178825Sdfr	ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
529178825Sdfr    else
530178825Sdfr	ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE;
531178825Sdfr}
532178825Sdfr
533178825Sdfr/**
534178825Sdfr * Select strict RFC3280 verification of certificiates. This means
535178825Sdfr * checking key usage on CA certificates, this will make version 1
536178825Sdfr * certificiates unuseable.
537178825Sdfr *
538178825Sdfr * @param ctx a verification context
539178825Sdfr * @param boolean if non zero, use strict verification.
540178825Sdfr *
541178825Sdfr * @ingroup hx509_verify
542178825Sdfr */
543178825Sdfr
544178825Sdfrvoid
545178825Sdfrhx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean)
546178825Sdfr{
547178825Sdfr    if (boolean)
548178825Sdfr	ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
549178825Sdfr    else
550178825Sdfr	ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280;
551178825Sdfr}
552178825Sdfr
553178825Sdfr/**
554178825Sdfr * Allow using the operating system builtin trust anchors if no other
555178825Sdfr * trust anchors are configured.
556178825Sdfr *
557178825Sdfr * @param ctx a verification context
558178825Sdfr * @param boolean if non zero, useing the operating systems builtin
559178825Sdfr * trust anchors.
560178825Sdfr *
561178825Sdfr *
562178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
563178825Sdfr *
564178825Sdfr * @ingroup hx509_cert
565178825Sdfr */
566178825Sdfr
567178825Sdfrvoid
568178825Sdfrhx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean)
569178825Sdfr{
570178825Sdfr    if (boolean)
571178825Sdfr	ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
572178825Sdfr    else
573178825Sdfr	ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS;
574178825Sdfr}
575178825Sdfr
576233294Sstasvoid
577233294Sstashx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx,
578233294Sstas						    int boolean)
579233294Sstas{
580233294Sstas    if (boolean)
581233294Sstas	ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
582233294Sstas    else
583233294Sstas	ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK;
584233294Sstas}
585233294Sstas
586178825Sdfrstatic const Extension *
587233294Sstasfind_extension(const Certificate *cert, const heim_oid *oid, size_t *idx)
588178825Sdfr{
589178825Sdfr    const TBSCertificate *c = &cert->tbsCertificate;
590178825Sdfr
591178825Sdfr    if (c->version == NULL || *c->version < 2 || c->extensions == NULL)
592178825Sdfr	return NULL;
593233294Sstas
594178825Sdfr    for (;*idx < c->extensions->len; (*idx)++) {
595178825Sdfr	if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0)
596178825Sdfr	    return &c->extensions->val[(*idx)++];
597178825Sdfr    }
598178825Sdfr    return NULL;
599178825Sdfr}
600178825Sdfr
601178825Sdfrstatic int
602233294Sstasfind_extension_auth_key_id(const Certificate *subject,
603178825Sdfr			   AuthorityKeyIdentifier *ai)
604178825Sdfr{
605178825Sdfr    const Extension *e;
606178825Sdfr    size_t size;
607233294Sstas    size_t i = 0;
608178825Sdfr
609178825Sdfr    memset(ai, 0, sizeof(*ai));
610178825Sdfr
611233294Sstas    e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i);
612178825Sdfr    if (e == NULL)
613178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
614233294Sstas
615233294Sstas    return decode_AuthorityKeyIdentifier(e->extnValue.data,
616233294Sstas					 e->extnValue.length,
617178825Sdfr					 ai, &size);
618178825Sdfr}
619178825Sdfr
620178825Sdfrint
621178825Sdfr_hx509_find_extension_subject_key_id(const Certificate *issuer,
622178825Sdfr				     SubjectKeyIdentifier *si)
623178825Sdfr{
624178825Sdfr    const Extension *e;
625178825Sdfr    size_t size;
626233294Sstas    size_t i = 0;
627178825Sdfr
628178825Sdfr    memset(si, 0, sizeof(*si));
629178825Sdfr
630233294Sstas    e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i);
631178825Sdfr    if (e == NULL)
632178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
633233294Sstas
634233294Sstas    return decode_SubjectKeyIdentifier(e->extnValue.data,
635178825Sdfr				       e->extnValue.length,
636178825Sdfr				       si, &size);
637178825Sdfr}
638178825Sdfr
639178825Sdfrstatic int
640233294Sstasfind_extension_name_constraints(const Certificate *subject,
641178825Sdfr				NameConstraints *nc)
642178825Sdfr{
643178825Sdfr    const Extension *e;
644178825Sdfr    size_t size;
645233294Sstas    size_t i = 0;
646178825Sdfr
647178825Sdfr    memset(nc, 0, sizeof(*nc));
648178825Sdfr
649233294Sstas    e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i);
650178825Sdfr    if (e == NULL)
651178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
652233294Sstas
653233294Sstas    return decode_NameConstraints(e->extnValue.data,
654233294Sstas				  e->extnValue.length,
655178825Sdfr				  nc, &size);
656178825Sdfr}
657178825Sdfr
658178825Sdfrstatic int
659233294Sstasfind_extension_subject_alt_name(const Certificate *cert, size_t *i,
660178825Sdfr				GeneralNames *sa)
661178825Sdfr{
662178825Sdfr    const Extension *e;
663178825Sdfr    size_t size;
664178825Sdfr
665178825Sdfr    memset(sa, 0, sizeof(*sa));
666178825Sdfr
667233294Sstas    e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i);
668178825Sdfr    if (e == NULL)
669178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
670233294Sstas
671233294Sstas    return decode_GeneralNames(e->extnValue.data,
672178825Sdfr			       e->extnValue.length,
673178825Sdfr			       sa, &size);
674178825Sdfr}
675178825Sdfr
676178825Sdfrstatic int
677178825Sdfrfind_extension_eku(const Certificate *cert, ExtKeyUsage *eku)
678178825Sdfr{
679178825Sdfr    const Extension *e;
680178825Sdfr    size_t size;
681233294Sstas    size_t i = 0;
682178825Sdfr
683178825Sdfr    memset(eku, 0, sizeof(*eku));
684178825Sdfr
685233294Sstas    e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i);
686178825Sdfr    if (e == NULL)
687178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
688233294Sstas
689233294Sstas    return decode_ExtKeyUsage(e->extnValue.data,
690178825Sdfr			      e->extnValue.length,
691178825Sdfr			      eku, &size);
692178825Sdfr}
693178825Sdfr
694178825Sdfrstatic int
695178825Sdfradd_to_list(hx509_octet_string_list *list, const heim_octet_string *entry)
696178825Sdfr{
697178825Sdfr    void *p;
698178825Sdfr    int ret;
699178825Sdfr
700178825Sdfr    p = realloc(list->val, (list->len + 1) * sizeof(list->val[0]));
701178825Sdfr    if (p == NULL)
702178825Sdfr	return ENOMEM;
703178825Sdfr    list->val = p;
704178825Sdfr    ret = der_copy_octet_string(entry, &list->val[list->len]);
705178825Sdfr    if (ret)
706178825Sdfr	return ret;
707178825Sdfr    list->len++;
708178825Sdfr    return 0;
709178825Sdfr}
710178825Sdfr
711178825Sdfr/**
712178825Sdfr * Free a list of octet strings returned by another hx509 library
713178825Sdfr * function.
714178825Sdfr *
715178825Sdfr * @param list list to be freed.
716178825Sdfr *
717178825Sdfr * @ingroup hx509_misc
718178825Sdfr */
719178825Sdfr
720178825Sdfrvoid
721178825Sdfrhx509_free_octet_string_list(hx509_octet_string_list *list)
722178825Sdfr{
723233294Sstas    size_t i;
724178825Sdfr    for (i = 0; i < list->len; i++)
725178825Sdfr	der_free_octet_string(&list->val[i]);
726178825Sdfr    free(list->val);
727178825Sdfr    list->val = NULL;
728178825Sdfr    list->len = 0;
729178825Sdfr}
730178825Sdfr
731178825Sdfr/**
732178825Sdfr * Return a list of subjectAltNames specified by oid in the
733233294Sstas * certificate. On error the
734178825Sdfr *
735178825Sdfr * The returned list of octet string should be freed with
736178825Sdfr * hx509_free_octet_string_list().
737178825Sdfr *
738178825Sdfr * @param context A hx509 context.
739178825Sdfr * @param cert a hx509 certificate object.
740178825Sdfr * @param oid an oid to for SubjectAltName.
741178825Sdfr * @param list list of matching SubjectAltName.
742178825Sdfr *
743178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
744178825Sdfr *
745178825Sdfr * @ingroup hx509_cert
746178825Sdfr */
747178825Sdfr
748178825Sdfrint
749178825Sdfrhx509_cert_find_subjectAltName_otherName(hx509_context context,
750178825Sdfr					 hx509_cert cert,
751178825Sdfr					 const heim_oid *oid,
752178825Sdfr					 hx509_octet_string_list *list)
753178825Sdfr{
754178825Sdfr    GeneralNames sa;
755233294Sstas    int ret;
756233294Sstas    size_t i, j;
757178825Sdfr
758178825Sdfr    list->val = NULL;
759178825Sdfr    list->len = 0;
760178825Sdfr
761178825Sdfr    i = 0;
762178825Sdfr    while (1) {
763178825Sdfr	ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa);
764178825Sdfr	i++;
765178825Sdfr	if (ret == HX509_EXTENSION_NOT_FOUND) {
766233294Sstas	    return 0;
767178825Sdfr	} else if (ret != 0) {
768178825Sdfr	    hx509_set_error_string(context, 0, ret, "Error searching for SAN");
769178825Sdfr	    hx509_free_octet_string_list(list);
770178825Sdfr	    return ret;
771178825Sdfr	}
772178825Sdfr
773178825Sdfr	for (j = 0; j < sa.len; j++) {
774178825Sdfr	    if (sa.val[j].element == choice_GeneralName_otherName &&
775233294Sstas		der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0)
776178825Sdfr	    {
777178825Sdfr		ret = add_to_list(list, &sa.val[j].u.otherName.value);
778178825Sdfr		if (ret) {
779233294Sstas		    hx509_set_error_string(context, 0, ret,
780178825Sdfr					   "Error adding an exra SAN to "
781178825Sdfr					   "return list");
782178825Sdfr		    hx509_free_octet_string_list(list);
783178825Sdfr		    free_GeneralNames(&sa);
784178825Sdfr		    return ret;
785178825Sdfr		}
786178825Sdfr	    }
787178825Sdfr	}
788178825Sdfr	free_GeneralNames(&sa);
789178825Sdfr    }
790178825Sdfr}
791178825Sdfr
792178825Sdfr
793178825Sdfrstatic int
794233294Sstascheck_key_usage(hx509_context context, const Certificate *cert,
795178825Sdfr		unsigned flags, int req_present)
796178825Sdfr{
797178825Sdfr    const Extension *e;
798178825Sdfr    KeyUsage ku;
799178825Sdfr    size_t size;
800233294Sstas    int ret;
801233294Sstas    size_t i = 0;
802178825Sdfr    unsigned ku_flags;
803178825Sdfr
804178825Sdfr    if (_hx509_cert_get_version(cert) < 3)
805178825Sdfr	return 0;
806178825Sdfr
807233294Sstas    e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
808178825Sdfr    if (e == NULL) {
809178825Sdfr	if (req_present) {
810178825Sdfr	    hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
811178825Sdfr				   "Required extension key "
812178825Sdfr				   "usage missing from certifiate");
813178825Sdfr	    return HX509_KU_CERT_MISSING;
814178825Sdfr	}
815178825Sdfr	return 0;
816178825Sdfr    }
817233294Sstas
818178825Sdfr    ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size);
819178825Sdfr    if (ret)
820178825Sdfr	return ret;
821178825Sdfr    ku_flags = KeyUsage2int(ku);
822178825Sdfr    if ((ku_flags & flags) != flags) {
823178825Sdfr	unsigned missing = (~ku_flags) & flags;
824178825Sdfr	char buf[256], *name;
825178825Sdfr
826178825Sdfr	unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf));
827178825Sdfr	_hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
828178825Sdfr	hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING,
829178825Sdfr			       "Key usage %s required but missing "
830178825Sdfr			       "from certifiate %s", buf, name);
831178825Sdfr	free(name);
832178825Sdfr	return HX509_KU_CERT_MISSING;
833178825Sdfr    }
834178825Sdfr    return 0;
835178825Sdfr}
836178825Sdfr
837178825Sdfr/*
838178825Sdfr * Return 0 on matching key usage 'flags' for 'cert', otherwise return
839178825Sdfr * an error code. If 'req_present' the existance is required of the
840178825Sdfr * KeyUsage extension.
841178825Sdfr */
842178825Sdfr
843178825Sdfrint
844233294Sstas_hx509_check_key_usage(hx509_context context, hx509_cert cert,
845178825Sdfr		       unsigned flags, int req_present)
846178825Sdfr{
847178825Sdfr    return check_key_usage(context, _hx509_get_cert(cert), flags, req_present);
848178825Sdfr}
849178825Sdfr
850178825Sdfrenum certtype { PROXY_CERT, EE_CERT, CA_CERT };
851178825Sdfr
852178825Sdfrstatic int
853233294Sstascheck_basic_constraints(hx509_context context, const Certificate *cert,
854233294Sstas			enum certtype type, size_t depth)
855178825Sdfr{
856178825Sdfr    BasicConstraints bc;
857178825Sdfr    const Extension *e;
858178825Sdfr    size_t size;
859233294Sstas    int ret;
860233294Sstas    size_t i = 0;
861178825Sdfr
862178825Sdfr    if (_hx509_cert_get_version(cert) < 3)
863178825Sdfr	return 0;
864178825Sdfr
865233294Sstas    e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i);
866178825Sdfr    if (e == NULL) {
867178825Sdfr	switch(type) {
868178825Sdfr	case PROXY_CERT:
869178825Sdfr	case EE_CERT:
870178825Sdfr	    return 0;
871178825Sdfr	case CA_CERT: {
872178825Sdfr	    char *name;
873178825Sdfr	    ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name);
874178825Sdfr	    assert(ret == 0);
875178825Sdfr	    hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND,
876178825Sdfr				   "basicConstraints missing from "
877178825Sdfr				   "CA certifiacte %s", name);
878178825Sdfr	    free(name);
879178825Sdfr	    return HX509_EXTENSION_NOT_FOUND;
880178825Sdfr	}
881178825Sdfr	}
882178825Sdfr    }
883233294Sstas
884233294Sstas    ret = decode_BasicConstraints(e->extnValue.data,
885178825Sdfr				  e->extnValue.length, &bc,
886178825Sdfr				  &size);
887178825Sdfr    if (ret)
888178825Sdfr	return ret;
889178825Sdfr    switch(type) {
890178825Sdfr    case PROXY_CERT:
891178825Sdfr	if (bc.cA != NULL && *bc.cA)
892178825Sdfr	    ret = HX509_PARENT_IS_CA;
893178825Sdfr	break;
894178825Sdfr    case EE_CERT:
895178825Sdfr	ret = 0;
896178825Sdfr	break;
897178825Sdfr    case CA_CERT:
898178825Sdfr	if (bc.cA == NULL || !*bc.cA)
899178825Sdfr	    ret = HX509_PARENT_NOT_CA;
900178825Sdfr	else if (bc.pathLenConstraint)
901178825Sdfr	    if (depth - 1 > *bc.pathLenConstraint)
902178825Sdfr		ret = HX509_CA_PATH_TOO_DEEP;
903178825Sdfr	break;
904178825Sdfr    }
905178825Sdfr    free_BasicConstraints(&bc);
906178825Sdfr    return ret;
907178825Sdfr}
908178825Sdfr
909178825Sdfrint
910178825Sdfr_hx509_cert_is_parent_cmp(const Certificate *subject,
911178825Sdfr			  const Certificate *issuer,
912178825Sdfr			  int allow_self_signed)
913178825Sdfr{
914178825Sdfr    int diff;
915178825Sdfr    AuthorityKeyIdentifier ai;
916178825Sdfr    SubjectKeyIdentifier si;
917233294Sstas    int ret_ai, ret_si, ret;
918178825Sdfr
919233294Sstas    ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
920233294Sstas			  &subject->tbsCertificate.issuer,
921233294Sstas			  &diff);
922233294Sstas    if (ret)
923233294Sstas	return ret;
924178825Sdfr    if (diff)
925178825Sdfr	return diff;
926233294Sstas
927178825Sdfr    memset(&ai, 0, sizeof(ai));
928178825Sdfr    memset(&si, 0, sizeof(si));
929178825Sdfr
930178825Sdfr    /*
931178825Sdfr     * Try to find AuthorityKeyIdentifier, if it's not present in the
932178825Sdfr     * subject certificate nor the parent.
933178825Sdfr     */
934178825Sdfr
935178825Sdfr    ret_ai = find_extension_auth_key_id(subject, &ai);
936178825Sdfr    if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND)
937178825Sdfr	return 1;
938178825Sdfr    ret_si = _hx509_find_extension_subject_key_id(issuer, &si);
939178825Sdfr    if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND)
940178825Sdfr	return -1;
941178825Sdfr
942178825Sdfr    if (ret_si && ret_ai)
943178825Sdfr	goto out;
944178825Sdfr    if (ret_ai)
945178825Sdfr	goto out;
946178825Sdfr    if (ret_si) {
947178825Sdfr	if (allow_self_signed) {
948178825Sdfr	    diff = 0;
949178825Sdfr	    goto out;
950178825Sdfr	} else if (ai.keyIdentifier) {
951178825Sdfr	    diff = -1;
952178825Sdfr	    goto out;
953178825Sdfr	}
954178825Sdfr    }
955233294Sstas
956178825Sdfr    if (ai.keyIdentifier == NULL) {
957178825Sdfr	Name name;
958178825Sdfr
959178825Sdfr	if (ai.authorityCertIssuer == NULL)
960178825Sdfr	    return -1;
961178825Sdfr	if (ai.authorityCertSerialNumber == NULL)
962178825Sdfr	    return -1;
963178825Sdfr
964233294Sstas	diff = der_heim_integer_cmp(ai.authorityCertSerialNumber,
965178825Sdfr				    &issuer->tbsCertificate.serialNumber);
966178825Sdfr	if (diff)
967178825Sdfr	    return diff;
968178825Sdfr	if (ai.authorityCertIssuer->len != 1)
969178825Sdfr	    return -1;
970178825Sdfr	if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName)
971178825Sdfr	    return -1;
972233294Sstas
973233294Sstas	name.element =
974178825Sdfr	    ai.authorityCertIssuer->val[0].u.directoryName.element;
975233294Sstas	name.u.rdnSequence =
976178825Sdfr	    ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence;
977178825Sdfr
978233294Sstas	ret = _hx509_name_cmp(&issuer->tbsCertificate.subject,
979233294Sstas			      &name,
980233294Sstas			      &diff);
981233294Sstas	if (ret)
982233294Sstas	    return ret;
983178825Sdfr	if (diff)
984178825Sdfr	    return diff;
985178825Sdfr	diff = 0;
986178825Sdfr    } else
987178825Sdfr	diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si);
988178825Sdfr    if (diff)
989178825Sdfr	goto out;
990178825Sdfr
991178825Sdfr out:
992178825Sdfr    free_AuthorityKeyIdentifier(&ai);
993178825Sdfr    free_SubjectKeyIdentifier(&si);
994178825Sdfr    return diff;
995178825Sdfr}
996178825Sdfr
997178825Sdfrstatic int
998178825Sdfrcertificate_is_anchor(hx509_context context,
999178825Sdfr		      hx509_certs trust_anchors,
1000178825Sdfr		      const hx509_cert cert)
1001178825Sdfr{
1002178825Sdfr    hx509_query q;
1003178825Sdfr    hx509_cert c;
1004178825Sdfr    int ret;
1005178825Sdfr
1006178825Sdfr    if (trust_anchors == NULL)
1007178825Sdfr	return 0;
1008178825Sdfr
1009178825Sdfr    _hx509_query_clear(&q);
1010178825Sdfr
1011178825Sdfr    q.match = HX509_QUERY_MATCH_CERTIFICATE;
1012178825Sdfr    q.certificate = _hx509_get_cert(cert);
1013178825Sdfr
1014178825Sdfr    ret = hx509_certs_find(context, trust_anchors, &q, &c);
1015178825Sdfr    if (ret == 0)
1016178825Sdfr	hx509_cert_free(c);
1017178825Sdfr    return ret == 0;
1018178825Sdfr}
1019178825Sdfr
1020178825Sdfrstatic int
1021233294Sstascertificate_is_self_signed(hx509_context context,
1022233294Sstas			   const Certificate *cert,
1023233294Sstas			   int *self_signed)
1024178825Sdfr{
1025233294Sstas    int ret, diff;
1026233294Sstas    ret = _hx509_name_cmp(&cert->tbsCertificate.subject,
1027233294Sstas			  &cert->tbsCertificate.issuer, &diff);
1028233294Sstas    *self_signed = (diff == 0);
1029233294Sstas    if (ret) {
1030233294Sstas	hx509_set_error_string(context, 0, ret,
1031233294Sstas			       "Failed to check if self signed");
1032233294Sstas    } else
1033233294Sstas	ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm);
1034233294Sstas
1035233294Sstas    return ret;
1036178825Sdfr}
1037178825Sdfr
1038178825Sdfr/*
1039178825Sdfr * The subjectName is "null" when it's empty set of relative DBs.
1040178825Sdfr */
1041178825Sdfr
1042178825Sdfrstatic int
1043178825Sdfrsubject_null_p(const Certificate *c)
1044178825Sdfr{
1045178825Sdfr    return c->tbsCertificate.subject.u.rdnSequence.len == 0;
1046178825Sdfr}
1047178825Sdfr
1048178825Sdfr
1049178825Sdfrstatic int
1050178825Sdfrfind_parent(hx509_context context,
1051178825Sdfr	    time_t time_now,
1052178825Sdfr	    hx509_certs trust_anchors,
1053178825Sdfr	    hx509_path *path,
1054233294Sstas	    hx509_certs pool,
1055178825Sdfr	    hx509_cert current,
1056178825Sdfr	    hx509_cert *parent)
1057178825Sdfr{
1058178825Sdfr    AuthorityKeyIdentifier ai;
1059178825Sdfr    hx509_query q;
1060178825Sdfr    int ret;
1061178825Sdfr
1062178825Sdfr    *parent = NULL;
1063178825Sdfr    memset(&ai, 0, sizeof(ai));
1064233294Sstas
1065178825Sdfr    _hx509_query_clear(&q);
1066178825Sdfr
1067178825Sdfr    if (!subject_null_p(current->data)) {
1068178825Sdfr	q.match |= HX509_QUERY_FIND_ISSUER_CERT;
1069178825Sdfr	q.subject = _hx509_get_cert(current);
1070178825Sdfr    } else {
1071178825Sdfr	ret = find_extension_auth_key_id(current->data, &ai);
1072178825Sdfr	if (ret) {
1073178825Sdfr	    hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1074178825Sdfr				   "Subjectless certificate missing AuthKeyID");
1075178825Sdfr	    return HX509_CERTIFICATE_MALFORMED;
1076178825Sdfr	}
1077178825Sdfr
1078178825Sdfr	if (ai.keyIdentifier == NULL) {
1079178825Sdfr	    free_AuthorityKeyIdentifier(&ai);
1080178825Sdfr	    hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED,
1081178825Sdfr				   "Subjectless certificate missing keyIdentifier "
1082178825Sdfr				   "inside AuthKeyID");
1083178825Sdfr	    return HX509_CERTIFICATE_MALFORMED;
1084178825Sdfr	}
1085178825Sdfr
1086178825Sdfr	q.subject_id = ai.keyIdentifier;
1087178825Sdfr	q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
1088178825Sdfr    }
1089178825Sdfr
1090178825Sdfr    q.path = path;
1091178825Sdfr    q.match |= HX509_QUERY_NO_MATCH_PATH;
1092178825Sdfr
1093178825Sdfr    if (pool) {
1094178825Sdfr	q.timenow = time_now;
1095178825Sdfr	q.match |= HX509_QUERY_MATCH_TIME;
1096178825Sdfr
1097178825Sdfr	ret = hx509_certs_find(context, pool, &q, parent);
1098178825Sdfr	if (ret == 0) {
1099178825Sdfr	    free_AuthorityKeyIdentifier(&ai);
1100178825Sdfr	    return 0;
1101178825Sdfr	}
1102178825Sdfr	q.match &= ~HX509_QUERY_MATCH_TIME;
1103178825Sdfr    }
1104178825Sdfr
1105178825Sdfr    if (trust_anchors) {
1106178825Sdfr	ret = hx509_certs_find(context, trust_anchors, &q, parent);
1107178825Sdfr	if (ret == 0) {
1108178825Sdfr	    free_AuthorityKeyIdentifier(&ai);
1109178825Sdfr	    return ret;
1110178825Sdfr	}
1111178825Sdfr    }
1112178825Sdfr    free_AuthorityKeyIdentifier(&ai);
1113178825Sdfr
1114178825Sdfr    {
1115178825Sdfr	hx509_name name;
1116178825Sdfr	char *str;
1117178825Sdfr
1118178825Sdfr	ret = hx509_cert_get_subject(current, &name);
1119178825Sdfr	if (ret) {
1120178825Sdfr	    hx509_clear_error_string(context);
1121178825Sdfr	    return HX509_ISSUER_NOT_FOUND;
1122178825Sdfr	}
1123178825Sdfr	ret = hx509_name_to_string(name, &str);
1124178825Sdfr	hx509_name_free(&name);
1125178825Sdfr	if (ret) {
1126178825Sdfr	    hx509_clear_error_string(context);
1127178825Sdfr	    return HX509_ISSUER_NOT_FOUND;
1128178825Sdfr	}
1129233294Sstas
1130178825Sdfr	hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND,
1131178825Sdfr			       "Failed to find issuer for "
1132178825Sdfr			       "certificate with subject: '%s'", str);
1133178825Sdfr	free(str);
1134178825Sdfr    }
1135178825Sdfr    return HX509_ISSUER_NOT_FOUND;
1136178825Sdfr}
1137178825Sdfr
1138178825Sdfr/*
1139178825Sdfr *
1140178825Sdfr */
1141178825Sdfr
1142178825Sdfrstatic int
1143233294Sstasis_proxy_cert(hx509_context context,
1144233294Sstas	      const Certificate *cert,
1145178825Sdfr	      ProxyCertInfo *rinfo)
1146178825Sdfr{
1147178825Sdfr    ProxyCertInfo info;
1148178825Sdfr    const Extension *e;
1149178825Sdfr    size_t size;
1150233294Sstas    int ret;
1151233294Sstas    size_t i = 0;
1152178825Sdfr
1153178825Sdfr    if (rinfo)
1154178825Sdfr	memset(rinfo, 0, sizeof(*rinfo));
1155178825Sdfr
1156233294Sstas    e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i);
1157178825Sdfr    if (e == NULL) {
1158178825Sdfr	hx509_clear_error_string(context);
1159178825Sdfr	return HX509_EXTENSION_NOT_FOUND;
1160178825Sdfr    }
1161178825Sdfr
1162233294Sstas    ret = decode_ProxyCertInfo(e->extnValue.data,
1163233294Sstas			       e->extnValue.length,
1164178825Sdfr			       &info,
1165178825Sdfr			       &size);
1166178825Sdfr    if (ret) {
1167178825Sdfr	hx509_clear_error_string(context);
1168178825Sdfr	return ret;
1169178825Sdfr    }
1170178825Sdfr    if (size != e->extnValue.length) {
1171178825Sdfr	free_ProxyCertInfo(&info);
1172178825Sdfr	hx509_clear_error_string(context);
1173233294Sstas	return HX509_EXTRA_DATA_AFTER_STRUCTURE;
1174178825Sdfr    }
1175178825Sdfr    if (rinfo == NULL)
1176178825Sdfr	free_ProxyCertInfo(&info);
1177178825Sdfr    else
1178178825Sdfr	*rinfo = info;
1179178825Sdfr
1180178825Sdfr    return 0;
1181178825Sdfr}
1182178825Sdfr
1183178825Sdfr/*
1184178825Sdfr * Path operations are like MEMORY based keyset, but with exposed
1185178825Sdfr * internal so we can do easy searches.
1186178825Sdfr */
1187178825Sdfr
1188178825Sdfrint
1189178825Sdfr_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert)
1190178825Sdfr{
1191178825Sdfr    hx509_cert *val;
1192178825Sdfr    val = realloc(path->val, (path->len + 1) * sizeof(path->val[0]));
1193178825Sdfr    if (val == NULL) {
1194178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
1195178825Sdfr	return ENOMEM;
1196178825Sdfr    }
1197178825Sdfr
1198178825Sdfr    path->val = val;
1199178825Sdfr    path->val[path->len] = hx509_cert_ref(cert);
1200178825Sdfr    path->len++;
1201178825Sdfr
1202178825Sdfr    return 0;
1203178825Sdfr}
1204178825Sdfr
1205178825Sdfrvoid
1206178825Sdfr_hx509_path_free(hx509_path *path)
1207178825Sdfr{
1208178825Sdfr    unsigned i;
1209233294Sstas
1210178825Sdfr    for (i = 0; i < path->len; i++)
1211178825Sdfr	hx509_cert_free(path->val[i]);
1212178825Sdfr    free(path->val);
1213178825Sdfr    path->val = NULL;
1214178825Sdfr    path->len = 0;
1215178825Sdfr}
1216178825Sdfr
1217178825Sdfr/*
1218178825Sdfr * Find path by looking up issuer for the top certificate and continue
1219178825Sdfr * until an anchor certificate is found or max limit is found. A
1220178825Sdfr * certificate never included twice in the path.
1221178825Sdfr *
1222178825Sdfr * If the trust anchors are not given, calculate optimistic path, just
1223178825Sdfr * follow the chain upward until we no longer find a parent or we hit
1224178825Sdfr * the max path limit. In this case, a failure will always be returned
1225178825Sdfr * depending on what error condition is hit first.
1226178825Sdfr *
1227178825Sdfr * The path includes a path from the top certificate to the anchor
1228178825Sdfr * certificate.
1229178825Sdfr *
1230233294Sstas * The caller needs to free `path�� both on successful built path and
1231178825Sdfr * failure.
1232178825Sdfr */
1233178825Sdfr
1234178825Sdfrint
1235178825Sdfr_hx509_calculate_path(hx509_context context,
1236178825Sdfr		      int flags,
1237178825Sdfr		      time_t time_now,
1238178825Sdfr		      hx509_certs anchors,
1239178825Sdfr		      unsigned int max_depth,
1240178825Sdfr		      hx509_cert cert,
1241178825Sdfr		      hx509_certs pool,
1242178825Sdfr		      hx509_path *path)
1243178825Sdfr{
1244178825Sdfr    hx509_cert parent, current;
1245178825Sdfr    int ret;
1246178825Sdfr
1247178825Sdfr    if (max_depth == 0)
1248178825Sdfr	max_depth = HX509_VERIFY_MAX_DEPTH;
1249178825Sdfr
1250178825Sdfr    ret = _hx509_path_append(context, path, cert);
1251178825Sdfr    if (ret)
1252178825Sdfr	return ret;
1253178825Sdfr
1254178825Sdfr    current = hx509_cert_ref(cert);
1255178825Sdfr
1256178825Sdfr    while (!certificate_is_anchor(context, anchors, current)) {
1257178825Sdfr
1258233294Sstas	ret = find_parent(context, time_now, anchors, path,
1259178825Sdfr			  pool, current, &parent);
1260178825Sdfr	hx509_cert_free(current);
1261178825Sdfr	if (ret)
1262178825Sdfr	    return ret;
1263178825Sdfr
1264178825Sdfr	ret = _hx509_path_append(context, path, parent);
1265178825Sdfr	if (ret)
1266178825Sdfr	    return ret;
1267178825Sdfr	current = parent;
1268178825Sdfr
1269178825Sdfr	if (path->len > max_depth) {
1270178825Sdfr	    hx509_cert_free(current);
1271178825Sdfr	    hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG,
1272178825Sdfr				   "Path too long while bulding "
1273178825Sdfr				   "certificate chain");
1274178825Sdfr	    return HX509_PATH_TOO_LONG;
1275178825Sdfr	}
1276178825Sdfr    }
1277178825Sdfr
1278233294Sstas    if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) &&
1279233294Sstas	path->len > 0 &&
1280178825Sdfr	certificate_is_anchor(context, anchors, path->val[path->len - 1]))
1281178825Sdfr    {
1282178825Sdfr	hx509_cert_free(path->val[path->len - 1]);
1283178825Sdfr	path->len--;
1284178825Sdfr    }
1285178825Sdfr
1286178825Sdfr    hx509_cert_free(current);
1287178825Sdfr    return 0;
1288178825Sdfr}
1289178825Sdfr
1290178825Sdfrint
1291178825Sdfr_hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p,
1292178825Sdfr			       const AlgorithmIdentifier *q)
1293178825Sdfr{
1294178825Sdfr    int diff;
1295178825Sdfr    diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1296178825Sdfr    if (diff)
1297178825Sdfr	return diff;
1298178825Sdfr    if (p->parameters) {
1299178825Sdfr	if (q->parameters)
1300178825Sdfr	    return heim_any_cmp(p->parameters,
1301178825Sdfr				q->parameters);
1302178825Sdfr	else
1303178825Sdfr	    return 1;
1304178825Sdfr    } else {
1305178825Sdfr	if (q->parameters)
1306178825Sdfr	    return -1;
1307178825Sdfr	else
1308178825Sdfr	    return 0;
1309178825Sdfr    }
1310178825Sdfr}
1311178825Sdfr
1312178825Sdfrint
1313178825Sdfr_hx509_Certificate_cmp(const Certificate *p, const Certificate *q)
1314178825Sdfr{
1315178825Sdfr    int diff;
1316178825Sdfr    diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue);
1317178825Sdfr    if (diff)
1318178825Sdfr	return diff;
1319233294Sstas    diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm,
1320178825Sdfr					  &q->signatureAlgorithm);
1321178825Sdfr    if (diff)
1322178825Sdfr	return diff;
1323178825Sdfr    diff = der_heim_octet_string_cmp(&p->tbsCertificate._save,
1324178825Sdfr				     &q->tbsCertificate._save);
1325178825Sdfr    return diff;
1326178825Sdfr}
1327178825Sdfr
1328178825Sdfr/**
1329178825Sdfr * Compare to hx509 certificate object, useful for sorting.
1330178825Sdfr *
1331178825Sdfr * @param p a hx509 certificate object.
1332178825Sdfr * @param q a hx509 certificate object.
1333178825Sdfr *
1334178825Sdfr * @return 0 the objects are the same, returns > 0 is p is "larger"
1335178825Sdfr * then q, < 0 if p is "smaller" then q.
1336178825Sdfr *
1337178825Sdfr * @ingroup hx509_cert
1338178825Sdfr */
1339178825Sdfr
1340178825Sdfrint
1341178825Sdfrhx509_cert_cmp(hx509_cert p, hx509_cert q)
1342178825Sdfr{
1343178825Sdfr    return _hx509_Certificate_cmp(p->data, q->data);
1344178825Sdfr}
1345178825Sdfr
1346178825Sdfr/**
1347178825Sdfr * Return the name of the issuer of the hx509 certificate.
1348178825Sdfr *
1349178825Sdfr * @param p a hx509 certificate object.
1350178825Sdfr * @param name a pointer to a hx509 name, should be freed by
1351178825Sdfr * hx509_name_free().
1352178825Sdfr *
1353178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1354178825Sdfr *
1355178825Sdfr * @ingroup hx509_cert
1356178825Sdfr */
1357178825Sdfr
1358178825Sdfrint
1359178825Sdfrhx509_cert_get_issuer(hx509_cert p, hx509_name *name)
1360178825Sdfr{
1361178825Sdfr    return _hx509_name_from_Name(&p->data->tbsCertificate.issuer, name);
1362178825Sdfr}
1363178825Sdfr
1364178825Sdfr/**
1365178825Sdfr * Return the name of the subject of the hx509 certificate.
1366178825Sdfr *
1367178825Sdfr * @param p a hx509 certificate object.
1368178825Sdfr * @param name a pointer to a hx509 name, should be freed by
1369178825Sdfr * hx509_name_free(). See also hx509_cert_get_base_subject().
1370178825Sdfr *
1371178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1372178825Sdfr *
1373178825Sdfr * @ingroup hx509_cert
1374178825Sdfr */
1375178825Sdfr
1376178825Sdfrint
1377178825Sdfrhx509_cert_get_subject(hx509_cert p, hx509_name *name)
1378178825Sdfr{
1379178825Sdfr    return _hx509_name_from_Name(&p->data->tbsCertificate.subject, name);
1380178825Sdfr}
1381178825Sdfr
1382178825Sdfr/**
1383178825Sdfr * Return the name of the base subject of the hx509 certificate. If
1384178825Sdfr * the certiicate is a verified proxy certificate, the this function
1385178825Sdfr * return the base certificate (root of the proxy chain). If the proxy
1386178825Sdfr * certificate is not verified with the base certificate
1387178825Sdfr * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned.
1388178825Sdfr *
1389178825Sdfr * @param context a hx509 context.
1390178825Sdfr * @param c a hx509 certificate object.
1391178825Sdfr * @param name a pointer to a hx509 name, should be freed by
1392178825Sdfr * hx509_name_free(). See also hx509_cert_get_subject().
1393178825Sdfr *
1394178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1395178825Sdfr *
1396178825Sdfr * @ingroup hx509_cert
1397178825Sdfr */
1398178825Sdfr
1399178825Sdfrint
1400178825Sdfrhx509_cert_get_base_subject(hx509_context context, hx509_cert c,
1401178825Sdfr			    hx509_name *name)
1402178825Sdfr{
1403178825Sdfr    if (c->basename)
1404178825Sdfr	return hx509_name_copy(context, c->basename, name);
1405178825Sdfr    if (is_proxy_cert(context, c->data, NULL) == 0) {
1406178825Sdfr	int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED;
1407178825Sdfr	hx509_set_error_string(context, 0, ret,
1408178825Sdfr			       "Proxy certificate have not been "
1409178825Sdfr			       "canonicalize yet, no base name");
1410178825Sdfr	return ret;
1411178825Sdfr    }
1412178825Sdfr    return _hx509_name_from_Name(&c->data->tbsCertificate.subject, name);
1413178825Sdfr}
1414178825Sdfr
1415178825Sdfr/**
1416178825Sdfr * Get serial number of the certificate.
1417178825Sdfr *
1418178825Sdfr * @param p a hx509 certificate object.
1419178825Sdfr * @param i serial number, should be freed ith der_free_heim_integer().
1420178825Sdfr *
1421178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1422178825Sdfr *
1423178825Sdfr * @ingroup hx509_cert
1424178825Sdfr */
1425178825Sdfr
1426178825Sdfrint
1427178825Sdfrhx509_cert_get_serialnumber(hx509_cert p, heim_integer *i)
1428178825Sdfr{
1429178825Sdfr    return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i);
1430178825Sdfr}
1431178825Sdfr
1432178825Sdfr/**
1433178825Sdfr * Get notBefore time of the certificate.
1434178825Sdfr *
1435178825Sdfr * @param p a hx509 certificate object.
1436178825Sdfr *
1437178825Sdfr * @return return not before time
1438178825Sdfr *
1439178825Sdfr * @ingroup hx509_cert
1440178825Sdfr */
1441178825Sdfr
1442178825Sdfrtime_t
1443178825Sdfrhx509_cert_get_notBefore(hx509_cert p)
1444178825Sdfr{
1445178825Sdfr    return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore);
1446178825Sdfr}
1447178825Sdfr
1448178825Sdfr/**
1449178825Sdfr * Get notAfter time of the certificate.
1450178825Sdfr *
1451178825Sdfr * @param p a hx509 certificate object.
1452178825Sdfr *
1453178825Sdfr * @return return not after time.
1454178825Sdfr *
1455178825Sdfr * @ingroup hx509_cert
1456178825Sdfr */
1457178825Sdfr
1458178825Sdfrtime_t
1459178825Sdfrhx509_cert_get_notAfter(hx509_cert p)
1460178825Sdfr{
1461178825Sdfr    return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
1462178825Sdfr}
1463178825Sdfr
1464178825Sdfr/**
1465178825Sdfr * Get the SubjectPublicKeyInfo structure from the hx509 certificate.
1466178825Sdfr *
1467178825Sdfr * @param context a hx509 context.
1468178825Sdfr * @param p a hx509 certificate object.
1469178825Sdfr * @param spki SubjectPublicKeyInfo, should be freed with
1470178825Sdfr * free_SubjectPublicKeyInfo().
1471178825Sdfr *
1472178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1473178825Sdfr *
1474178825Sdfr * @ingroup hx509_cert
1475178825Sdfr */
1476178825Sdfr
1477178825Sdfrint
1478178825Sdfrhx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki)
1479178825Sdfr{
1480178825Sdfr    int ret;
1481178825Sdfr
1482178825Sdfr    ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki);
1483178825Sdfr    if (ret)
1484178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed to copy SPKI");
1485178825Sdfr    return ret;
1486178825Sdfr}
1487178825Sdfr
1488178825Sdfr/**
1489178825Sdfr * Get the AlgorithmIdentifier from the hx509 certificate.
1490178825Sdfr *
1491178825Sdfr * @param context a hx509 context.
1492178825Sdfr * @param p a hx509 certificate object.
1493178825Sdfr * @param alg AlgorithmIdentifier, should be freed with
1494233294Sstas *            free_AlgorithmIdentifier(). The algorithmidentifier is
1495233294Sstas *            typicly rsaEncryption, or id-ecPublicKey, or some other
1496233294Sstas *            public key mechanism.
1497178825Sdfr *
1498178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1499178825Sdfr *
1500178825Sdfr * @ingroup hx509_cert
1501178825Sdfr */
1502178825Sdfr
1503178825Sdfrint
1504178825Sdfrhx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context,
1505233294Sstas					hx509_cert p,
1506178825Sdfr					AlgorithmIdentifier *alg)
1507178825Sdfr{
1508178825Sdfr    int ret;
1509178825Sdfr
1510178825Sdfr    ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg);
1511178825Sdfr    if (ret)
1512178825Sdfr	hx509_set_error_string(context, 0, ret,
1513178825Sdfr			       "Failed to copy SPKI AlgorithmIdentifier");
1514178825Sdfr    return ret;
1515178825Sdfr}
1516178825Sdfr
1517233294Sstasstatic int
1518233294Sstasget_x_unique_id(hx509_context context, const char *name,
1519233294Sstas		const heim_bit_string *cert, heim_bit_string *subject)
1520233294Sstas{
1521233294Sstas    int ret;
1522178825Sdfr
1523233294Sstas    if (cert == NULL) {
1524233294Sstas	ret = HX509_EXTENSION_NOT_FOUND;
1525233294Sstas	hx509_set_error_string(context, 0, ret, "%s unique id doesn't exists", name);
1526233294Sstas	return ret;
1527233294Sstas    }
1528233294Sstas    ret = der_copy_bit_string(cert, subject);
1529233294Sstas    if (ret) {
1530233294Sstas	hx509_set_error_string(context, 0, ret, "malloc out of memory", name);
1531233294Sstas	return ret;
1532233294Sstas    }
1533233294Sstas    return 0;
1534233294Sstas}
1535233294Sstas
1536233294Sstas/**
1537233294Sstas * Get a copy of the Issuer Unique ID
1538233294Sstas *
1539233294Sstas * @param context a hx509_context
1540233294Sstas * @param p a hx509 certificate
1541233294Sstas * @param issuer the issuer id returned, free with der_free_bit_string()
1542233294Sstas *
1543233294Sstas * @return An hx509 error code, see hx509_get_error_string(). The
1544233294Sstas * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1545233294Sstas * doesn't have a issuerUniqueID
1546233294Sstas *
1547233294Sstas * @ingroup hx509_cert
1548233294Sstas */
1549233294Sstas
1550233294Sstasint
1551233294Sstashx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer)
1552233294Sstas{
1553233294Sstas    return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer);
1554233294Sstas}
1555233294Sstas
1556233294Sstas/**
1557233294Sstas * Get a copy of the Subect Unique ID
1558233294Sstas *
1559233294Sstas * @param context a hx509_context
1560233294Sstas * @param p a hx509 certificate
1561233294Sstas * @param subject the subject id returned, free with der_free_bit_string()
1562233294Sstas *
1563233294Sstas * @return An hx509 error code, see hx509_get_error_string(). The
1564233294Sstas * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate
1565233294Sstas * doesn't have a subjectUniqueID
1566233294Sstas *
1567233294Sstas * @ingroup hx509_cert
1568233294Sstas */
1569233294Sstas
1570233294Sstasint
1571233294Sstashx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject)
1572233294Sstas{
1573233294Sstas    return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject);
1574233294Sstas}
1575233294Sstas
1576233294Sstas
1577178825Sdfrhx509_private_key
1578178825Sdfr_hx509_cert_private_key(hx509_cert p)
1579178825Sdfr{
1580178825Sdfr    return p->private_key;
1581178825Sdfr}
1582178825Sdfr
1583178825Sdfrint
1584178825Sdfrhx509_cert_have_private_key(hx509_cert p)
1585178825Sdfr{
1586178825Sdfr    return p->private_key ? 1 : 0;
1587178825Sdfr}
1588178825Sdfr
1589178825Sdfr
1590178825Sdfrint
1591178825Sdfr_hx509_cert_private_key_exportable(hx509_cert p)
1592178825Sdfr{
1593178825Sdfr    if (p->private_key == NULL)
1594178825Sdfr	return 0;
1595178825Sdfr    return _hx509_private_key_exportable(p->private_key);
1596178825Sdfr}
1597178825Sdfr
1598178825Sdfrint
1599178825Sdfr_hx509_cert_private_decrypt(hx509_context context,
1600178825Sdfr			    const heim_octet_string *ciphertext,
1601178825Sdfr			    const heim_oid *encryption_oid,
1602178825Sdfr			    hx509_cert p,
1603178825Sdfr			    heim_octet_string *cleartext)
1604178825Sdfr{
1605178825Sdfr    cleartext->data = NULL;
1606178825Sdfr    cleartext->length = 0;
1607178825Sdfr
1608178825Sdfr    if (p->private_key == NULL) {
1609178825Sdfr	hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1610178825Sdfr			       "Private key missing");
1611178825Sdfr	return HX509_PRIVATE_KEY_MISSING;
1612178825Sdfr    }
1613178825Sdfr
1614233294Sstas    return hx509_private_key_private_decrypt(context,
1615178825Sdfr					      ciphertext,
1616178825Sdfr					      encryption_oid,
1617233294Sstas					      p->private_key,
1618178825Sdfr					      cleartext);
1619178825Sdfr}
1620178825Sdfr
1621178825Sdfrint
1622233294Sstashx509_cert_public_encrypt(hx509_context context,
1623178825Sdfr			   const heim_octet_string *cleartext,
1624178825Sdfr			   const hx509_cert p,
1625178825Sdfr			   heim_oid *encryption_oid,
1626178825Sdfr			   heim_octet_string *ciphertext)
1627178825Sdfr{
1628178825Sdfr    return _hx509_public_encrypt(context,
1629178825Sdfr				 cleartext, p->data,
1630178825Sdfr				 encryption_oid, ciphertext);
1631178825Sdfr}
1632178825Sdfr
1633178825Sdfr/*
1634178825Sdfr *
1635178825Sdfr */
1636178825Sdfr
1637178825Sdfrtime_t
1638178825Sdfr_hx509_Time2time_t(const Time *t)
1639178825Sdfr{
1640178825Sdfr    switch(t->element) {
1641178825Sdfr    case choice_Time_utcTime:
1642178825Sdfr	return t->u.utcTime;
1643178825Sdfr    case choice_Time_generalTime:
1644178825Sdfr	return t->u.generalTime;
1645178825Sdfr    }
1646178825Sdfr    return 0;
1647178825Sdfr}
1648178825Sdfr
1649178825Sdfr/*
1650178825Sdfr *
1651178825Sdfr */
1652178825Sdfr
1653178825Sdfrstatic int
1654178825Sdfrinit_name_constraints(hx509_name_constraints *nc)
1655178825Sdfr{
1656178825Sdfr    memset(nc, 0, sizeof(*nc));
1657178825Sdfr    return 0;
1658178825Sdfr}
1659178825Sdfr
1660178825Sdfrstatic int
1661178825Sdfradd_name_constraints(hx509_context context, const Certificate *c, int not_ca,
1662178825Sdfr		     hx509_name_constraints *nc)
1663178825Sdfr{
1664178825Sdfr    NameConstraints tnc;
1665178825Sdfr    int ret;
1666178825Sdfr
1667178825Sdfr    ret = find_extension_name_constraints(c, &tnc);
1668178825Sdfr    if (ret == HX509_EXTENSION_NOT_FOUND)
1669178825Sdfr	return 0;
1670178825Sdfr    else if (ret) {
1671178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints");
1672178825Sdfr	return ret;
1673178825Sdfr    } else if (not_ca) {
1674178825Sdfr	ret = HX509_VERIFY_CONSTRAINTS;
1675178825Sdfr	hx509_set_error_string(context, 0, ret, "Not a CA and "
1676178825Sdfr			       "have NameConstraints");
1677178825Sdfr    } else {
1678178825Sdfr	NameConstraints *val;
1679178825Sdfr	val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1));
1680178825Sdfr	if (val == NULL) {
1681178825Sdfr	    hx509_clear_error_string(context);
1682178825Sdfr	    ret = ENOMEM;
1683178825Sdfr	    goto out;
1684178825Sdfr	}
1685178825Sdfr	nc->val = val;
1686178825Sdfr	ret = copy_NameConstraints(&tnc, &nc->val[nc->len]);
1687178825Sdfr	if (ret) {
1688178825Sdfr	    hx509_clear_error_string(context);
1689178825Sdfr	    goto out;
1690178825Sdfr	}
1691178825Sdfr	nc->len += 1;
1692178825Sdfr    }
1693178825Sdfrout:
1694178825Sdfr    free_NameConstraints(&tnc);
1695178825Sdfr    return ret;
1696178825Sdfr}
1697178825Sdfr
1698178825Sdfrstatic int
1699178825Sdfrmatch_RDN(const RelativeDistinguishedName *c,
1700178825Sdfr	  const RelativeDistinguishedName *n)
1701178825Sdfr{
1702233294Sstas    size_t i;
1703178825Sdfr
1704178825Sdfr    if (c->len != n->len)
1705178825Sdfr	return HX509_NAME_CONSTRAINT_ERROR;
1706233294Sstas
1707178825Sdfr    for (i = 0; i < n->len; i++) {
1708233294Sstas	int diff, ret;
1709233294Sstas
1710178825Sdfr	if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0)
1711178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1712233294Sstas	ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff);
1713233294Sstas	if (ret)
1714233294Sstas	    return ret;
1715233294Sstas	if (diff != 0)
1716178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1717178825Sdfr    }
1718178825Sdfr    return 0;
1719178825Sdfr}
1720178825Sdfr
1721178825Sdfrstatic int
1722178825Sdfrmatch_X501Name(const Name *c, const Name *n)
1723178825Sdfr{
1724233294Sstas    size_t i;
1725233294Sstas    int ret;
1726178825Sdfr
1727178825Sdfr    if (c->element != choice_Name_rdnSequence
1728178825Sdfr	|| n->element != choice_Name_rdnSequence)
1729178825Sdfr	return 0;
1730178825Sdfr    if (c->u.rdnSequence.len > n->u.rdnSequence.len)
1731178825Sdfr	return HX509_NAME_CONSTRAINT_ERROR;
1732178825Sdfr    for (i = 0; i < c->u.rdnSequence.len; i++) {
1733178825Sdfr	ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]);
1734178825Sdfr	if (ret)
1735178825Sdfr	    return ret;
1736178825Sdfr    }
1737178825Sdfr    return 0;
1738233294Sstas}
1739178825Sdfr
1740178825Sdfr
1741178825Sdfrstatic int
1742178825Sdfrmatch_general_name(const GeneralName *c, const GeneralName *n, int *match)
1743178825Sdfr{
1744233294Sstas    /*
1745178825Sdfr     * Name constraints only apply to the same name type, see RFC3280,
1746178825Sdfr     * 4.2.1.11.
1747178825Sdfr     */
1748178825Sdfr    assert(c->element == n->element);
1749178825Sdfr
1750178825Sdfr    switch(c->element) {
1751178825Sdfr    case choice_GeneralName_otherName:
1752178825Sdfr	if (der_heim_oid_cmp(&c->u.otherName.type_id,
1753178825Sdfr			 &n->u.otherName.type_id) != 0)
1754178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1755178825Sdfr	if (heim_any_cmp(&c->u.otherName.value,
1756178825Sdfr			 &n->u.otherName.value) != 0)
1757178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1758178825Sdfr	*match = 1;
1759178825Sdfr	return 0;
1760178825Sdfr    case choice_GeneralName_rfc822Name: {
1761178825Sdfr	const char *s;
1762178825Sdfr	size_t len1, len2;
1763233294Sstas	s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length);
1764178825Sdfr	if (s) {
1765233294Sstas	    if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0)
1766178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1767178825Sdfr	} else {
1768233294Sstas	    s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length);
1769178825Sdfr	    if (s == NULL)
1770178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1771233294Sstas	    len1 = c->u.rfc822Name.length;
1772233294Sstas	    len2 = n->u.rfc822Name.length -
1773233294Sstas		(s - ((char *)n->u.rfc822Name.data));
1774178825Sdfr	    if (len1 > len2)
1775178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1776233294Sstas	    if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0)
1777178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1778178825Sdfr	    if (len1 < len2 && s[len2 - len1 + 1] != '.')
1779178825Sdfr		return HX509_NAME_CONSTRAINT_ERROR;
1780178825Sdfr	}
1781178825Sdfr	*match = 1;
1782178825Sdfr	return 0;
1783178825Sdfr    }
1784178825Sdfr    case choice_GeneralName_dNSName: {
1785178825Sdfr	size_t lenc, lenn;
1786233294Sstas	char *ptr;
1787178825Sdfr
1788233294Sstas	lenc = c->u.dNSName.length;
1789233294Sstas	lenn = n->u.dNSName.length;
1790178825Sdfr	if (lenc > lenn)
1791178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1792233294Sstas	ptr = n->u.dNSName.data;
1793233294Sstas	if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0)
1794178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1795233294Sstas	if (lenn != lenc && ptr[lenn - lenc - 1] != '.')
1796178825Sdfr	    return HX509_NAME_CONSTRAINT_ERROR;
1797178825Sdfr	*match = 1;
1798178825Sdfr	return 0;
1799178825Sdfr    }
1800178825Sdfr    case choice_GeneralName_directoryName: {
1801178825Sdfr	Name c_name, n_name;
1802178825Sdfr	int ret;
1803178825Sdfr
1804178825Sdfr	c_name._save.data = NULL;
1805178825Sdfr	c_name._save.length = 0;
1806178825Sdfr	c_name.element = c->u.directoryName.element;
1807178825Sdfr	c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence;
1808178825Sdfr
1809178825Sdfr	n_name._save.data = NULL;
1810178825Sdfr	n_name._save.length = 0;
1811178825Sdfr	n_name.element = n->u.directoryName.element;
1812178825Sdfr	n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence;
1813178825Sdfr
1814178825Sdfr	ret = match_X501Name(&c_name, &n_name);
1815178825Sdfr	if (ret == 0)
1816178825Sdfr	    *match = 1;
1817178825Sdfr	return ret;
1818178825Sdfr    }
1819178825Sdfr    case choice_GeneralName_uniformResourceIdentifier:
1820178825Sdfr    case choice_GeneralName_iPAddress:
1821178825Sdfr    case choice_GeneralName_registeredID:
1822178825Sdfr    default:
1823178825Sdfr	return HX509_NAME_CONSTRAINT_ERROR;
1824178825Sdfr    }
1825178825Sdfr}
1826178825Sdfr
1827178825Sdfrstatic int
1828233294Sstasmatch_alt_name(const GeneralName *n, const Certificate *c,
1829178825Sdfr	       int *same, int *match)
1830178825Sdfr{
1831178825Sdfr    GeneralNames sa;
1832233294Sstas    int ret;
1833233294Sstas    size_t i, j;
1834178825Sdfr
1835178825Sdfr    i = 0;
1836178825Sdfr    do {
1837178825Sdfr	ret = find_extension_subject_alt_name(c, &i, &sa);
1838178825Sdfr	if (ret == HX509_EXTENSION_NOT_FOUND) {
1839178825Sdfr	    ret = 0;
1840178825Sdfr	    break;
1841178825Sdfr	} else if (ret != 0)
1842178825Sdfr	    break;
1843178825Sdfr
1844178825Sdfr	for (j = 0; j < sa.len; j++) {
1845178825Sdfr	    if (n->element == sa.val[j].element) {
1846178825Sdfr		*same = 1;
1847178825Sdfr		ret = match_general_name(n, &sa.val[j], match);
1848178825Sdfr	    }
1849178825Sdfr	}
1850178825Sdfr	free_GeneralNames(&sa);
1851178825Sdfr    } while (1);
1852178825Sdfr    return ret;
1853178825Sdfr}
1854178825Sdfr
1855178825Sdfr
1856178825Sdfrstatic int
1857178825Sdfrmatch_tree(const GeneralSubtrees *t, const Certificate *c, int *match)
1858178825Sdfr{
1859178825Sdfr    int name, alt_name, same;
1860178825Sdfr    unsigned int i;
1861178825Sdfr    int ret = 0;
1862178825Sdfr
1863178825Sdfr    name = alt_name = same = *match = 0;
1864178825Sdfr    for (i = 0; i < t->len; i++) {
1865178825Sdfr	if (t->val[i].minimum && t->val[i].maximum)
1866178825Sdfr	    return HX509_RANGE;
1867178825Sdfr
1868178825Sdfr	/*
1869178825Sdfr	 * If the constraint apply to directoryNames, test is with
1870178825Sdfr	 * subjectName of the certificate if the certificate have a
1871178825Sdfr	 * non-null (empty) subjectName.
1872178825Sdfr	 */
1873178825Sdfr
1874178825Sdfr	if (t->val[i].base.element == choice_GeneralName_directoryName
1875178825Sdfr	    && !subject_null_p(c))
1876178825Sdfr	{
1877178825Sdfr	    GeneralName certname;
1878233294Sstas
1879178825Sdfr	    memset(&certname, 0, sizeof(certname));
1880178825Sdfr	    certname.element = choice_GeneralName_directoryName;
1881233294Sstas	    certname.u.directoryName.element =
1882178825Sdfr		c->tbsCertificate.subject.element;
1883233294Sstas	    certname.u.directoryName.u.rdnSequence =
1884178825Sdfr		c->tbsCertificate.subject.u.rdnSequence;
1885233294Sstas
1886178825Sdfr	    ret = match_general_name(&t->val[i].base, &certname, &name);
1887178825Sdfr	}
1888178825Sdfr
1889178825Sdfr	/* Handle subjectAltNames, this is icky since they
1890178825Sdfr	 * restrictions only apply if the subjectAltName is of the
1891178825Sdfr	 * same type. So if there have been a match of type, require
1892178825Sdfr	 * altname to be set.
1893178825Sdfr	 */
1894178825Sdfr	ret = match_alt_name(&t->val[i].base, c, &same, &alt_name);
1895178825Sdfr    }
1896178825Sdfr    if (name && (!same || alt_name))
1897178825Sdfr	*match = 1;
1898178825Sdfr    return ret;
1899178825Sdfr}
1900178825Sdfr
1901178825Sdfrstatic int
1902233294Sstascheck_name_constraints(hx509_context context,
1903178825Sdfr		       const hx509_name_constraints *nc,
1904178825Sdfr		       const Certificate *c)
1905178825Sdfr{
1906178825Sdfr    int match, ret;
1907233294Sstas    size_t i;
1908178825Sdfr
1909178825Sdfr    for (i = 0 ; i < nc->len; i++) {
1910178825Sdfr	GeneralSubtrees gs;
1911178825Sdfr
1912178825Sdfr	if (nc->val[i].permittedSubtrees) {
1913178825Sdfr	    GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees);
1914178825Sdfr	    ret = match_tree(&gs, c, &match);
1915178825Sdfr	    if (ret) {
1916178825Sdfr		hx509_clear_error_string(context);
1917178825Sdfr		return ret;
1918178825Sdfr	    }
1919178825Sdfr	    /* allow null subjectNames, they wont matches anything */
1920178825Sdfr	    if (match == 0 && !subject_null_p(c)) {
1921178825Sdfr		hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1922178825Sdfr				       "Error verify constraints, "
1923178825Sdfr				       "certificate didn't match any "
1924178825Sdfr				       "permitted subtree");
1925178825Sdfr		return HX509_VERIFY_CONSTRAINTS;
1926178825Sdfr	    }
1927178825Sdfr	}
1928178825Sdfr	if (nc->val[i].excludedSubtrees) {
1929178825Sdfr	    GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees);
1930178825Sdfr	    ret = match_tree(&gs, c, &match);
1931178825Sdfr	    if (ret) {
1932178825Sdfr		hx509_clear_error_string(context);
1933178825Sdfr		return ret;
1934178825Sdfr	    }
1935178825Sdfr	    if (match) {
1936178825Sdfr		hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS,
1937178825Sdfr				       "Error verify constraints, "
1938178825Sdfr				       "certificate included in excluded "
1939178825Sdfr				       "subtree");
1940178825Sdfr		return HX509_VERIFY_CONSTRAINTS;
1941178825Sdfr	    }
1942178825Sdfr	}
1943178825Sdfr    }
1944178825Sdfr    return 0;
1945178825Sdfr}
1946178825Sdfr
1947178825Sdfrstatic void
1948178825Sdfrfree_name_constraints(hx509_name_constraints *nc)
1949178825Sdfr{
1950233294Sstas    size_t i;
1951178825Sdfr
1952178825Sdfr    for (i = 0 ; i < nc->len; i++)
1953178825Sdfr	free_NameConstraints(&nc->val[i]);
1954178825Sdfr    free(nc->val);
1955178825Sdfr}
1956178825Sdfr
1957178825Sdfr/**
1958178825Sdfr * Build and verify the path for the certificate to the trust anchor
1959178825Sdfr * specified in the verify context. The path is constructed from the
1960178825Sdfr * certificate, the pool and the trust anchors.
1961178825Sdfr *
1962178825Sdfr * @param context A hx509 context.
1963178825Sdfr * @param ctx A hx509 verification context.
1964178825Sdfr * @param cert the certificate to build the path from.
1965178825Sdfr * @param pool A keyset of certificates to build the chain from.
1966178825Sdfr *
1967178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
1968178825Sdfr *
1969178825Sdfr * @ingroup hx509_verify
1970178825Sdfr */
1971178825Sdfr
1972178825Sdfrint
1973178825Sdfrhx509_verify_path(hx509_context context,
1974178825Sdfr		  hx509_verify_ctx ctx,
1975178825Sdfr		  hx509_cert cert,
1976178825Sdfr		  hx509_certs pool)
1977178825Sdfr{
1978178825Sdfr    hx509_name_constraints nc;
1979178825Sdfr    hx509_path path;
1980233294Sstas    int ret, proxy_cert_depth, selfsigned_depth, diff;
1981233294Sstas    size_t i, k;
1982178825Sdfr    enum certtype type;
1983178825Sdfr    Name proxy_issuer;
1984178825Sdfr    hx509_certs anchors = NULL;
1985178825Sdfr
1986178825Sdfr    memset(&proxy_issuer, 0, sizeof(proxy_issuer));
1987178825Sdfr
1988178825Sdfr    ret = init_name_constraints(&nc);
1989233294Sstas    if (ret)
1990178825Sdfr	return ret;
1991178825Sdfr
1992178825Sdfr    path.val = NULL;
1993178825Sdfr    path.len = 0;
1994178825Sdfr
1995178825Sdfr    if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0)
1996178825Sdfr	ctx->time_now = time(NULL);
1997178825Sdfr
1998178825Sdfr    /*
1999178825Sdfr     *
2000178825Sdfr     */
2001178825Sdfr    if (ctx->trust_anchors)
2002233294Sstas	anchors = hx509_certs_ref(ctx->trust_anchors);
2003178825Sdfr    else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx))
2004233294Sstas	anchors = hx509_certs_ref(context->default_trust_anchors);
2005178825Sdfr    else {
2006178825Sdfr	ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors);
2007178825Sdfr	if (ret)
2008178825Sdfr	    goto out;
2009178825Sdfr    }
2010178825Sdfr
2011178825Sdfr    /*
2012178825Sdfr     * Calculate the path from the certificate user presented to the
2013178825Sdfr     * to an anchor.
2014178825Sdfr     */
2015178825Sdfr    ret = _hx509_calculate_path(context, 0, ctx->time_now,
2016178825Sdfr				anchors, ctx->max_depth,
2017178825Sdfr				cert, pool, &path);
2018178825Sdfr    if (ret)
2019178825Sdfr	goto out;
2020178825Sdfr
2021178825Sdfr    /*
2022178825Sdfr     * Check CA and proxy certificate chain from the top of the
2023178825Sdfr     * certificate chain. Also check certificate is valid with respect
2024178825Sdfr     * to the current time.
2025178825Sdfr     *
2026178825Sdfr     */
2027178825Sdfr
2028178825Sdfr    proxy_cert_depth = 0;
2029178825Sdfr    selfsigned_depth = 0;
2030178825Sdfr
2031178825Sdfr    if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE)
2032178825Sdfr	type = PROXY_CERT;
2033178825Sdfr    else
2034178825Sdfr	type = EE_CERT;
2035178825Sdfr
2036178825Sdfr    for (i = 0; i < path.len; i++) {
2037178825Sdfr	Certificate *c;
2038178825Sdfr	time_t t;
2039178825Sdfr
2040178825Sdfr	c = _hx509_get_cert(path.val[i]);
2041233294Sstas
2042178825Sdfr	/*
2043178825Sdfr	 * Lets do some basic check on issuer like
2044178825Sdfr	 * keyUsage.keyCertSign and basicConstraints.cA bit depending
2045178825Sdfr	 * on what type of certificate this is.
2046178825Sdfr	 */
2047178825Sdfr
2048178825Sdfr	switch (type) {
2049178825Sdfr	case CA_CERT:
2050233294Sstas
2051178825Sdfr	    /* XXX make constants for keyusage */
2052178825Sdfr	    ret = check_key_usage(context, c, 1 << 5,
2053178825Sdfr				  REQUIRE_RFC3280(ctx) ? TRUE : FALSE);
2054178825Sdfr	    if (ret) {
2055178825Sdfr		hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2056178825Sdfr				       "Key usage missing from CA certificate");
2057178825Sdfr		goto out;
2058178825Sdfr	    }
2059178825Sdfr
2060233294Sstas	    /* self signed cert doesn't add to path length */
2061233294Sstas	    if (i + 1 != path.len) {
2062233294Sstas		int selfsigned;
2063178825Sdfr
2064233294Sstas		ret = certificate_is_self_signed(context, c, &selfsigned);
2065233294Sstas		if (ret)
2066233294Sstas		    goto out;
2067233294Sstas		if (selfsigned)
2068233294Sstas		    selfsigned_depth++;
2069233294Sstas	    }
2070233294Sstas
2071178825Sdfr	    break;
2072178825Sdfr	case PROXY_CERT: {
2073233294Sstas	    ProxyCertInfo info;
2074178825Sdfr
2075178825Sdfr	    if (is_proxy_cert(context, c, &info) == 0) {
2076233294Sstas		size_t j;
2077178825Sdfr
2078178825Sdfr		if (info.pCPathLenConstraint != NULL &&
2079178825Sdfr		    *info.pCPathLenConstraint < i)
2080178825Sdfr		{
2081178825Sdfr		    free_ProxyCertInfo(&info);
2082178825Sdfr		    ret = HX509_PATH_TOO_LONG;
2083178825Sdfr		    hx509_set_error_string(context, 0, ret,
2084178825Sdfr					   "Proxy certificate chain "
2085178825Sdfr					   "longer then allowed");
2086178825Sdfr		    goto out;
2087178825Sdfr		}
2088178825Sdfr		/* XXX MUST check info.proxyPolicy */
2089178825Sdfr		free_ProxyCertInfo(&info);
2090233294Sstas
2091178825Sdfr		j = 0;
2092233294Sstas		if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) {
2093178825Sdfr		    ret = HX509_PROXY_CERT_INVALID;
2094233294Sstas		    hx509_set_error_string(context, 0, ret,
2095178825Sdfr					   "Proxy certificate have explicity "
2096178825Sdfr					   "forbidden subjectAltName");
2097178825Sdfr		    goto out;
2098178825Sdfr		}
2099178825Sdfr
2100178825Sdfr		j = 0;
2101233294Sstas		if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) {
2102178825Sdfr		    ret = HX509_PROXY_CERT_INVALID;
2103233294Sstas		    hx509_set_error_string(context, 0, ret,
2104178825Sdfr					   "Proxy certificate have explicity "
2105178825Sdfr					   "forbidden issuerAltName");
2106178825Sdfr		    goto out;
2107178825Sdfr		}
2108233294Sstas
2109233294Sstas		/*
2110178825Sdfr		 * The subject name of the proxy certificate should be
2111178825Sdfr		 * CN=XXX,<proxy issuer>, prune of CN and check if its
2112178825Sdfr		 * the same over the whole chain of proxy certs and
2113178825Sdfr		 * then check with the EE cert when we get to it.
2114178825Sdfr		 */
2115178825Sdfr
2116178825Sdfr		if (proxy_cert_depth) {
2117233294Sstas		    ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff);
2118178825Sdfr		    if (ret) {
2119233294Sstas			hx509_set_error_string(context, 0, ret, "Out of memory");
2120233294Sstas			goto out;
2121233294Sstas		    }
2122233294Sstas		    if (diff) {
2123178825Sdfr			ret = HX509_PROXY_CERT_NAME_WRONG;
2124178825Sdfr			hx509_set_error_string(context, 0, ret,
2125178825Sdfr					       "Base proxy name not right");
2126178825Sdfr			goto out;
2127178825Sdfr		    }
2128178825Sdfr		}
2129178825Sdfr
2130178825Sdfr		free_Name(&proxy_issuer);
2131178825Sdfr
2132178825Sdfr		ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer);
2133178825Sdfr		if (ret) {
2134178825Sdfr		    hx509_clear_error_string(context);
2135178825Sdfr		    goto out;
2136178825Sdfr		}
2137178825Sdfr
2138178825Sdfr		j = proxy_issuer.u.rdnSequence.len;
2139233294Sstas		if (proxy_issuer.u.rdnSequence.len < 2
2140178825Sdfr		    || proxy_issuer.u.rdnSequence.val[j - 1].len > 1
2141178825Sdfr		    || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type,
2142233294Sstas					&asn1_oid_id_at_commonName))
2143178825Sdfr		{
2144178825Sdfr		    ret = HX509_PROXY_CERT_NAME_WRONG;
2145178825Sdfr		    hx509_set_error_string(context, 0, ret,
2146178825Sdfr					   "Proxy name too short or "
2147178825Sdfr					   "does not have Common name "
2148178825Sdfr					   "at the top");
2149178825Sdfr		    goto out;
2150178825Sdfr		}
2151178825Sdfr
2152178825Sdfr		free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]);
2153178825Sdfr		proxy_issuer.u.rdnSequence.len -= 1;
2154178825Sdfr
2155233294Sstas		ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff);
2156233294Sstas		if (ret) {
2157233294Sstas		    hx509_set_error_string(context, 0, ret, "Out of memory");
2158233294Sstas		    goto out;
2159233294Sstas		}
2160233294Sstas		if (diff != 0) {
2161178825Sdfr		    ret = HX509_PROXY_CERT_NAME_WRONG;
2162178825Sdfr		    hx509_set_error_string(context, 0, ret,
2163178825Sdfr					   "Proxy issuer name not as expected");
2164178825Sdfr		    goto out;
2165178825Sdfr		}
2166178825Sdfr
2167178825Sdfr		break;
2168178825Sdfr	    } else {
2169233294Sstas		/*
2170178825Sdfr		 * Now we are done with the proxy certificates, this
2171178825Sdfr		 * cert was an EE cert and we we will fall though to
2172178825Sdfr		 * EE checking below.
2173178825Sdfr		 */
2174178825Sdfr		type = EE_CERT;
2175178825Sdfr		/* FALLTHOUGH */
2176178825Sdfr	    }
2177178825Sdfr	}
2178178825Sdfr	case EE_CERT:
2179178825Sdfr	    /*
2180178825Sdfr	     * If there where any proxy certificates in the chain
2181178825Sdfr	     * (proxy_cert_depth > 0), check that the proxy issuer
2182178825Sdfr	     * matched proxy certificates "base" subject.
2183178825Sdfr	     */
2184178825Sdfr	    if (proxy_cert_depth) {
2185178825Sdfr
2186178825Sdfr		ret = _hx509_name_cmp(&proxy_issuer,
2187233294Sstas				      &c->tbsCertificate.subject, &diff);
2188178825Sdfr		if (ret) {
2189233294Sstas		    hx509_set_error_string(context, 0, ret, "out of memory");
2190233294Sstas		    goto out;
2191233294Sstas		}
2192233294Sstas		if (diff) {
2193178825Sdfr		    ret = HX509_PROXY_CERT_NAME_WRONG;
2194178825Sdfr		    hx509_clear_error_string(context);
2195178825Sdfr		    goto out;
2196178825Sdfr		}
2197178825Sdfr		if (cert->basename)
2198178825Sdfr		    hx509_name_free(&cert->basename);
2199233294Sstas
2200178825Sdfr		ret = _hx509_name_from_Name(&proxy_issuer, &cert->basename);
2201178825Sdfr		if (ret) {
2202178825Sdfr		    hx509_clear_error_string(context);
2203178825Sdfr		    goto out;
2204178825Sdfr		}
2205178825Sdfr	    }
2206178825Sdfr
2207178825Sdfr	    break;
2208178825Sdfr	}
2209178825Sdfr
2210233294Sstas	ret = check_basic_constraints(context, c, type,
2211178825Sdfr				      i - proxy_cert_depth - selfsigned_depth);
2212178825Sdfr	if (ret)
2213178825Sdfr	    goto out;
2214233294Sstas
2215178825Sdfr	/*
2216178825Sdfr	 * Don't check the trust anchors expiration time since they
2217178825Sdfr	 * are transported out of band, from RFC3820.
2218178825Sdfr	 */
2219178825Sdfr	if (i + 1 != path.len || CHECK_TA(ctx)) {
2220178825Sdfr
2221178825Sdfr	    t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2222178825Sdfr	    if (t > ctx->time_now) {
2223178825Sdfr		ret = HX509_CERT_USED_BEFORE_TIME;
2224178825Sdfr		hx509_clear_error_string(context);
2225178825Sdfr		goto out;
2226178825Sdfr	    }
2227178825Sdfr	    t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
2228178825Sdfr	    if (t < ctx->time_now) {
2229178825Sdfr		ret = HX509_CERT_USED_AFTER_TIME;
2230178825Sdfr		hx509_clear_error_string(context);
2231178825Sdfr		goto out;
2232178825Sdfr	    }
2233178825Sdfr	}
2234178825Sdfr
2235178825Sdfr	if (type == EE_CERT)
2236178825Sdfr	    type = CA_CERT;
2237178825Sdfr	else if (type == PROXY_CERT)
2238178825Sdfr	    proxy_cert_depth++;
2239178825Sdfr    }
2240178825Sdfr
2241178825Sdfr    /*
2242178825Sdfr     * Verify constraints, do this backward so path constraints are
2243178825Sdfr     * checked in the right order.
2244178825Sdfr     */
2245178825Sdfr
2246233294Sstas    for (ret = 0, k = path.len; k > 0; k--) {
2247178825Sdfr	Certificate *c;
2248233294Sstas	int selfsigned;
2249233294Sstas	i = k - 1;
2250178825Sdfr
2251178825Sdfr	c = _hx509_get_cert(path.val[i]);
2252178825Sdfr
2253233294Sstas	ret = certificate_is_self_signed(context, c, &selfsigned);
2254233294Sstas	if (ret)
2255233294Sstas	    goto out;
2256233294Sstas
2257178825Sdfr	/* verify name constraints, not for selfsigned and anchor */
2258233294Sstas	if (!selfsigned || i + 1 != path.len) {
2259178825Sdfr	    ret = check_name_constraints(context, &nc, c);
2260178825Sdfr	    if (ret) {
2261178825Sdfr		goto out;
2262178825Sdfr	    }
2263178825Sdfr	}
2264178825Sdfr	ret = add_name_constraints(context, c, i == 0, &nc);
2265178825Sdfr	if (ret)
2266178825Sdfr	    goto out;
2267178825Sdfr
2268178825Sdfr	/* XXX verify all other silly constraints */
2269178825Sdfr
2270178825Sdfr    }
2271178825Sdfr
2272178825Sdfr    /*
2273178825Sdfr     * Verify that no certificates has been revoked.
2274178825Sdfr     */
2275178825Sdfr
2276178825Sdfr    if (ctx->revoke_ctx) {
2277178825Sdfr	hx509_certs certs;
2278178825Sdfr
2279178825Sdfr	ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0,
2280178825Sdfr			       NULL, &certs);
2281178825Sdfr	if (ret)
2282178825Sdfr	    goto out;
2283178825Sdfr
2284178825Sdfr	for (i = 0; i < path.len; i++) {
2285178825Sdfr	    ret = hx509_certs_add(context, certs, path.val[i]);
2286178825Sdfr	    if (ret) {
2287178825Sdfr		hx509_certs_free(&certs);
2288178825Sdfr		goto out;
2289178825Sdfr	    }
2290178825Sdfr	}
2291178825Sdfr	ret = hx509_certs_merge(context, certs, pool);
2292178825Sdfr	if (ret) {
2293178825Sdfr	    hx509_certs_free(&certs);
2294178825Sdfr	    goto out;
2295178825Sdfr	}
2296178825Sdfr
2297178825Sdfr	for (i = 0; i < path.len - 1; i++) {
2298233294Sstas	    size_t parent = (i < path.len - 1) ? i + 1 : i;
2299178825Sdfr
2300178825Sdfr	    ret = hx509_revoke_verify(context,
2301233294Sstas				      ctx->revoke_ctx,
2302178825Sdfr				      certs,
2303178825Sdfr				      ctx->time_now,
2304178825Sdfr				      path.val[i],
2305178825Sdfr				      path.val[parent]);
2306178825Sdfr	    if (ret) {
2307178825Sdfr		hx509_certs_free(&certs);
2308178825Sdfr		goto out;
2309178825Sdfr	    }
2310178825Sdfr	}
2311178825Sdfr	hx509_certs_free(&certs);
2312178825Sdfr    }
2313178825Sdfr
2314178825Sdfr    /*
2315178825Sdfr     * Verify signatures, do this backward so public key working
2316178825Sdfr     * parameter is passed up from the anchor up though the chain.
2317178825Sdfr     */
2318178825Sdfr
2319233294Sstas    for (k = path.len; k > 0; k--) {
2320233294Sstas	hx509_cert signer;
2321233294Sstas	Certificate *c;
2322233294Sstas	i = k - 1;
2323178825Sdfr
2324178825Sdfr	c = _hx509_get_cert(path.val[i]);
2325178825Sdfr
2326178825Sdfr	/* is last in chain (trust anchor) */
2327178825Sdfr	if (i + 1 == path.len) {
2328233294Sstas	    int selfsigned;
2329178825Sdfr
2330233294Sstas	    signer = path.val[i];
2331233294Sstas
2332233294Sstas	    ret = certificate_is_self_signed(context, signer->data, &selfsigned);
2333233294Sstas	    if (ret)
2334233294Sstas		goto out;
2335233294Sstas
2336178825Sdfr	    /* if trust anchor is not self signed, don't check sig */
2337233294Sstas	    if (!selfsigned)
2338178825Sdfr		continue;
2339178825Sdfr	} else {
2340178825Sdfr	    /* take next certificate in chain */
2341233294Sstas	    signer = path.val[i + 1];
2342178825Sdfr	}
2343178825Sdfr
2344178825Sdfr	/* verify signatureValue */
2345178825Sdfr	ret = _hx509_verify_signature_bitstring(context,
2346178825Sdfr						signer,
2347178825Sdfr						&c->signatureAlgorithm,
2348178825Sdfr						&c->tbsCertificate._save,
2349178825Sdfr						&c->signatureValue);
2350178825Sdfr	if (ret) {
2351178825Sdfr	    hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
2352178825Sdfr				   "Failed to verify signature of certificate");
2353178825Sdfr	    goto out;
2354178825Sdfr	}
2355233294Sstas	/*
2356233294Sstas	 * Verify that the sigature algorithm "best-before" date is
2357233294Sstas	 * before the creation date of the certificate, do this for
2358233294Sstas	 * trust anchors too, since any trust anchor that is created
2359233294Sstas	 * after a algorithm is known to be bad deserved to be invalid.
2360233294Sstas	 *
2361233294Sstas	 * Skip the leaf certificate for now...
2362233294Sstas	 */
2363233294Sstas
2364233294Sstas	if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) {
2365233294Sstas	    time_t notBefore =
2366233294Sstas		_hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
2367233294Sstas	    ret = _hx509_signature_best_before(context,
2368233294Sstas					       &c->signatureAlgorithm,
2369233294Sstas					       notBefore);
2370233294Sstas	    if (ret)
2371233294Sstas		goto out;
2372233294Sstas	}
2373178825Sdfr    }
2374178825Sdfr
2375178825Sdfrout:
2376178825Sdfr    hx509_certs_free(&anchors);
2377178825Sdfr    free_Name(&proxy_issuer);
2378178825Sdfr    free_name_constraints(&nc);
2379178825Sdfr    _hx509_path_free(&path);
2380178825Sdfr
2381178825Sdfr    return ret;
2382178825Sdfr}
2383178825Sdfr
2384178825Sdfr/**
2385178825Sdfr * Verify a signature made using the private key of an certificate.
2386178825Sdfr *
2387178825Sdfr * @param context A hx509 context.
2388178825Sdfr * @param signer the certificate that made the signature.
2389178825Sdfr * @param alg algorthm that was used to sign the data.
2390178825Sdfr * @param data the data that was signed.
2391178825Sdfr * @param sig the sigature to verify.
2392178825Sdfr *
2393178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2394178825Sdfr *
2395178825Sdfr * @ingroup hx509_crypto
2396178825Sdfr */
2397178825Sdfr
2398178825Sdfrint
2399178825Sdfrhx509_verify_signature(hx509_context context,
2400178825Sdfr		       const hx509_cert signer,
2401178825Sdfr		       const AlgorithmIdentifier *alg,
2402178825Sdfr		       const heim_octet_string *data,
2403178825Sdfr		       const heim_octet_string *sig)
2404178825Sdfr{
2405233294Sstas    return _hx509_verify_signature(context, signer, alg, data, sig);
2406178825Sdfr}
2407178825Sdfr
2408233294Sstasint
2409233294Sstas_hx509_verify_signature_bitstring(hx509_context context,
2410233294Sstas				  const hx509_cert signer,
2411233294Sstas				  const AlgorithmIdentifier *alg,
2412233294Sstas				  const heim_octet_string *data,
2413233294Sstas				  const heim_bit_string *sig)
2414233294Sstas{
2415233294Sstas    heim_octet_string os;
2416178825Sdfr
2417233294Sstas    if (sig->length & 7) {
2418233294Sstas	hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT,
2419233294Sstas			       "signature not multiple of 8 bits");
2420233294Sstas	return HX509_CRYPTO_SIG_INVALID_FORMAT;
2421233294Sstas    }
2422233294Sstas
2423233294Sstas    os.data = sig->data;
2424233294Sstas    os.length = sig->length / 8;
2425233294Sstas
2426233294Sstas    return _hx509_verify_signature(context, signer, alg, data, &os);
2427233294Sstas}
2428233294Sstas
2429233294Sstas
2430233294Sstas
2431178825Sdfr/**
2432178825Sdfr * Verify that the certificate is allowed to be used for the hostname
2433178825Sdfr * and address.
2434178825Sdfr *
2435178825Sdfr * @param context A hx509 context.
2436178825Sdfr * @param cert the certificate to match with
2437178825Sdfr * @param flags Flags to modify the behavior:
2438178825Sdfr * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok
2439178825Sdfr * @param type type of hostname:
2440178825Sdfr * - HX509_HN_HOSTNAME for plain hostname.
2441178825Sdfr * - HX509_HN_DNSSRV for DNS SRV names.
2442178825Sdfr * @param hostname the hostname to check
2443178825Sdfr * @param sa address of the host
2444178825Sdfr * @param sa_size length of address
2445178825Sdfr *
2446178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2447178825Sdfr *
2448178825Sdfr * @ingroup hx509_cert
2449178825Sdfr */
2450178825Sdfr
2451178825Sdfrint
2452178825Sdfrhx509_verify_hostname(hx509_context context,
2453178825Sdfr		      const hx509_cert cert,
2454178825Sdfr		      int flags,
2455178825Sdfr		      hx509_hostname_type type,
2456178825Sdfr		      const char *hostname,
2457178825Sdfr		      const struct sockaddr *sa,
2458233294Sstas		      /* XXX krb5_socklen_t */ int sa_size)
2459178825Sdfr{
2460178825Sdfr    GeneralNames san;
2461233294Sstas    const Name *name;
2462233294Sstas    int ret;
2463233294Sstas    size_t i, j, k;
2464178825Sdfr
2465178825Sdfr    if (sa && sa_size <= 0)
2466178825Sdfr	return EINVAL;
2467178825Sdfr
2468178825Sdfr    memset(&san, 0, sizeof(san));
2469178825Sdfr
2470178825Sdfr    i = 0;
2471178825Sdfr    do {
2472178825Sdfr	ret = find_extension_subject_alt_name(cert->data, &i, &san);
2473233294Sstas	if (ret == HX509_EXTENSION_NOT_FOUND)
2474178825Sdfr	    break;
2475233294Sstas	else if (ret != 0)
2476233294Sstas	    return HX509_PARSING_NAME_FAILED;
2477178825Sdfr
2478178825Sdfr	for (j = 0; j < san.len; j++) {
2479178825Sdfr	    switch (san.val[j].element) {
2480233294Sstas	    case choice_GeneralName_dNSName: {
2481233294Sstas		heim_printable_string hn;
2482233294Sstas		hn.data = rk_UNCONST(hostname);
2483233294Sstas		hn.length = strlen(hostname);
2484233294Sstas
2485233294Sstas		if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) {
2486178825Sdfr		    free_GeneralNames(&san);
2487178825Sdfr		    return 0;
2488178825Sdfr		}
2489178825Sdfr		break;
2490233294Sstas	    }
2491178825Sdfr	    default:
2492178825Sdfr		break;
2493178825Sdfr	    }
2494178825Sdfr	}
2495178825Sdfr	free_GeneralNames(&san);
2496178825Sdfr    } while (1);
2497178825Sdfr
2498233294Sstas    name = &cert->data->tbsCertificate.subject;
2499178825Sdfr
2500233294Sstas    /* Find first CN= in the name, and try to match the hostname on that */
2501233294Sstas    for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) {
2502233294Sstas	i = k - 1;
2503233294Sstas	for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) {
2504233294Sstas	    AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j];
2505178825Sdfr
2506233294Sstas	    if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) {
2507233294Sstas		DirectoryString *ds = &n->value;
2508233294Sstas		switch (ds->element) {
2509233294Sstas		case choice_DirectoryString_printableString: {
2510233294Sstas		    heim_printable_string hn;
2511233294Sstas		    hn.data = rk_UNCONST(hostname);
2512233294Sstas		    hn.length = strlen(hostname);
2513233294Sstas
2514233294Sstas		    if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0)
2515233294Sstas			return 0;
2516233294Sstas		    break;
2517233294Sstas		}
2518233294Sstas		case choice_DirectoryString_ia5String: {
2519233294Sstas		    heim_ia5_string hn;
2520233294Sstas		    hn.data = rk_UNCONST(hostname);
2521233294Sstas		    hn.length = strlen(hostname);
2522233294Sstas
2523233294Sstas		    if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0)
2524233294Sstas			return 0;
2525233294Sstas		    break;
2526233294Sstas		}
2527233294Sstas		case choice_DirectoryString_utf8String:
2528233294Sstas		    if (strcasecmp(ds->u.utf8String, hostname) == 0)
2529233294Sstas			return 0;
2530233294Sstas		default:
2531233294Sstas		    break;
2532233294Sstas		}
2533233294Sstas		ret = HX509_NAME_CONSTRAINT_ERROR;
2534178825Sdfr	    }
2535178825Sdfr	}
2536178825Sdfr    }
2537178825Sdfr
2538178825Sdfr    if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0)
2539178825Sdfr	ret = HX509_NAME_CONSTRAINT_ERROR;
2540178825Sdfr
2541178825Sdfr    return ret;
2542178825Sdfr}
2543178825Sdfr
2544178825Sdfrint
2545178825Sdfr_hx509_set_cert_attribute(hx509_context context,
2546233294Sstas			  hx509_cert cert,
2547233294Sstas			  const heim_oid *oid,
2548178825Sdfr			  const heim_octet_string *attr)
2549178825Sdfr{
2550178825Sdfr    hx509_cert_attribute a;
2551178825Sdfr    void *d;
2552178825Sdfr
2553178825Sdfr    if (hx509_cert_get_attribute(cert, oid) != NULL)
2554178825Sdfr	return 0;
2555178825Sdfr
2556233294Sstas    d = realloc(cert->attrs.val,
2557178825Sdfr		sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1));
2558178825Sdfr    if (d == NULL) {
2559178825Sdfr	hx509_clear_error_string(context);
2560178825Sdfr	return ENOMEM;
2561178825Sdfr    }
2562178825Sdfr    cert->attrs.val = d;
2563178825Sdfr
2564178825Sdfr    a = malloc(sizeof(*a));
2565178825Sdfr    if (a == NULL)
2566178825Sdfr	return ENOMEM;
2567178825Sdfr
2568178825Sdfr    der_copy_octet_string(attr, &a->data);
2569178825Sdfr    der_copy_oid(oid, &a->oid);
2570233294Sstas
2571178825Sdfr    cert->attrs.val[cert->attrs.len] = a;
2572178825Sdfr    cert->attrs.len++;
2573178825Sdfr
2574178825Sdfr    return 0;
2575178825Sdfr}
2576178825Sdfr
2577178825Sdfr/**
2578178825Sdfr * Get an external attribute for the certificate, examples are
2579178825Sdfr * friendly name and id.
2580178825Sdfr *
2581178825Sdfr * @param cert hx509 certificate object to search
2582178825Sdfr * @param oid an oid to search for.
2583178825Sdfr *
2584178825Sdfr * @return an hx509_cert_attribute, only valid as long as the
2585178825Sdfr * certificate is referenced.
2586178825Sdfr *
2587178825Sdfr * @ingroup hx509_cert
2588178825Sdfr */
2589178825Sdfr
2590178825Sdfrhx509_cert_attribute
2591178825Sdfrhx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid)
2592178825Sdfr{
2593233294Sstas    size_t i;
2594178825Sdfr    for (i = 0; i < cert->attrs.len; i++)
2595178825Sdfr	if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0)
2596178825Sdfr	    return cert->attrs.val[i];
2597178825Sdfr    return NULL;
2598178825Sdfr}
2599178825Sdfr
2600178825Sdfr/**
2601178825Sdfr * Set the friendly name on the certificate.
2602178825Sdfr *
2603178825Sdfr * @param cert The certificate to set the friendly name on
2604178825Sdfr * @param name Friendly name.
2605178825Sdfr *
2606178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2607178825Sdfr *
2608178825Sdfr * @ingroup hx509_cert
2609178825Sdfr */
2610178825Sdfr
2611178825Sdfrint
2612178825Sdfrhx509_cert_set_friendly_name(hx509_cert cert, const char *name)
2613178825Sdfr{
2614178825Sdfr    if (cert->friendlyname)
2615178825Sdfr	free(cert->friendlyname);
2616178825Sdfr    cert->friendlyname = strdup(name);
2617178825Sdfr    if (cert->friendlyname == NULL)
2618178825Sdfr	return ENOMEM;
2619178825Sdfr    return 0;
2620178825Sdfr}
2621178825Sdfr
2622178825Sdfr/**
2623178825Sdfr * Get friendly name of the certificate.
2624178825Sdfr *
2625178825Sdfr * @param cert cert to get the friendly name from.
2626178825Sdfr *
2627178825Sdfr * @return an friendly name or NULL if there is. The friendly name is
2628178825Sdfr * only valid as long as the certificate is referenced.
2629178825Sdfr *
2630178825Sdfr * @ingroup hx509_cert
2631178825Sdfr */
2632178825Sdfr
2633178825Sdfrconst char *
2634178825Sdfrhx509_cert_get_friendly_name(hx509_cert cert)
2635178825Sdfr{
2636178825Sdfr    hx509_cert_attribute a;
2637178825Sdfr    PKCS9_friendlyName n;
2638178825Sdfr    size_t sz;
2639233294Sstas    int ret;
2640233294Sstas    size_t i;
2641178825Sdfr
2642178825Sdfr    if (cert->friendlyname)
2643178825Sdfr	return cert->friendlyname;
2644178825Sdfr
2645233294Sstas    a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName);
2646178825Sdfr    if (a == NULL) {
2647233294Sstas	hx509_name name;
2648233294Sstas
2649233294Sstas	ret = hx509_cert_get_subject(cert, &name);
2650233294Sstas	if (ret)
2651233294Sstas	    return NULL;
2652233294Sstas	ret = hx509_name_to_string(name, &cert->friendlyname);
2653233294Sstas	hx509_name_free(&name);
2654233294Sstas	if (ret)
2655233294Sstas	    return NULL;
2656233294Sstas	return cert->friendlyname;
2657178825Sdfr    }
2658178825Sdfr
2659178825Sdfr    ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz);
2660178825Sdfr    if (ret)
2661178825Sdfr	return NULL;
2662233294Sstas
2663178825Sdfr    if (n.len != 1) {
2664178825Sdfr	free_PKCS9_friendlyName(&n);
2665178825Sdfr	return NULL;
2666178825Sdfr    }
2667233294Sstas
2668178825Sdfr    cert->friendlyname = malloc(n.val[0].length + 1);
2669178825Sdfr    if (cert->friendlyname == NULL) {
2670178825Sdfr	free_PKCS9_friendlyName(&n);
2671178825Sdfr	return NULL;
2672178825Sdfr    }
2673233294Sstas
2674178825Sdfr    for (i = 0; i < n.val[0].length; i++) {
2675178825Sdfr	if (n.val[0].data[i] <= 0xff)
2676178825Sdfr	    cert->friendlyname[i] = n.val[0].data[i] & 0xff;
2677178825Sdfr	else
2678178825Sdfr	    cert->friendlyname[i] = 'X';
2679178825Sdfr    }
2680178825Sdfr    cert->friendlyname[i] = '\0';
2681178825Sdfr    free_PKCS9_friendlyName(&n);
2682178825Sdfr
2683178825Sdfr    return cert->friendlyname;
2684178825Sdfr}
2685178825Sdfr
2686178825Sdfrvoid
2687178825Sdfr_hx509_query_clear(hx509_query *q)
2688178825Sdfr{
2689178825Sdfr    memset(q, 0, sizeof(*q));
2690178825Sdfr}
2691178825Sdfr
2692178825Sdfr/**
2693178825Sdfr * Allocate an query controller. Free using hx509_query_free().
2694178825Sdfr *
2695178825Sdfr * @param context A hx509 context.
2696178825Sdfr * @param q return pointer to a hx509_query.
2697178825Sdfr *
2698178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2699178825Sdfr *
2700178825Sdfr * @ingroup hx509_cert
2701178825Sdfr */
2702178825Sdfr
2703178825Sdfrint
2704178825Sdfrhx509_query_alloc(hx509_context context, hx509_query **q)
2705178825Sdfr{
2706178825Sdfr    *q = calloc(1, sizeof(**q));
2707178825Sdfr    if (*q == NULL)
2708178825Sdfr	return ENOMEM;
2709178825Sdfr    return 0;
2710178825Sdfr}
2711178825Sdfr
2712233294Sstas
2713178825Sdfr/**
2714178825Sdfr * Set match options for the hx509 query controller.
2715178825Sdfr *
2716178825Sdfr * @param q query controller.
2717178825Sdfr * @param option options to control the query controller.
2718178825Sdfr *
2719178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2720178825Sdfr *
2721178825Sdfr * @ingroup hx509_cert
2722178825Sdfr */
2723178825Sdfr
2724178825Sdfrvoid
2725178825Sdfrhx509_query_match_option(hx509_query *q, hx509_query_option option)
2726178825Sdfr{
2727178825Sdfr    switch(option) {
2728178825Sdfr    case HX509_QUERY_OPTION_PRIVATE_KEY:
2729178825Sdfr	q->match |= HX509_QUERY_PRIVATE_KEY;
2730178825Sdfr	break;
2731178825Sdfr    case HX509_QUERY_OPTION_KU_ENCIPHERMENT:
2732178825Sdfr	q->match |= HX509_QUERY_KU_ENCIPHERMENT;
2733178825Sdfr	break;
2734178825Sdfr    case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE:
2735178825Sdfr	q->match |= HX509_QUERY_KU_DIGITALSIGNATURE;
2736178825Sdfr	break;
2737178825Sdfr    case HX509_QUERY_OPTION_KU_KEYCERTSIGN:
2738178825Sdfr	q->match |= HX509_QUERY_KU_KEYCERTSIGN;
2739178825Sdfr	break;
2740178825Sdfr    case HX509_QUERY_OPTION_END:
2741178825Sdfr    default:
2742178825Sdfr	break;
2743178825Sdfr    }
2744178825Sdfr}
2745178825Sdfr
2746178825Sdfr/**
2747178825Sdfr * Set the issuer and serial number of match in the query
2748178825Sdfr * controller. The function make copies of the isser and serial number.
2749178825Sdfr *
2750178825Sdfr * @param q a hx509 query controller
2751178825Sdfr * @param issuer issuer to search for
2752178825Sdfr * @param serialNumber the serialNumber of the issuer.
2753178825Sdfr *
2754178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2755178825Sdfr *
2756178825Sdfr * @ingroup hx509_cert
2757178825Sdfr */
2758178825Sdfr
2759178825Sdfrint
2760178825Sdfrhx509_query_match_issuer_serial(hx509_query *q,
2761233294Sstas				const Name *issuer,
2762178825Sdfr				const heim_integer *serialNumber)
2763178825Sdfr{
2764178825Sdfr    int ret;
2765178825Sdfr    if (q->serial) {
2766178825Sdfr	der_free_heim_integer(q->serial);
2767178825Sdfr	free(q->serial);
2768178825Sdfr    }
2769178825Sdfr    q->serial = malloc(sizeof(*q->serial));
2770178825Sdfr    if (q->serial == NULL)
2771178825Sdfr	return ENOMEM;
2772178825Sdfr    ret = der_copy_heim_integer(serialNumber, q->serial);
2773178825Sdfr    if (ret) {
2774178825Sdfr	free(q->serial);
2775178825Sdfr	q->serial = NULL;
2776178825Sdfr	return ret;
2777178825Sdfr    }
2778178825Sdfr    if (q->issuer_name) {
2779178825Sdfr	free_Name(q->issuer_name);
2780178825Sdfr	free(q->issuer_name);
2781178825Sdfr    }
2782178825Sdfr    q->issuer_name = malloc(sizeof(*q->issuer_name));
2783178825Sdfr    if (q->issuer_name == NULL)
2784178825Sdfr	return ENOMEM;
2785178825Sdfr    ret = copy_Name(issuer, q->issuer_name);
2786178825Sdfr    if (ret) {
2787178825Sdfr	free(q->issuer_name);
2788178825Sdfr	q->issuer_name = NULL;
2789178825Sdfr	return ret;
2790178825Sdfr    }
2791178825Sdfr    q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
2792178825Sdfr    return 0;
2793178825Sdfr}
2794178825Sdfr
2795178825Sdfr/**
2796178825Sdfr * Set the query controller to match on a friendly name
2797178825Sdfr *
2798178825Sdfr * @param q a hx509 query controller.
2799178825Sdfr * @param name a friendly name to match on
2800178825Sdfr *
2801178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2802178825Sdfr *
2803178825Sdfr * @ingroup hx509_cert
2804178825Sdfr */
2805178825Sdfr
2806178825Sdfrint
2807178825Sdfrhx509_query_match_friendly_name(hx509_query *q, const char *name)
2808178825Sdfr{
2809178825Sdfr    if (q->friendlyname)
2810178825Sdfr	free(q->friendlyname);
2811178825Sdfr    q->friendlyname = strdup(name);
2812178825Sdfr    if (q->friendlyname == NULL)
2813178825Sdfr	return ENOMEM;
2814178825Sdfr    q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME;
2815178825Sdfr    return 0;
2816178825Sdfr}
2817178825Sdfr
2818178825Sdfr/**
2819233294Sstas * Set the query controller to require an one specific EKU (extended
2820233294Sstas * key usage). Any previous EKU matching is overwitten. If NULL is
2821233294Sstas * passed in as the eku, the EKU requirement is reset.
2822233294Sstas *
2823233294Sstas * @param q a hx509 query controller.
2824233294Sstas * @param eku an EKU to match on.
2825233294Sstas *
2826233294Sstas * @return An hx509 error code, see hx509_get_error_string().
2827233294Sstas *
2828233294Sstas * @ingroup hx509_cert
2829233294Sstas */
2830233294Sstas
2831233294Sstasint
2832233294Sstashx509_query_match_eku(hx509_query *q, const heim_oid *eku)
2833233294Sstas{
2834233294Sstas    int ret;
2835233294Sstas
2836233294Sstas    if (eku == NULL) {
2837233294Sstas	if (q->eku) {
2838233294Sstas	    der_free_oid(q->eku);
2839233294Sstas	    free(q->eku);
2840233294Sstas	    q->eku = NULL;
2841233294Sstas	}
2842233294Sstas	q->match &= ~HX509_QUERY_MATCH_EKU;
2843233294Sstas    } else {
2844233294Sstas	if (q->eku) {
2845233294Sstas	    der_free_oid(q->eku);
2846233294Sstas	} else {
2847233294Sstas	    q->eku = calloc(1, sizeof(*q->eku));
2848233294Sstas	    if (q->eku == NULL)
2849233294Sstas		return ENOMEM;
2850233294Sstas	}
2851233294Sstas	ret = der_copy_oid(eku, q->eku);
2852233294Sstas	if (ret) {
2853233294Sstas	    free(q->eku);
2854233294Sstas	    q->eku = NULL;
2855233294Sstas	    return ret;
2856233294Sstas	}
2857233294Sstas	q->match |= HX509_QUERY_MATCH_EKU;
2858233294Sstas    }
2859233294Sstas    return 0;
2860233294Sstas}
2861233294Sstas
2862233294Sstasint
2863233294Sstashx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr)
2864233294Sstas{
2865233294Sstas    if (q->expr) {
2866233294Sstas	_hx509_expr_free(q->expr);
2867233294Sstas	q->expr = NULL;
2868233294Sstas    }
2869233294Sstas
2870233294Sstas    if (expr == NULL) {
2871233294Sstas	q->match &= ~HX509_QUERY_MATCH_EXPR;
2872233294Sstas    } else {
2873233294Sstas	q->expr = _hx509_expr_parse(expr);
2874233294Sstas	if (q->expr)
2875233294Sstas	    q->match |= HX509_QUERY_MATCH_EXPR;
2876233294Sstas    }
2877233294Sstas
2878233294Sstas    return 0;
2879233294Sstas}
2880233294Sstas
2881233294Sstas/**
2882178825Sdfr * Set the query controller to match using a specific match function.
2883178825Sdfr *
2884178825Sdfr * @param q a hx509 query controller.
2885178825Sdfr * @param func function to use for matching, if the argument is NULL,
2886178825Sdfr * the match function is removed.
2887178825Sdfr * @param ctx context passed to the function.
2888178825Sdfr *
2889178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
2890178825Sdfr *
2891178825Sdfr * @ingroup hx509_cert
2892178825Sdfr */
2893178825Sdfr
2894178825Sdfrint
2895178825Sdfrhx509_query_match_cmp_func(hx509_query *q,
2896233294Sstas			   int (*func)(hx509_context, hx509_cert, void *),
2897178825Sdfr			   void *ctx)
2898178825Sdfr{
2899178825Sdfr    if (func)
2900178825Sdfr	q->match |= HX509_QUERY_MATCH_FUNCTION;
2901178825Sdfr    else
2902178825Sdfr	q->match &= ~HX509_QUERY_MATCH_FUNCTION;
2903178825Sdfr    q->cmp_func = func;
2904178825Sdfr    q->cmp_func_ctx = ctx;
2905178825Sdfr    return 0;
2906178825Sdfr}
2907178825Sdfr
2908178825Sdfr/**
2909178825Sdfr * Free the query controller.
2910178825Sdfr *
2911178825Sdfr * @param context A hx509 context.
2912178825Sdfr * @param q a pointer to the query controller.
2913178825Sdfr *
2914178825Sdfr * @ingroup hx509_cert
2915178825Sdfr */
2916178825Sdfr
2917178825Sdfrvoid
2918178825Sdfrhx509_query_free(hx509_context context, hx509_query *q)
2919178825Sdfr{
2920233294Sstas    if (q == NULL)
2921233294Sstas	return;
2922233294Sstas
2923178825Sdfr    if (q->serial) {
2924178825Sdfr	der_free_heim_integer(q->serial);
2925178825Sdfr	free(q->serial);
2926178825Sdfr    }
2927178825Sdfr    if (q->issuer_name) {
2928178825Sdfr	free_Name(q->issuer_name);
2929178825Sdfr	free(q->issuer_name);
2930178825Sdfr    }
2931233294Sstas    if (q->eku) {
2932233294Sstas	der_free_oid(q->eku);
2933233294Sstas	free(q->eku);
2934233294Sstas    }
2935233294Sstas    if (q->friendlyname)
2936178825Sdfr	free(q->friendlyname);
2937233294Sstas    if (q->expr)
2938233294Sstas	_hx509_expr_free(q->expr);
2939233294Sstas
2940233294Sstas    memset(q, 0, sizeof(*q));
2941178825Sdfr    free(q);
2942178825Sdfr}
2943178825Sdfr
2944178825Sdfrint
2945178825Sdfr_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert)
2946178825Sdfr{
2947178825Sdfr    Certificate *c = _hx509_get_cert(cert);
2948233294Sstas    int ret, diff;
2949178825Sdfr
2950178825Sdfr    _hx509_query_statistic(context, 1, q);
2951178825Sdfr
2952178825Sdfr    if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) &&
2953178825Sdfr	_hx509_cert_is_parent_cmp(q->subject, c, 0) != 0)
2954178825Sdfr	return 0;
2955178825Sdfr
2956178825Sdfr    if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) &&
2957178825Sdfr	_hx509_Certificate_cmp(q->certificate, c) != 0)
2958178825Sdfr	return 0;
2959178825Sdfr
2960178825Sdfr    if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER)
2961178825Sdfr	&& der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0)
2962178825Sdfr	return 0;
2963178825Sdfr
2964233294Sstas    if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) {
2965233294Sstas	ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff);
2966233294Sstas	if (ret || diff)
2967233294Sstas	    return 0;
2968233294Sstas    }
2969178825Sdfr
2970233294Sstas    if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) {
2971233294Sstas	ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff);
2972233294Sstas	if (ret || diff)
2973233294Sstas	    return 0;
2974233294Sstas    }
2975178825Sdfr
2976178825Sdfr    if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) {
2977178825Sdfr	SubjectKeyIdentifier si;
2978178825Sdfr
2979178825Sdfr	ret = _hx509_find_extension_subject_key_id(c, &si);
2980178825Sdfr	if (ret == 0) {
2981178825Sdfr	    if (der_heim_octet_string_cmp(&si, q->subject_id) != 0)
2982178825Sdfr		ret = 1;
2983178825Sdfr	    free_SubjectKeyIdentifier(&si);
2984178825Sdfr	}
2985178825Sdfr	if (ret)
2986178825Sdfr	    return 0;
2987178825Sdfr    }
2988178825Sdfr    if ((q->match & HX509_QUERY_MATCH_ISSUER_ID))
2989178825Sdfr	return 0;
2990233294Sstas    if ((q->match & HX509_QUERY_PRIVATE_KEY) &&
2991178825Sdfr	_hx509_cert_private_key(cert) == NULL)
2992178825Sdfr	return 0;
2993178825Sdfr
2994178825Sdfr    {
2995178825Sdfr	unsigned ku = 0;
2996178825Sdfr	if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE)
2997178825Sdfr	    ku |= (1 << 0);
2998178825Sdfr	if (q->match & HX509_QUERY_KU_NONREPUDIATION)
2999178825Sdfr	    ku |= (1 << 1);
3000178825Sdfr	if (q->match & HX509_QUERY_KU_ENCIPHERMENT)
3001178825Sdfr	    ku |= (1 << 2);
3002178825Sdfr	if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT)
3003178825Sdfr	    ku |= (1 << 3);
3004178825Sdfr	if (q->match & HX509_QUERY_KU_KEYAGREEMENT)
3005178825Sdfr	    ku |= (1 << 4);
3006178825Sdfr	if (q->match & HX509_QUERY_KU_KEYCERTSIGN)
3007178825Sdfr	    ku |= (1 << 5);
3008178825Sdfr	if (q->match & HX509_QUERY_KU_CRLSIGN)
3009178825Sdfr	    ku |= (1 << 6);
3010178825Sdfr	if (ku && check_key_usage(context, c, ku, TRUE))
3011178825Sdfr	    return 0;
3012178825Sdfr    }
3013178825Sdfr    if ((q->match & HX509_QUERY_ANCHOR))
3014178825Sdfr	return 0;
3015178825Sdfr
3016178825Sdfr    if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) {
3017178825Sdfr	hx509_cert_attribute a;
3018178825Sdfr
3019233294Sstas	a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId);
3020178825Sdfr	if (a == NULL)
3021178825Sdfr	    return 0;
3022178825Sdfr	if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0)
3023178825Sdfr	    return 0;
3024178825Sdfr    }
3025178825Sdfr
3026178825Sdfr    if (q->match & HX509_QUERY_NO_MATCH_PATH) {
3027178825Sdfr	size_t i;
3028178825Sdfr
3029178825Sdfr	for (i = 0; i < q->path->len; i++)
3030178825Sdfr	    if (hx509_cert_cmp(q->path->val[i], cert) == 0)
3031178825Sdfr		return 0;
3032178825Sdfr    }
3033178825Sdfr    if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) {
3034178825Sdfr	const char *name = hx509_cert_get_friendly_name(cert);
3035178825Sdfr	if (name == NULL)
3036178825Sdfr	    return 0;
3037178825Sdfr	if (strcasecmp(q->friendlyname, name) != 0)
3038178825Sdfr	    return 0;
3039178825Sdfr    }
3040178825Sdfr    if (q->match & HX509_QUERY_MATCH_FUNCTION) {
3041233294Sstas	ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx);
3042178825Sdfr	if (ret != 0)
3043178825Sdfr	    return 0;
3044178825Sdfr    }
3045178825Sdfr
3046178825Sdfr    if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) {
3047178825Sdfr	heim_octet_string os;
3048178825Sdfr
3049178825Sdfr	os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3050233294Sstas	os.length =
3051178825Sdfr	    c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3052178825Sdfr
3053178825Sdfr	ret = _hx509_verify_signature(context,
3054178825Sdfr				      NULL,
3055178825Sdfr				      hx509_signature_sha1(),
3056178825Sdfr				      &os,
3057178825Sdfr				      q->keyhash_sha1);
3058178825Sdfr	if (ret != 0)
3059178825Sdfr	    return 0;
3060178825Sdfr    }
3061178825Sdfr
3062178825Sdfr    if (q->match & HX509_QUERY_MATCH_TIME) {
3063178825Sdfr	time_t t;
3064178825Sdfr	t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore);
3065178825Sdfr	if (t > q->timenow)
3066178825Sdfr	    return 0;
3067178825Sdfr	t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter);
3068178825Sdfr	if (t < q->timenow)
3069178825Sdfr	    return 0;
3070178825Sdfr    }
3071178825Sdfr
3072233294Sstas    /* If an EKU is required, check the cert for it. */
3073233294Sstas    if ((q->match & HX509_QUERY_MATCH_EKU) &&
3074233294Sstas	hx509_cert_check_eku(context, cert, q->eku, 0))
3075233294Sstas	return 0;
3076233294Sstas
3077233294Sstas    if ((q->match & HX509_QUERY_MATCH_EXPR)) {
3078233294Sstas	hx509_env env = NULL;
3079233294Sstas
3080233294Sstas	ret = _hx509_cert_to_env(context, cert, &env);
3081233294Sstas	if (ret)
3082233294Sstas	    return 0;
3083233294Sstas
3084233294Sstas	ret = _hx509_expr_eval(context, env, q->expr);
3085233294Sstas	hx509_env_free(&env);
3086233294Sstas	if (ret == 0)
3087233294Sstas	    return 0;
3088233294Sstas    }
3089233294Sstas
3090178825Sdfr    if (q->match & ~HX509_QUERY_MASK)
3091178825Sdfr	return 0;
3092178825Sdfr
3093178825Sdfr    return 1;
3094178825Sdfr}
3095178825Sdfr
3096178825Sdfr/**
3097178825Sdfr * Set a statistic file for the query statistics.
3098178825Sdfr *
3099178825Sdfr * @param context A hx509 context.
3100178825Sdfr * @param fn statistics file name
3101178825Sdfr *
3102178825Sdfr * @ingroup hx509_cert
3103178825Sdfr */
3104178825Sdfr
3105178825Sdfrvoid
3106178825Sdfrhx509_query_statistic_file(hx509_context context, const char *fn)
3107178825Sdfr{
3108178825Sdfr    if (context->querystat)
3109178825Sdfr	free(context->querystat);
3110178825Sdfr    context->querystat = strdup(fn);
3111178825Sdfr}
3112178825Sdfr
3113178825Sdfrvoid
3114178825Sdfr_hx509_query_statistic(hx509_context context, int type, const hx509_query *q)
3115178825Sdfr{
3116178825Sdfr    FILE *f;
3117178825Sdfr    if (context->querystat == NULL)
3118178825Sdfr	return;
3119178825Sdfr    f = fopen(context->querystat, "a");
3120178825Sdfr    if (f == NULL)
3121178825Sdfr	return;
3122233294Sstas    rk_cloexec_file(f);
3123178825Sdfr    fprintf(f, "%d %d\n", type, q->match);
3124178825Sdfr    fclose(f);
3125178825Sdfr}
3126178825Sdfr
3127178825Sdfrstatic const char *statname[] = {
3128178825Sdfr    "find issuer cert",
3129178825Sdfr    "match serialnumber",
3130178825Sdfr    "match issuer name",
3131178825Sdfr    "match subject name",
3132178825Sdfr    "match subject key id",
3133178825Sdfr    "match issuer id",
3134178825Sdfr    "private key",
3135178825Sdfr    "ku encipherment",
3136178825Sdfr    "ku digitalsignature",
3137178825Sdfr    "ku keycertsign",
3138178825Sdfr    "ku crlsign",
3139178825Sdfr    "ku nonrepudiation",
3140178825Sdfr    "ku keyagreement",
3141178825Sdfr    "ku dataencipherment",
3142178825Sdfr    "anchor",
3143178825Sdfr    "match certificate",
3144178825Sdfr    "match local key id",
3145178825Sdfr    "no match path",
3146178825Sdfr    "match friendly name",
3147178825Sdfr    "match function",
3148178825Sdfr    "match key hash sha1",
3149178825Sdfr    "match time"
3150178825Sdfr};
3151178825Sdfr
3152178825Sdfrstruct stat_el {
3153178825Sdfr    unsigned long stats;
3154178825Sdfr    unsigned int index;
3155178825Sdfr};
3156178825Sdfr
3157178825Sdfr
3158178825Sdfrstatic int
3159178825Sdfrstat_sort(const void *a, const void *b)
3160178825Sdfr{
3161178825Sdfr    const struct stat_el *ae = a;
3162178825Sdfr    const struct stat_el *be = b;
3163178825Sdfr    return be->stats - ae->stats;
3164178825Sdfr}
3165178825Sdfr
3166178825Sdfr/**
3167178825Sdfr * Unparse the statistics file and print the result on a FILE descriptor.
3168178825Sdfr *
3169178825Sdfr * @param context A hx509 context.
3170178825Sdfr * @param printtype tyep to print
3171178825Sdfr * @param out the FILE to write the data on.
3172178825Sdfr *
3173178825Sdfr * @ingroup hx509_cert
3174178825Sdfr */
3175178825Sdfr
3176178825Sdfrvoid
3177178825Sdfrhx509_query_unparse_stats(hx509_context context, int printtype, FILE *out)
3178178825Sdfr{
3179178825Sdfr    rtbl_t t;
3180178825Sdfr    FILE *f;
3181233294Sstas    int type, mask, num;
3182233294Sstas    size_t i;
3183178825Sdfr    unsigned long multiqueries = 0, totalqueries = 0;
3184178825Sdfr    struct stat_el stats[32];
3185178825Sdfr
3186178825Sdfr    if (context->querystat == NULL)
3187178825Sdfr	return;
3188178825Sdfr    f = fopen(context->querystat, "r");
3189178825Sdfr    if (f == NULL) {
3190233294Sstas	fprintf(out, "No statistic file %s: %s.\n",
3191178825Sdfr		context->querystat, strerror(errno));
3192178825Sdfr	return;
3193178825Sdfr    }
3194233294Sstas    rk_cloexec_file(f);
3195233294Sstas
3196178825Sdfr    for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3197178825Sdfr	stats[i].index = i;
3198178825Sdfr	stats[i].stats = 0;
3199178825Sdfr    }
3200178825Sdfr
3201178825Sdfr    while (fscanf(f, "%d %d\n", &type, &mask) == 2) {
3202178825Sdfr	if (type != printtype)
3203178825Sdfr	    continue;
3204178825Sdfr	num = i = 0;
3205178825Sdfr	while (mask && i < sizeof(stats)/sizeof(stats[0])) {
3206178825Sdfr	    if (mask & 1) {
3207178825Sdfr		stats[i].stats++;
3208178825Sdfr		num++;
3209178825Sdfr	    }
3210178825Sdfr	    mask = mask >>1 ;
3211178825Sdfr	    i++;
3212178825Sdfr	}
3213178825Sdfr	if (num > 1)
3214178825Sdfr	    multiqueries++;
3215178825Sdfr	totalqueries++;
3216178825Sdfr    }
3217178825Sdfr    fclose(f);
3218178825Sdfr
3219178825Sdfr    qsort(stats, sizeof(stats)/sizeof(stats[0]), sizeof(stats[0]), stat_sort);
3220178825Sdfr
3221178825Sdfr    t = rtbl_create();
3222178825Sdfr    if (t == NULL)
3223178825Sdfr	errx(1, "out of memory");
3224178825Sdfr
3225178825Sdfr    rtbl_set_separator (t, "  ");
3226233294Sstas
3227178825Sdfr    rtbl_add_column_by_id (t, 0, "Name", 0);
3228178825Sdfr    rtbl_add_column_by_id (t, 1, "Counter", 0);
3229178825Sdfr
3230178825Sdfr
3231178825Sdfr    for (i = 0; i < sizeof(stats)/sizeof(stats[0]); i++) {
3232178825Sdfr	char str[10];
3233178825Sdfr
3234233294Sstas	if (stats[i].index < sizeof(statname)/sizeof(statname[0]))
3235178825Sdfr	    rtbl_add_column_entry_by_id (t, 0, statname[stats[i].index]);
3236178825Sdfr	else {
3237178825Sdfr	    snprintf(str, sizeof(str), "%d", stats[i].index);
3238178825Sdfr	    rtbl_add_column_entry_by_id (t, 0, str);
3239178825Sdfr	}
3240178825Sdfr	snprintf(str, sizeof(str), "%lu", stats[i].stats);
3241178825Sdfr	rtbl_add_column_entry_by_id (t, 1, str);
3242178825Sdfr    }
3243178825Sdfr
3244178825Sdfr    rtbl_format(t, out);
3245178825Sdfr    rtbl_destroy(t);
3246178825Sdfr
3247233294Sstas    fprintf(out, "\nQueries: multi %lu total %lu\n",
3248178825Sdfr	    multiqueries, totalqueries);
3249178825Sdfr}
3250178825Sdfr
3251178825Sdfr/**
3252178825Sdfr * Check the extended key usage on the hx509 certificate.
3253178825Sdfr *
3254178825Sdfr * @param context A hx509 context.
3255178825Sdfr * @param cert A hx509 context.
3256178825Sdfr * @param eku the EKU to check for
3257178825Sdfr * @param allow_any_eku if the any EKU is set, allow that to be a
3258178825Sdfr * substitute.
3259178825Sdfr *
3260178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
3261178825Sdfr *
3262178825Sdfr * @ingroup hx509_cert
3263178825Sdfr */
3264178825Sdfr
3265178825Sdfrint
3266178825Sdfrhx509_cert_check_eku(hx509_context context, hx509_cert cert,
3267178825Sdfr		     const heim_oid *eku, int allow_any_eku)
3268178825Sdfr{
3269178825Sdfr    ExtKeyUsage e;
3270233294Sstas    int ret;
3271233294Sstas    size_t i;
3272178825Sdfr
3273178825Sdfr    ret = find_extension_eku(_hx509_get_cert(cert), &e);
3274178825Sdfr    if (ret) {
3275178825Sdfr	hx509_clear_error_string(context);
3276178825Sdfr	return ret;
3277178825Sdfr    }
3278178825Sdfr
3279178825Sdfr    for (i = 0; i < e.len; i++) {
3280178825Sdfr	if (der_heim_oid_cmp(eku, &e.val[i]) == 0) {
3281178825Sdfr	    free_ExtKeyUsage(&e);
3282178825Sdfr	    return 0;
3283178825Sdfr	}
3284178825Sdfr	if (allow_any_eku) {
3285178825Sdfr#if 0
3286178825Sdfr	    if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) {
3287178825Sdfr		free_ExtKeyUsage(&e);
3288178825Sdfr		return 0;
3289178825Sdfr	    }
3290178825Sdfr#endif
3291178825Sdfr	}
3292178825Sdfr    }
3293178825Sdfr    free_ExtKeyUsage(&e);
3294178825Sdfr    hx509_clear_error_string(context);
3295178825Sdfr    return HX509_CERTIFICATE_MISSING_EKU;
3296178825Sdfr}
3297178825Sdfr
3298178825Sdfrint
3299178825Sdfr_hx509_cert_get_keyusage(hx509_context context,
3300178825Sdfr			 hx509_cert c,
3301178825Sdfr			 KeyUsage *ku)
3302178825Sdfr{
3303178825Sdfr    Certificate *cert;
3304178825Sdfr    const Extension *e;
3305178825Sdfr    size_t size;
3306233294Sstas    int ret;
3307233294Sstas    size_t i = 0;
3308178825Sdfr
3309178825Sdfr    memset(ku, 0, sizeof(*ku));
3310178825Sdfr
3311178825Sdfr    cert = _hx509_get_cert(c);
3312178825Sdfr
3313178825Sdfr    if (_hx509_cert_get_version(cert) < 3)
3314178825Sdfr	return 0;
3315178825Sdfr
3316233294Sstas    e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i);
3317178825Sdfr    if (e == NULL)
3318178825Sdfr	return HX509_KU_CERT_MISSING;
3319233294Sstas
3320178825Sdfr    ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size);
3321178825Sdfr    if (ret)
3322178825Sdfr	return ret;
3323178825Sdfr    return 0;
3324178825Sdfr}
3325178825Sdfr
3326178825Sdfrint
3327178825Sdfr_hx509_cert_get_eku(hx509_context context,
3328178825Sdfr		    hx509_cert cert,
3329178825Sdfr		    ExtKeyUsage *e)
3330178825Sdfr{
3331178825Sdfr    int ret;
3332178825Sdfr
3333178825Sdfr    memset(e, 0, sizeof(*e));
3334178825Sdfr
3335178825Sdfr    ret = find_extension_eku(_hx509_get_cert(cert), e);
3336178825Sdfr    if (ret && ret != HX509_EXTENSION_NOT_FOUND) {
3337178825Sdfr	hx509_clear_error_string(context);
3338178825Sdfr	return ret;
3339178825Sdfr    }
3340178825Sdfr    return 0;
3341178825Sdfr}
3342178825Sdfr
3343178825Sdfr/**
3344178825Sdfr * Encodes the hx509 certificate as a DER encode binary.
3345178825Sdfr *
3346178825Sdfr * @param context A hx509 context.
3347178825Sdfr * @param c the certificate to encode.
3348178825Sdfr * @param os the encode certificate, set to NULL, 0 on case of
3349233294Sstas * error. Free the os->data with hx509_xfree().
3350178825Sdfr *
3351178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
3352178825Sdfr *
3353178825Sdfr * @ingroup hx509_cert
3354178825Sdfr */
3355178825Sdfr
3356178825Sdfrint
3357178825Sdfrhx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os)
3358178825Sdfr{
3359178825Sdfr    size_t size;
3360178825Sdfr    int ret;
3361178825Sdfr
3362178825Sdfr    os->data = NULL;
3363178825Sdfr    os->length = 0;
3364178825Sdfr
3365233294Sstas    ASN1_MALLOC_ENCODE(Certificate, os->data, os->length,
3366178825Sdfr		       _hx509_get_cert(c), &size, ret);
3367178825Sdfr    if (ret) {
3368178825Sdfr	os->data = NULL;
3369178825Sdfr	os->length = 0;
3370178825Sdfr	return ret;
3371178825Sdfr    }
3372178825Sdfr    if (os->length != size)
3373178825Sdfr	_hx509_abort("internal ASN.1 encoder error");
3374178825Sdfr
3375178825Sdfr    return ret;
3376178825Sdfr}
3377178825Sdfr
3378178825Sdfr/*
3379178825Sdfr * Last to avoid lost __attribute__s due to #undef.
3380178825Sdfr */
3381178825Sdfr
3382178825Sdfr#undef __attribute__
3383178825Sdfr#define __attribute__(X)
3384178825Sdfr
3385178825Sdfrvoid
3386178825Sdfr_hx509_abort(const char *fmt, ...)
3387178825Sdfr     __attribute__ ((noreturn, format (printf, 1, 2)))
3388178825Sdfr{
3389178825Sdfr    va_list ap;
3390178825Sdfr    va_start(ap, fmt);
3391178825Sdfr    vprintf(fmt, ap);
3392178825Sdfr    va_end(ap);
3393178825Sdfr    printf("\n");
3394178825Sdfr    fflush(stdout);
3395178825Sdfr    abort();
3396178825Sdfr}
3397178825Sdfr
3398178825Sdfr/**
3399178825Sdfr * Free a data element allocated in the library.
3400178825Sdfr *
3401178825Sdfr * @param ptr data to be freed.
3402178825Sdfr *
3403178825Sdfr * @ingroup hx509_misc
3404178825Sdfr */
3405178825Sdfr
3406178825Sdfrvoid
3407178825Sdfrhx509_xfree(void *ptr)
3408178825Sdfr{
3409178825Sdfr    free(ptr);
3410178825Sdfr}
3411233294Sstas
3412233294Sstas/**
3413233294Sstas *
3414233294Sstas */
3415233294Sstas
3416233294Sstasint
3417233294Sstas_hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env)
3418233294Sstas{
3419233294Sstas    ExtKeyUsage eku;
3420233294Sstas    hx509_name name;
3421233294Sstas    char *buf;
3422233294Sstas    int ret;
3423233294Sstas    hx509_env envcert = NULL;
3424233294Sstas
3425233294Sstas    *env = NULL;
3426233294Sstas
3427233294Sstas    /* version */
3428233294Sstas    asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert)));
3429233294Sstas    ret = hx509_env_add(context, &envcert, "version", buf);
3430233294Sstas    free(buf);
3431233294Sstas    if (ret)
3432233294Sstas	goto out;
3433233294Sstas
3434233294Sstas    /* subject */
3435233294Sstas    ret = hx509_cert_get_subject(cert, &name);
3436233294Sstas    if (ret)
3437233294Sstas	goto out;
3438233294Sstas
3439233294Sstas    ret = hx509_name_to_string(name, &buf);
3440233294Sstas    if (ret) {
3441233294Sstas	hx509_name_free(&name);
3442233294Sstas	goto out;
3443233294Sstas    }
3444233294Sstas
3445233294Sstas    ret = hx509_env_add(context, &envcert, "subject", buf);
3446233294Sstas    hx509_name_free(&name);
3447233294Sstas    if (ret)
3448233294Sstas	goto out;
3449233294Sstas
3450233294Sstas    /* issuer */
3451233294Sstas    ret = hx509_cert_get_issuer(cert, &name);
3452233294Sstas    if (ret)
3453233294Sstas	goto out;
3454233294Sstas
3455233294Sstas    ret = hx509_name_to_string(name, &buf);
3456233294Sstas    hx509_name_free(&name);
3457233294Sstas    if (ret)
3458233294Sstas	goto out;
3459233294Sstas
3460233294Sstas    ret = hx509_env_add(context, &envcert, "issuer", buf);
3461233294Sstas    hx509_xfree(buf);
3462233294Sstas    if (ret)
3463233294Sstas	goto out;
3464233294Sstas
3465233294Sstas    /* eku */
3466233294Sstas
3467233294Sstas    ret = _hx509_cert_get_eku(context, cert, &eku);
3468233294Sstas    if (ret == HX509_EXTENSION_NOT_FOUND)
3469233294Sstas	;
3470233294Sstas    else if (ret != 0)
3471233294Sstas	goto out;
3472233294Sstas    else {
3473233294Sstas	size_t i;
3474233294Sstas	hx509_env enveku = NULL;
3475233294Sstas
3476233294Sstas	for (i = 0; i < eku.len; i++) {
3477233294Sstas
3478233294Sstas	    ret = der_print_heim_oid(&eku.val[i], '.', &buf);
3479233294Sstas	    if (ret) {
3480233294Sstas		free_ExtKeyUsage(&eku);
3481233294Sstas		hx509_env_free(&enveku);
3482233294Sstas		goto out;
3483233294Sstas	    }
3484233294Sstas	    ret = hx509_env_add(context, &enveku, buf, "oid-name-here");
3485233294Sstas	    free(buf);
3486233294Sstas	    if (ret) {
3487233294Sstas		free_ExtKeyUsage(&eku);
3488233294Sstas		hx509_env_free(&enveku);
3489233294Sstas		goto out;
3490233294Sstas	    }
3491233294Sstas	}
3492233294Sstas	free_ExtKeyUsage(&eku);
3493233294Sstas
3494233294Sstas	ret = hx509_env_add_binding(context, &envcert, "eku", enveku);
3495233294Sstas	if (ret) {
3496233294Sstas	    hx509_env_free(&enveku);
3497233294Sstas	    goto out;
3498233294Sstas	}
3499233294Sstas    }
3500233294Sstas
3501233294Sstas    {
3502233294Sstas	Certificate *c = _hx509_get_cert(cert);
3503233294Sstas        heim_octet_string os, sig;
3504233294Sstas	hx509_env envhash = NULL;
3505233294Sstas
3506233294Sstas	os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
3507233294Sstas	os.length =
3508233294Sstas	  c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8;
3509233294Sstas
3510233294Sstas	ret = _hx509_create_signature(context,
3511233294Sstas				      NULL,
3512233294Sstas				      hx509_signature_sha1(),
3513233294Sstas				      &os,
3514233294Sstas				      NULL,
3515233294Sstas				      &sig);
3516233294Sstas	if (ret != 0)
3517233294Sstas	    goto out;
3518233294Sstas
3519233294Sstas	ret = hex_encode(sig.data, sig.length, &buf);
3520233294Sstas	der_free_octet_string(&sig);
3521233294Sstas	if (ret < 0) {
3522233294Sstas	    ret = ENOMEM;
3523233294Sstas	    hx509_set_error_string(context, 0, ret,
3524233294Sstas				   "Out of memory");
3525233294Sstas	    goto out;
3526233294Sstas	}
3527233294Sstas
3528233294Sstas	ret = hx509_env_add(context, &envhash, "sha1", buf);
3529233294Sstas	free(buf);
3530233294Sstas	if (ret)
3531233294Sstas	    goto out;
3532233294Sstas
3533233294Sstas	ret = hx509_env_add_binding(context, &envcert, "hash", envhash);
3534233294Sstas	if (ret) {
3535233294Sstas	  hx509_env_free(&envhash);
3536233294Sstas	  goto out;
3537233294Sstas	}
3538233294Sstas    }
3539233294Sstas
3540233294Sstas    ret = hx509_env_add_binding(context, env, "certificate", envcert);
3541233294Sstas    if (ret)
3542233294Sstas	goto out;
3543233294Sstas
3544233294Sstas    return 0;
3545233294Sstas
3546233294Sstasout:
3547233294Sstas    hx509_env_free(&envcert);
3548233294Sstas    return ret;
3549233294Sstas}
3550233294Sstas
3551233294Sstas/**
3552233294Sstas * Print a simple representation of a certificate
3553233294Sstas *
3554233294Sstas * @param context A hx509 context, can be NULL
3555233294Sstas * @param cert certificate to print
3556233294Sstas * @param out the stdio output stream, if NULL, stdout is used
3557233294Sstas *
3558233294Sstas * @return An hx509 error code
3559233294Sstas *
3560233294Sstas * @ingroup hx509_cert
3561233294Sstas */
3562233294Sstas
3563233294Sstasint
3564233294Sstashx509_print_cert(hx509_context context, hx509_cert cert, FILE *out)
3565233294Sstas{
3566233294Sstas    hx509_name name;
3567233294Sstas    char *str;
3568233294Sstas    int ret;
3569233294Sstas
3570233294Sstas    if (out == NULL)
3571233294Sstas	out = stderr;
3572233294Sstas
3573233294Sstas    ret = hx509_cert_get_issuer(cert, &name);
3574233294Sstas    if (ret)
3575233294Sstas	return ret;
3576233294Sstas    hx509_name_to_string(name, &str);
3577233294Sstas    hx509_name_free(&name);
3578233294Sstas    fprintf(out, "    issuer:  \"%s\"\n", str);
3579233294Sstas    free(str);
3580233294Sstas
3581233294Sstas    ret = hx509_cert_get_subject(cert, &name);
3582233294Sstas    if (ret)
3583233294Sstas	return ret;
3584233294Sstas    hx509_name_to_string(name, &str);
3585233294Sstas    hx509_name_free(&name);
3586233294Sstas    fprintf(out, "    subject: \"%s\"\n", str);
3587233294Sstas    free(str);
3588233294Sstas
3589233294Sstas    {
3590233294Sstas	heim_integer serialNumber;
3591233294Sstas
3592233294Sstas	ret = hx509_cert_get_serialnumber(cert, &serialNumber);
3593233294Sstas	if (ret)
3594233294Sstas	    return ret;
3595233294Sstas	ret = der_print_hex_heim_integer(&serialNumber, &str);
3596233294Sstas	if (ret)
3597233294Sstas	    return ret;
3598233294Sstas	der_free_heim_integer(&serialNumber);
3599233294Sstas	fprintf(out, "    serial: %s\n", str);
3600233294Sstas	free(str);
3601233294Sstas    }
3602233294Sstas
3603233294Sstas    printf("    keyusage: ");
3604233294Sstas    ret = hx509_cert_keyusage_print(context, cert, &str);
3605233294Sstas    if (ret == 0) {
3606233294Sstas	fprintf(out, "%s\n", str);
3607233294Sstas	free(str);
3608233294Sstas    } else
3609233294Sstas	fprintf(out, "no");
3610233294Sstas
3611233294Sstas    return 0;
3612233294Sstas}
3613