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