xref: /freebsd/crypto/heimdal/lib/hx509/cert.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
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