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