1178825Sdfr/*
2233294Sstas * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7178825Sdfr *
8233294Sstas * Redistribution and use in source and binary forms, with or without
9233294Sstas * modification, are permitted provided that the following conditions
10233294Sstas * are met:
11178825Sdfr *
12233294Sstas * 1. Redistributions of source code must retain the above copyright
13233294Sstas *    notice, this list of conditions and the following disclaimer.
14178825Sdfr *
15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
16233294Sstas *    notice, this list of conditions and the following disclaimer in the
17233294Sstas *    documentation and/or other materials provided with the distribution.
18178825Sdfr *
19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
20233294Sstas *    may be used to endorse or promote products derived from this software
21233294Sstas *    without specific prior written permission.
22233294Sstas *
23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33233294Sstas * SUCH DAMAGE.
34178825Sdfr */
35178825Sdfr
36178825Sdfr#include "hx_locl.h"
37178825Sdfr
38178825Sdfr/**
39178825Sdfr * @page page_keyset Certificate store operations
40178825Sdfr *
41178825Sdfr * Type of certificates store:
42178825Sdfr * - MEMORY
43178825Sdfr *   In memory based format. Doesnt support storing.
44233294Sstas * - FILE
45178825Sdfr *   FILE supports raw DER certicates and PEM certicates. When PEM is
46178825Sdfr *   used the file can contain may certificates and match private
47178825Sdfr *   keys. Support storing the certificates. DER format only supports
48178825Sdfr *   on certificate and no private key.
49178825Sdfr * - PEM-FILE
50178825Sdfr *   Same as FILE, defaulting to PEM encoded certificates.
51178825Sdfr * - PEM-FILE
52178825Sdfr *   Same as FILE, defaulting to DER encoded certificates.
53178825Sdfr * - PKCS11
54178825Sdfr * - PKCS12
55178825Sdfr * - DIR
56178825Sdfr * - KEYCHAIN
57178825Sdfr *   Apple Mac OS X KeyChain backed keychain object.
58178825Sdfr *
59178825Sdfr * See the library functions here: @ref hx509_keyset
60178825Sdfr */
61178825Sdfr
62178825Sdfrstruct hx509_certs_data {
63233294Sstas    unsigned int ref;
64178825Sdfr    struct hx509_keyset_ops *ops;
65178825Sdfr    void *ops_data;
66178825Sdfr};
67178825Sdfr
68178825Sdfrstatic struct hx509_keyset_ops *
69178825Sdfr_hx509_ks_type(hx509_context context, const char *type)
70178825Sdfr{
71178825Sdfr    int i;
72178825Sdfr
73178825Sdfr    for (i = 0; i < context->ks_num_ops; i++)
74178825Sdfr	if (strcasecmp(type, context->ks_ops[i]->name) == 0)
75178825Sdfr	    return context->ks_ops[i];
76178825Sdfr
77178825Sdfr    return NULL;
78178825Sdfr}
79178825Sdfr
80178825Sdfrvoid
81178825Sdfr_hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
82178825Sdfr{
83178825Sdfr    struct hx509_keyset_ops **val;
84178825Sdfr
85178825Sdfr    if (_hx509_ks_type(context, ops->name))
86178825Sdfr	return;
87178825Sdfr
88233294Sstas    val = realloc(context->ks_ops,
89178825Sdfr		  (context->ks_num_ops + 1) * sizeof(context->ks_ops[0]));
90178825Sdfr    if (val == NULL)
91178825Sdfr	return;
92178825Sdfr    val[context->ks_num_ops] = ops;
93178825Sdfr    context->ks_ops = val;
94178825Sdfr    context->ks_num_ops++;
95178825Sdfr}
96178825Sdfr
97178825Sdfr/**
98178825Sdfr * Open or creates a new hx509 certificate store.
99178825Sdfr *
100178825Sdfr * @param context A hx509 context
101178825Sdfr * @param name name of the store, format is TYPE:type-specific-string,
102178825Sdfr * if NULL is used the MEMORY store is used.
103178825Sdfr * @param flags list of flags:
104178825Sdfr * - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
105178825Sdfr * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
106178825Sdfr * @param lock a lock that unlocks the certificates store, use NULL to
107178825Sdfr * select no password/certifictes/prompt lock (see @ref page_lock).
108178825Sdfr * @param certs return pointer, free with hx509_certs_free().
109178825Sdfr *
110178825Sdfr * @ingroup hx509_keyset
111178825Sdfr */
112178825Sdfr
113178825Sdfrint
114178825Sdfrhx509_certs_init(hx509_context context,
115178825Sdfr		 const char *name, int flags,
116178825Sdfr		 hx509_lock lock, hx509_certs *certs)
117178825Sdfr{
118178825Sdfr    struct hx509_keyset_ops *ops;
119178825Sdfr    const char *residue;
120178825Sdfr    hx509_certs c;
121178825Sdfr    char *type;
122178825Sdfr    int ret;
123178825Sdfr
124178825Sdfr    *certs = NULL;
125178825Sdfr
126178825Sdfr    residue = strchr(name, ':');
127178825Sdfr    if (residue) {
128178825Sdfr	type = malloc(residue - name + 1);
129178825Sdfr	if (type)
130178825Sdfr	    strlcpy(type, name, residue - name + 1);
131178825Sdfr	residue++;
132178825Sdfr	if (residue[0] == '\0')
133178825Sdfr	    residue = NULL;
134178825Sdfr    } else {
135178825Sdfr	type = strdup("MEMORY");
136178825Sdfr	residue = name;
137178825Sdfr    }
138178825Sdfr    if (type == NULL) {
139178825Sdfr	hx509_clear_error_string(context);
140178825Sdfr	return ENOMEM;
141178825Sdfr    }
142233294Sstas
143178825Sdfr    ops = _hx509_ks_type(context, type);
144178825Sdfr    if (ops == NULL) {
145233294Sstas	hx509_set_error_string(context, 0, ENOENT,
146178825Sdfr			       "Keyset type %s is not supported", type);
147178825Sdfr	free(type);
148178825Sdfr	return ENOENT;
149178825Sdfr    }
150178825Sdfr    free(type);
151178825Sdfr    c = calloc(1, sizeof(*c));
152178825Sdfr    if (c == NULL) {
153178825Sdfr	hx509_clear_error_string(context);
154178825Sdfr	return ENOMEM;
155178825Sdfr    }
156178825Sdfr    c->ops = ops;
157178825Sdfr    c->ref = 1;
158178825Sdfr
159178825Sdfr    ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
160178825Sdfr    if (ret) {
161178825Sdfr	free(c);
162178825Sdfr	return ret;
163178825Sdfr    }
164178825Sdfr
165178825Sdfr    *certs = c;
166178825Sdfr    return 0;
167178825Sdfr}
168178825Sdfr
169178825Sdfr/**
170178825Sdfr * Write the certificate store to stable storage.
171178825Sdfr *
172178825Sdfr * @param context A hx509 context.
173178825Sdfr * @param certs a certificate store to store.
174178825Sdfr * @param flags currently unused, use 0.
175178825Sdfr * @param lock a lock that unlocks the certificates store, use NULL to
176178825Sdfr * select no password/certifictes/prompt lock (see @ref page_lock).
177178825Sdfr *
178178825Sdfr * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
179178825Sdfr * the certificate store doesn't support the store operation.
180178825Sdfr *
181178825Sdfr * @ingroup hx509_keyset
182178825Sdfr */
183178825Sdfr
184178825Sdfrint
185178825Sdfrhx509_certs_store(hx509_context context,
186178825Sdfr		  hx509_certs certs,
187178825Sdfr		  int flags,
188178825Sdfr		  hx509_lock lock)
189178825Sdfr{
190178825Sdfr    if (certs->ops->store == NULL) {
191178825Sdfr	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
192178825Sdfr			       "keystore if type %s doesn't support "
193178825Sdfr			       "store operation",
194178825Sdfr			       certs->ops->name);
195178825Sdfr	return HX509_UNSUPPORTED_OPERATION;
196178825Sdfr    }
197178825Sdfr
198178825Sdfr    return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
199178825Sdfr}
200178825Sdfr
201178825Sdfr
202178825Sdfrhx509_certs
203233294Sstashx509_certs_ref(hx509_certs certs)
204178825Sdfr{
205178825Sdfr    if (certs == NULL)
206178825Sdfr	return NULL;
207233294Sstas    if (certs->ref == 0)
208233294Sstas	_hx509_abort("certs refcount == 0 on ref");
209233294Sstas    if (certs->ref == UINT_MAX)
210233294Sstas	_hx509_abort("certs refcount == UINT_MAX on ref");
211178825Sdfr    certs->ref++;
212178825Sdfr    return certs;
213178825Sdfr}
214178825Sdfr
215178825Sdfr/**
216178825Sdfr * Free a certificate store.
217178825Sdfr *
218178825Sdfr * @param certs certificate store to free.
219178825Sdfr *
220178825Sdfr * @ingroup hx509_keyset
221178825Sdfr */
222178825Sdfr
223178825Sdfrvoid
224178825Sdfrhx509_certs_free(hx509_certs *certs)
225178825Sdfr{
226178825Sdfr    if (*certs) {
227233294Sstas	if ((*certs)->ref == 0)
228233294Sstas	    _hx509_abort("cert refcount == 0 on free");
229178825Sdfr	if (--(*certs)->ref > 0)
230178825Sdfr	    return;
231178825Sdfr
232178825Sdfr	(*(*certs)->ops->free)(*certs, (*certs)->ops_data);
233178825Sdfr	free(*certs);
234178825Sdfr	*certs = NULL;
235178825Sdfr    }
236178825Sdfr}
237178825Sdfr
238178825Sdfr/**
239178825Sdfr * Start the integration
240178825Sdfr *
241178825Sdfr * @param context a hx509 context.
242178825Sdfr * @param certs certificate store to iterate over
243178825Sdfr * @param cursor cursor that will keep track of progress, free with
244178825Sdfr * hx509_certs_end_seq().
245178825Sdfr *
246178825Sdfr * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is
247178825Sdfr * returned if the certificate store doesn't support the iteration
248178825Sdfr * operation.
249178825Sdfr *
250178825Sdfr * @ingroup hx509_keyset
251178825Sdfr */
252178825Sdfr
253178825Sdfrint
254178825Sdfrhx509_certs_start_seq(hx509_context context,
255178825Sdfr		      hx509_certs certs,
256178825Sdfr		      hx509_cursor *cursor)
257178825Sdfr{
258178825Sdfr    int ret;
259178825Sdfr
260178825Sdfr    if (certs->ops->iter_start == NULL) {
261233294Sstas	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
262233294Sstas			       "Keyset type %s doesn't support iteration",
263178825Sdfr			       certs->ops->name);
264178825Sdfr	return HX509_UNSUPPORTED_OPERATION;
265178825Sdfr    }
266178825Sdfr
267178825Sdfr    ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
268178825Sdfr    if (ret)
269178825Sdfr	return ret;
270178825Sdfr
271178825Sdfr    return 0;
272178825Sdfr}
273178825Sdfr
274178825Sdfr/**
275178825Sdfr * Get next ceritificate from the certificate keystore pointed out by
276178825Sdfr * cursor.
277178825Sdfr *
278178825Sdfr * @param context a hx509 context.
279178825Sdfr * @param certs certificate store to iterate over.
280178825Sdfr * @param cursor cursor that keeps track of progress.
281178825Sdfr * @param cert return certificate next in store, NULL if the store
282178825Sdfr * contains no more certificates. Free with hx509_cert_free().
283178825Sdfr *
284178825Sdfr * @return Returns an hx509 error code.
285178825Sdfr *
286178825Sdfr * @ingroup hx509_keyset
287178825Sdfr */
288178825Sdfr
289178825Sdfrint
290178825Sdfrhx509_certs_next_cert(hx509_context context,
291178825Sdfr		      hx509_certs certs,
292178825Sdfr		      hx509_cursor cursor,
293178825Sdfr		      hx509_cert *cert)
294178825Sdfr{
295178825Sdfr    *cert = NULL;
296178825Sdfr    return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
297178825Sdfr}
298178825Sdfr
299178825Sdfr/**
300178825Sdfr * End the iteration over certificates.
301178825Sdfr *
302178825Sdfr * @param context a hx509 context.
303178825Sdfr * @param certs certificate store to iterate over.
304178825Sdfr * @param cursor cursor that will keep track of progress, freed.
305178825Sdfr *
306178825Sdfr * @return Returns an hx509 error code.
307178825Sdfr *
308178825Sdfr * @ingroup hx509_keyset
309178825Sdfr */
310178825Sdfr
311178825Sdfrint
312178825Sdfrhx509_certs_end_seq(hx509_context context,
313178825Sdfr		    hx509_certs certs,
314178825Sdfr		    hx509_cursor cursor)
315178825Sdfr{
316178825Sdfr    (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor);
317178825Sdfr    return 0;
318178825Sdfr}
319178825Sdfr
320178825Sdfr/**
321178825Sdfr * Iterate over all certificates in a keystore and call an function
322178825Sdfr * for each fo them.
323178825Sdfr *
324178825Sdfr * @param context a hx509 context.
325178825Sdfr * @param certs certificate store to iterate over.
326178825Sdfr * @param func function to call for each certificate. The function
327178825Sdfr * should return non-zero to abort the iteration, that value is passed
328233294Sstas * back to the caller of hx509_certs_iter_f().
329178825Sdfr * @param ctx context variable that will passed to the function.
330178825Sdfr *
331178825Sdfr * @return Returns an hx509 error code.
332178825Sdfr *
333178825Sdfr * @ingroup hx509_keyset
334178825Sdfr */
335178825Sdfr
336178825Sdfrint
337233294Sstashx509_certs_iter_f(hx509_context context,
338233294Sstas		   hx509_certs certs,
339233294Sstas		   int (*func)(hx509_context, void *, hx509_cert),
340233294Sstas		   void *ctx)
341178825Sdfr{
342178825Sdfr    hx509_cursor cursor;
343178825Sdfr    hx509_cert c;
344178825Sdfr    int ret;
345178825Sdfr
346178825Sdfr    ret = hx509_certs_start_seq(context, certs, &cursor);
347178825Sdfr    if (ret)
348178825Sdfr	return ret;
349233294Sstas
350178825Sdfr    while (1) {
351178825Sdfr	ret = hx509_certs_next_cert(context, certs, cursor, &c);
352178825Sdfr	if (ret)
353178825Sdfr	    break;
354178825Sdfr	if (c == NULL) {
355178825Sdfr	    ret = 0;
356178825Sdfr	    break;
357178825Sdfr	}
358178825Sdfr	ret = (*func)(context, ctx, c);
359178825Sdfr	hx509_cert_free(c);
360178825Sdfr	if (ret)
361178825Sdfr	    break;
362178825Sdfr    }
363178825Sdfr
364178825Sdfr    hx509_certs_end_seq(context, certs, cursor);
365178825Sdfr
366178825Sdfr    return ret;
367178825Sdfr}
368178825Sdfr
369233294Sstas/**
370233294Sstas * Iterate over all certificates in a keystore and call an function
371233294Sstas * for each fo them.
372233294Sstas *
373233294Sstas * @param context a hx509 context.
374233294Sstas * @param certs certificate store to iterate over.
375233294Sstas * @param func function to call for each certificate. The function
376233294Sstas * should return non-zero to abort the iteration, that value is passed
377233294Sstas * back to the caller of hx509_certs_iter().
378233294Sstas *
379233294Sstas * @return Returns an hx509 error code.
380233294Sstas *
381233294Sstas * @ingroup hx509_keyset
382233294Sstas */
383178825Sdfr
384233294Sstas#ifdef __BLOCKS__
385233294Sstas
386233294Sstasstatic int
387233294Sstascerts_iter(hx509_context context, void *ctx, hx509_cert cert)
388233294Sstas{
389233294Sstas    int (^func)(hx509_cert) = ctx;
390233294Sstas    return func(cert);
391233294Sstas}
392233294Sstas
393178825Sdfr/**
394233294Sstas * Iterate over all certificates in a keystore and call an block
395233294Sstas * for each fo them.
396178825Sdfr *
397178825Sdfr * @param context a hx509 context.
398233294Sstas * @param certs certificate store to iterate over.
399233294Sstas * @param func block to call for each certificate. The function
400233294Sstas * should return non-zero to abort the iteration, that value is passed
401233294Sstas * back to the caller of hx509_certs_iter().
402233294Sstas *
403233294Sstas * @return Returns an hx509 error code.
404233294Sstas *
405233294Sstas * @ingroup hx509_keyset
406233294Sstas */
407233294Sstas
408233294Sstasint
409233294Sstashx509_certs_iter(hx509_context context,
410233294Sstas		 hx509_certs certs,
411233294Sstas		 int (^func)(hx509_cert))
412233294Sstas{
413233294Sstas    return hx509_certs_iter_f(context, certs, certs_iter, func);
414233294Sstas}
415233294Sstas#endif
416233294Sstas
417233294Sstas
418233294Sstas/**
419233294Sstas * Function to use to hx509_certs_iter_f() as a function argument, the
420233294Sstas * ctx variable to hx509_certs_iter_f() should be a FILE file descriptor.
421233294Sstas *
422233294Sstas * @param context a hx509 context.
423233294Sstas * @param ctx used by hx509_certs_iter_f().
424178825Sdfr * @param c a certificate
425178825Sdfr *
426178825Sdfr * @return Returns an hx509 error code.
427178825Sdfr *
428178825Sdfr * @ingroup hx509_keyset
429178825Sdfr */
430178825Sdfr
431178825Sdfrint
432178825Sdfrhx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
433178825Sdfr{
434178825Sdfr    Certificate *cert;
435178825Sdfr    hx509_name n;
436178825Sdfr    char *s, *i;
437178825Sdfr
438178825Sdfr    cert = _hx509_get_cert(c);
439178825Sdfr
440178825Sdfr    _hx509_name_from_Name(&cert->tbsCertificate.subject, &n);
441178825Sdfr    hx509_name_to_string(n, &s);
442178825Sdfr    hx509_name_free(&n);
443178825Sdfr    _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n);
444178825Sdfr    hx509_name_to_string(n, &i);
445178825Sdfr    hx509_name_free(&n);
446178825Sdfr    fprintf(ctx, "subject: %s\nissuer: %s\n", s, i);
447178825Sdfr    free(s);
448178825Sdfr    free(i);
449178825Sdfr    return 0;
450178825Sdfr}
451178825Sdfr
452178825Sdfr/**
453178825Sdfr * Add a certificate to the certificiate store.
454178825Sdfr *
455178825Sdfr * The receiving keyset certs will either increase reference counter
456178825Sdfr * of the cert or make a deep copy, either way, the caller needs to
457178825Sdfr * free the cert itself.
458178825Sdfr *
459178825Sdfr * @param context a hx509 context.
460178825Sdfr * @param certs certificate store to add the certificate to.
461178825Sdfr * @param cert certificate to add.
462178825Sdfr *
463178825Sdfr * @return Returns an hx509 error code.
464178825Sdfr *
465178825Sdfr * @ingroup hx509_keyset
466178825Sdfr */
467178825Sdfr
468178825Sdfrint
469178825Sdfrhx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
470178825Sdfr{
471178825Sdfr    if (certs->ops->add == NULL) {
472233294Sstas	hx509_set_error_string(context, 0, ENOENT,
473233294Sstas			       "Keyset type %s doesn't support add operation",
474178825Sdfr			       certs->ops->name);
475178825Sdfr	return ENOENT;
476178825Sdfr    }
477178825Sdfr
478178825Sdfr    return (*certs->ops->add)(context, certs, certs->ops_data, cert);
479178825Sdfr}
480178825Sdfr
481178825Sdfr/**
482178825Sdfr * Find a certificate matching the query.
483178825Sdfr *
484178825Sdfr * @param context a hx509 context.
485178825Sdfr * @param certs certificate store to search.
486178825Sdfr * @param q query allocated with @ref hx509_query functions.
487178825Sdfr * @param r return certificate (or NULL on error), should be freed
488178825Sdfr * with hx509_cert_free().
489178825Sdfr *
490178825Sdfr * @return Returns an hx509 error code.
491178825Sdfr *
492178825Sdfr * @ingroup hx509_keyset
493178825Sdfr */
494178825Sdfr
495178825Sdfrint
496178825Sdfrhx509_certs_find(hx509_context context,
497233294Sstas		 hx509_certs certs,
498178825Sdfr		 const hx509_query *q,
499178825Sdfr		 hx509_cert *r)
500178825Sdfr{
501178825Sdfr    hx509_cursor cursor;
502178825Sdfr    hx509_cert c;
503178825Sdfr    int ret;
504178825Sdfr
505178825Sdfr    *r = NULL;
506178825Sdfr
507178825Sdfr    _hx509_query_statistic(context, 0, q);
508178825Sdfr
509178825Sdfr    if (certs->ops->query)
510178825Sdfr	return (*certs->ops->query)(context, certs, certs->ops_data, q, r);
511178825Sdfr
512178825Sdfr    ret = hx509_certs_start_seq(context, certs, &cursor);
513178825Sdfr    if (ret)
514178825Sdfr	return ret;
515178825Sdfr
516178825Sdfr    c = NULL;
517178825Sdfr    while (1) {
518178825Sdfr	ret = hx509_certs_next_cert(context, certs, cursor, &c);
519178825Sdfr	if (ret)
520178825Sdfr	    break;
521178825Sdfr	if (c == NULL)
522178825Sdfr	    break;
523178825Sdfr	if (_hx509_query_match_cert(context, q, c)) {
524178825Sdfr	    *r = c;
525178825Sdfr	    break;
526178825Sdfr	}
527178825Sdfr	hx509_cert_free(c);
528178825Sdfr    }
529178825Sdfr
530178825Sdfr    hx509_certs_end_seq(context, certs, cursor);
531178825Sdfr    if (ret)
532178825Sdfr	return ret;
533233294Sstas    /**
534233294Sstas     * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
535233294Sstas     * the query.
536233294Sstas     */
537178825Sdfr    if (c == NULL) {
538178825Sdfr	hx509_clear_error_string(context);
539178825Sdfr	return HX509_CERT_NOT_FOUND;
540178825Sdfr    }
541178825Sdfr
542178825Sdfr    return 0;
543178825Sdfr}
544178825Sdfr
545233294Sstas/**
546233294Sstas * Filter certificate matching the query.
547233294Sstas *
548233294Sstas * @param context a hx509 context.
549233294Sstas * @param certs certificate store to search.
550233294Sstas * @param q query allocated with @ref hx509_query functions.
551233294Sstas * @param result the filtered certificate store, caller must free with
552233294Sstas *        hx509_certs_free().
553233294Sstas *
554233294Sstas * @return Returns an hx509 error code.
555233294Sstas *
556233294Sstas * @ingroup hx509_keyset
557233294Sstas */
558233294Sstas
559233294Sstasint
560233294Sstashx509_certs_filter(hx509_context context,
561233294Sstas		   hx509_certs certs,
562233294Sstas		   const hx509_query *q,
563233294Sstas		   hx509_certs *result)
564233294Sstas{
565233294Sstas    hx509_cursor cursor;
566233294Sstas    hx509_cert c;
567233294Sstas    int ret, found = 0;
568233294Sstas
569233294Sstas    _hx509_query_statistic(context, 0, q);
570233294Sstas
571233294Sstas    ret = hx509_certs_init(context, "MEMORY:filter-certs", 0,
572233294Sstas			   NULL, result);
573233294Sstas    if (ret)
574233294Sstas	return ret;
575233294Sstas
576233294Sstas    ret = hx509_certs_start_seq(context, certs, &cursor);
577233294Sstas    if (ret) {
578233294Sstas	hx509_certs_free(result);
579233294Sstas	return ret;
580233294Sstas    }
581233294Sstas
582233294Sstas    c = NULL;
583233294Sstas    while (1) {
584233294Sstas	ret = hx509_certs_next_cert(context, certs, cursor, &c);
585233294Sstas	if (ret)
586233294Sstas	    break;
587233294Sstas	if (c == NULL)
588233294Sstas	    break;
589233294Sstas	if (_hx509_query_match_cert(context, q, c)) {
590233294Sstas	    hx509_certs_add(context, *result, c);
591233294Sstas	    found = 1;
592233294Sstas	}
593233294Sstas	hx509_cert_free(c);
594233294Sstas    }
595233294Sstas
596233294Sstas    hx509_certs_end_seq(context, certs, cursor);
597233294Sstas    if (ret) {
598233294Sstas	hx509_certs_free(result);
599233294Sstas	return ret;
600233294Sstas    }
601233294Sstas
602233294Sstas    /**
603233294Sstas     * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
604233294Sstas     * the query.
605233294Sstas     */
606233294Sstas    if (!found) {
607233294Sstas	hx509_certs_free(result);
608233294Sstas	hx509_clear_error_string(context);
609233294Sstas	return HX509_CERT_NOT_FOUND;
610233294Sstas    }
611233294Sstas
612233294Sstas    return 0;
613233294Sstas}
614233294Sstas
615233294Sstas
616178825Sdfrstatic int
617178825Sdfrcerts_merge_func(hx509_context context, void *ctx, hx509_cert c)
618178825Sdfr{
619178825Sdfr    return hx509_certs_add(context, (hx509_certs)ctx, c);
620178825Sdfr}
621178825Sdfr
622178825Sdfr/**
623178825Sdfr * Merge a certificate store into another. The from store is keep
624178825Sdfr * intact.
625178825Sdfr *
626178825Sdfr * @param context a hx509 context.
627178825Sdfr * @param to the store to merge into.
628178825Sdfr * @param from the store to copy the object from.
629178825Sdfr *
630178825Sdfr * @return Returns an hx509 error code.
631178825Sdfr *
632178825Sdfr * @ingroup hx509_keyset
633178825Sdfr */
634178825Sdfr
635178825Sdfrint
636178825Sdfrhx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
637178825Sdfr{
638178825Sdfr    if (from == NULL)
639178825Sdfr	return 0;
640233294Sstas    return hx509_certs_iter_f(context, from, certs_merge_func, to);
641178825Sdfr}
642178825Sdfr
643178825Sdfr/**
644178825Sdfr * Same a hx509_certs_merge() but use a lock and name to describe the
645178825Sdfr * from source.
646178825Sdfr *
647178825Sdfr * @param context a hx509 context.
648178825Sdfr * @param to the store to merge into.
649178825Sdfr * @param lock a lock that unlocks the certificates store, use NULL to
650178825Sdfr * select no password/certifictes/prompt lock (see @ref page_lock).
651178825Sdfr * @param name name of the source store
652178825Sdfr *
653178825Sdfr * @return Returns an hx509 error code.
654178825Sdfr *
655178825Sdfr * @ingroup hx509_keyset
656178825Sdfr */
657178825Sdfr
658178825Sdfrint
659178825Sdfrhx509_certs_append(hx509_context context,
660178825Sdfr		   hx509_certs to,
661178825Sdfr		   hx509_lock lock,
662178825Sdfr		   const char *name)
663178825Sdfr{
664178825Sdfr    hx509_certs s;
665178825Sdfr    int ret;
666178825Sdfr
667178825Sdfr    ret = hx509_certs_init(context, name, 0, lock, &s);
668178825Sdfr    if (ret)
669178825Sdfr	return ret;
670178825Sdfr    ret = hx509_certs_merge(context, to, s);
671178825Sdfr    hx509_certs_free(&s);
672178825Sdfr    return ret;
673178825Sdfr}
674178825Sdfr
675178825Sdfr/**
676178825Sdfr * Get one random certificate from the certificate store.
677178825Sdfr *
678178825Sdfr * @param context a hx509 context.
679178825Sdfr * @param certs a certificate store to get the certificate from.
680178825Sdfr * @param c return certificate, should be freed with hx509_cert_free().
681178825Sdfr *
682178825Sdfr * @return Returns an hx509 error code.
683178825Sdfr *
684178825Sdfr * @ingroup hx509_keyset
685178825Sdfr */
686178825Sdfr
687178825Sdfrint
688178825Sdfrhx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
689178825Sdfr{
690178825Sdfr    hx509_cursor cursor;
691178825Sdfr    int ret;
692178825Sdfr
693178825Sdfr    *c = NULL;
694178825Sdfr
695178825Sdfr    ret = hx509_certs_start_seq(context, certs, &cursor);
696178825Sdfr    if (ret)
697178825Sdfr	return ret;
698178825Sdfr
699178825Sdfr    ret = hx509_certs_next_cert(context, certs, cursor, c);
700178825Sdfr    if (ret)
701178825Sdfr	return ret;
702178825Sdfr
703178825Sdfr    hx509_certs_end_seq(context, certs, cursor);
704178825Sdfr    return 0;
705178825Sdfr}
706178825Sdfr
707178825Sdfrstatic int
708178825Sdfrcerts_info_stdio(void *ctx, const char *str)
709178825Sdfr{
710178825Sdfr    FILE *f = ctx;
711178825Sdfr    fprintf(f, "%s\n", str);
712178825Sdfr    return 0;
713178825Sdfr}
714178825Sdfr
715178825Sdfr/**
716178825Sdfr * Print some info about the certificate store.
717178825Sdfr *
718178825Sdfr * @param context a hx509 context.
719178825Sdfr * @param certs certificate store to print information about.
720178825Sdfr * @param func function that will get each line of the information, if
721178825Sdfr * NULL is used the data is printed on a FILE descriptor that should
722178825Sdfr * be passed in ctx, if ctx also is NULL, stdout is used.
723178825Sdfr * @param ctx parameter to func.
724178825Sdfr *
725178825Sdfr * @return Returns an hx509 error code.
726178825Sdfr *
727178825Sdfr * @ingroup hx509_keyset
728178825Sdfr */
729178825Sdfr
730178825Sdfrint
731233294Sstashx509_certs_info(hx509_context context,
732178825Sdfr		 hx509_certs certs,
733178825Sdfr		 int (*func)(void *, const char *),
734178825Sdfr		 void *ctx)
735178825Sdfr{
736178825Sdfr    if (func == NULL) {
737178825Sdfr	func = certs_info_stdio;
738178825Sdfr	if (ctx == NULL)
739178825Sdfr	    ctx = stdout;
740178825Sdfr    }
741178825Sdfr    if (certs->ops->printinfo == NULL) {
742178825Sdfr	(*func)(ctx, "No info function for certs");
743178825Sdfr	return 0;
744178825Sdfr    }
745178825Sdfr    return (*certs->ops->printinfo)(context, certs, certs->ops_data,
746178825Sdfr				    func, ctx);
747178825Sdfr}
748178825Sdfr
749178825Sdfrvoid
750178825Sdfr_hx509_pi_printf(int (*func)(void *, const char *), void *ctx,
751178825Sdfr		 const char *fmt, ...)
752178825Sdfr{
753178825Sdfr    va_list ap;
754178825Sdfr    char *str;
755178825Sdfr
756178825Sdfr    va_start(ap, fmt);
757178825Sdfr    vasprintf(&str, fmt, ap);
758178825Sdfr    va_end(ap);
759178825Sdfr    if (str == NULL)
760178825Sdfr	return;
761178825Sdfr    (*func)(ctx, str);
762178825Sdfr    free(str);
763178825Sdfr}
764178825Sdfr
765178825Sdfrint
766233294Sstas_hx509_certs_keys_get(hx509_context context,
767233294Sstas		      hx509_certs certs,
768178825Sdfr		      hx509_private_key **keys)
769178825Sdfr{
770178825Sdfr    if (certs->ops->getkeys == NULL) {
771178825Sdfr	*keys = NULL;
772178825Sdfr	return 0;
773178825Sdfr    }
774178825Sdfr    return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys);
775178825Sdfr}
776178825Sdfr
777178825Sdfrint
778233294Sstas_hx509_certs_keys_add(hx509_context context,
779233294Sstas		      hx509_certs certs,
780178825Sdfr		      hx509_private_key key)
781178825Sdfr{
782178825Sdfr    if (certs->ops->addkey == NULL) {
783178825Sdfr	hx509_set_error_string(context, 0, EINVAL,
784178825Sdfr			       "keystore if type %s doesn't support "
785178825Sdfr			       "key add operation",
786178825Sdfr			       certs->ops->name);
787178825Sdfr	return EINVAL;
788178825Sdfr    }
789178825Sdfr    return (*certs->ops->addkey)(context, certs, certs->ops_data, key);
790178825Sdfr}
791178825Sdfr
792178825Sdfr
793178825Sdfrvoid
794178825Sdfr_hx509_certs_keys_free(hx509_context context,
795178825Sdfr		       hx509_private_key *keys)
796178825Sdfr{
797178825Sdfr    int i;
798178825Sdfr    for (i = 0; keys[i]; i++)
799233294Sstas	hx509_private_key_free(&keys[i]);
800178825Sdfr    free(keys);
801178825Sdfr}
802