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