keyset.c revision 256281
190075Sobrien/*
290075Sobrien * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan
3169689Skan * (Royal Institute of Technology, Stockholm, Sweden).
490075Sobrien * All rights reserved.
590075Sobrien *
690075Sobrien * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
790075Sobrien *
890075Sobrien * Redistribution and use in source and binary forms, with or without
990075Sobrien * modification, are permitted provided that the following conditions
1090075Sobrien * are met:
1190075Sobrien *
1290075Sobrien * 1. Redistributions of source code must retain the above copyright
1390075Sobrien *    notice, this list of conditions and the following disclaimer.
1490075Sobrien *
1590075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1690075Sobrien *    notice, this list of conditions and the following disclaimer in the
1790075Sobrien *    documentation and/or other materials provided with the distribution.
1890075Sobrien *
19169689Skan * 3. Neither the name of the Institute nor the names of its contributors
20169689Skan *    may be used to endorse or promote products derived from this software
2190075Sobrien *    without specific prior written permission.
2290075Sobrien *
2390075Sobrien * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2490075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2590075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2690075Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2790075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2890075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2990075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3090075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3290075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3390075Sobrien * SUCH DAMAGE.
3490075Sobrien */
35132718Skan
36132718Skan#include "hx_locl.h"
3790075Sobrien
3890075Sobrien/**
3990075Sobrien * @page page_keyset Certificate store operations
4090075Sobrien *
4190075Sobrien * Type of certificates store:
4290075Sobrien * - MEMORY
4390075Sobrien *   In memory based format. Doesnt support storing.
4490075Sobrien * - FILE
4590075Sobrien *   FILE supports raw DER certicates and PEM certicates. When PEM is
4690075Sobrien *   used the file can contain may certificates and match private
4790075Sobrien *   keys. Support storing the certificates. DER format only supports
4890075Sobrien *   on certificate and no private key.
49132718Skan * - PEM-FILE
50132718Skan *   Same as FILE, defaulting to PEM encoded certificates.
51169689Skan * - PEM-FILE
52169689Skan *   Same as FILE, defaulting to DER encoded certificates.
53132718Skan * - PKCS11
54132718Skan * - PKCS12
5590075Sobrien * - DIR
5690075Sobrien * - KEYCHAIN
5790075Sobrien *   Apple Mac OS X KeyChain backed keychain object.
5890075Sobrien *
59132718Skan * See the library functions here: @ref hx509_keyset
60132718Skan */
6190075Sobrien
6290075Sobrienstruct hx509_certs_data {
6390075Sobrien    unsigned int ref;
6490075Sobrien    struct hx509_keyset_ops *ops;
6590075Sobrien    void *ops_data;
6690075Sobrien};
67169689Skan
6890075Sobrienstatic struct hx509_keyset_ops *
6990075Sobrien_hx509_ks_type(hx509_context context, const char *type)
7090075Sobrien{
7190075Sobrien    int i;
7290075Sobrien
7390075Sobrien    for (i = 0; i < context->ks_num_ops; i++)
7490075Sobrien	if (strcasecmp(type, context->ks_ops[i]->name) == 0)
7590075Sobrien	    return context->ks_ops[i];
7690075Sobrien
7790075Sobrien    return NULL;
7890075Sobrien}
7990075Sobrien
8090075Sobrienvoid
8190075Sobrien_hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
8290075Sobrien{
8390075Sobrien    struct hx509_keyset_ops **val;
84169689Skan
8590075Sobrien    if (_hx509_ks_type(context, ops->name))
8690075Sobrien	return;
8790075Sobrien
8890075Sobrien    val = realloc(context->ks_ops,
8990075Sobrien		  (context->ks_num_ops + 1) * sizeof(context->ks_ops[0]));
9090075Sobrien    if (val == NULL)
91110611Skan	return;
92132718Skan    val[context->ks_num_ops] = ops;
9390075Sobrien    context->ks_ops = val;
9490075Sobrien    context->ks_num_ops++;
9590075Sobrien}
9690075Sobrien
9790075Sobrien/**
98117395Skan * Open or creates a new hx509 certificate store.
99117395Skan *
100117395Skan * @param context A hx509 context
10190075Sobrien * @param name name of the store, format is TYPE:type-specific-string,
102117395Skan * if NULL is used the MEMORY store is used.
103117395Skan * @param flags list of flags:
104117395Skan * - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
105117395Skan * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
10690075Sobrien * @param lock a lock that unlocks the certificates store, use NULL to
107117395Skan * select no password/certifictes/prompt lock (see @ref page_lock).
108169689Skan * @param certs return pointer, free with hx509_certs_free().
109169689Skan *
110169689Skan * @ingroup hx509_keyset
111169689Skan */
112169689Skan
113169689Skanint
114117395Skanhx509_certs_init(hx509_context context,
115117395Skan		 const char *name, int flags,
116117395Skan		 hx509_lock lock, hx509_certs *certs)
117117395Skan{
118117395Skan    struct hx509_keyset_ops *ops;
119117395Skan    const char *residue;
120117395Skan    hx509_certs c;
12190075Sobrien    char *type;
122117395Skan    int ret;
123169689Skan
124169689Skan    *certs = NULL;
125169689Skan
126169689Skan    residue = strchr(name, ':');
127169689Skan    if (residue) {
128117395Skan	type = malloc(residue - name + 1);
12990075Sobrien	if (type)
130117395Skan	    strlcpy(type, name, residue - name + 1);
131132718Skan	residue++;
132169689Skan	if (residue[0] == '\0')
133169689Skan	    residue = NULL;
134117395Skan    } else {
13590075Sobrien	type = strdup("MEMORY");
136117395Skan	residue = name;
137169689Skan    }
13890075Sobrien    if (type == NULL) {
13990075Sobrien	hx509_clear_error_string(context);
14090075Sobrien	return ENOMEM;
14190075Sobrien    }
14290075Sobrien
14390075Sobrien    ops = _hx509_ks_type(context, type);
144132718Skan    if (ops == NULL) {
14590075Sobrien	hx509_set_error_string(context, 0, ENOENT,
146169689Skan			       "Keyset type %s is not supported", type);
14790075Sobrien	free(type);
14890075Sobrien	return ENOENT;
14990075Sobrien    }
15090075Sobrien    free(type);
15190075Sobrien    c = calloc(1, sizeof(*c));
152132718Skan    if (c == NULL) {
153169689Skan	hx509_clear_error_string(context);
154169689Skan	return ENOMEM;
15590075Sobrien    }
15690075Sobrien    c->ops = ops;
15790075Sobrien    c->ref = 1;
15890075Sobrien
15990075Sobrien    ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
16090075Sobrien    if (ret) {
16190075Sobrien	free(c);
16290075Sobrien	return ret;
16390075Sobrien    }
16490075Sobrien
16590075Sobrien    *certs = c;
16690075Sobrien    return 0;
16790075Sobrien}
16890075Sobrien
16990075Sobrien/**
17090075Sobrien * Write the certificate store to stable storage.
17190075Sobrien *
172169689Skan * @param context A hx509 context.
17390075Sobrien * @param certs a certificate store to store.
17490075Sobrien * @param flags currently unused, use 0.
175169689Skan * @param lock a lock that unlocks the certificates store, use NULL to
17690075Sobrien * select no password/certifictes/prompt lock (see @ref page_lock).
17790075Sobrien *
17890075Sobrien * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
17990075Sobrien * the certificate store doesn't support the store operation.
18090075Sobrien *
18190075Sobrien * @ingroup hx509_keyset
18290075Sobrien */
18390075Sobrien
18490075Sobrienint
18590075Sobrienhx509_certs_store(hx509_context context,
18690075Sobrien		  hx509_certs certs,
187169689Skan		  int flags,
18890075Sobrien		  hx509_lock lock)
189169689Skan{
19090075Sobrien    if (certs->ops->store == NULL) {
19190075Sobrien	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
19290075Sobrien			       "keystore if type %s doesn't support "
19390075Sobrien			       "store operation",
19490075Sobrien			       certs->ops->name);
19590075Sobrien	return HX509_UNSUPPORTED_OPERATION;
19690075Sobrien    }
19790075Sobrien
19890075Sobrien    return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
19990075Sobrien}
20090075Sobrien
20190075Sobrien
20290075Sobrienhx509_certs
20390075Sobrienhx509_certs_ref(hx509_certs certs)
204169689Skan{
205169689Skan    if (certs == NULL)
20690075Sobrien	return NULL;
207169689Skan    if (certs->ref == 0)
20890075Sobrien	_hx509_abort("certs refcount == 0 on ref");
20990075Sobrien    if (certs->ref == UINT_MAX)
21090075Sobrien	_hx509_abort("certs refcount == UINT_MAX on ref");
21190075Sobrien    certs->ref++;
21290075Sobrien    return certs;
21390075Sobrien}
21490075Sobrien
21590075Sobrien/**
21690075Sobrien * Free a certificate store.
21790075Sobrien *
21890075Sobrien * @param certs certificate store to free.
219169689Skan *
220169689Skan * @ingroup hx509_keyset
221169689Skan */
222169689Skan
223169689Skanvoid
224169689Skanhx509_certs_free(hx509_certs *certs)
22590075Sobrien{
226169689Skan    if (*certs) {
227169689Skan	if ((*certs)->ref == 0)
228169689Skan	    _hx509_abort("cert refcount == 0 on free");
229169689Skan	if (--(*certs)->ref > 0)
23090075Sobrien	    return;
231169689Skan
232169689Skan	(*(*certs)->ops->free)(*certs, (*certs)->ops_data);
233169689Skan	free(*certs);
234169689Skan	*certs = NULL;
235169689Skan    }
23690075Sobrien}
237169689Skan
238169689Skan/**
239169689Skan * Start the integration
240169689Skan *
241169689Skan * @param context a hx509 context.
242169689Skan * @param certs certificate store to iterate over
243169689Skan * @param cursor cursor that will keep track of progress, free with
244169689Skan * hx509_certs_end_seq().
245169689Skan *
246169689Skan * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is
247169689Skan * returned if the certificate store doesn't support the iteration
248169689Skan * operation.
249169689Skan *
250169689Skan * @ingroup hx509_keyset
25190075Sobrien */
252169689Skan
25390075Sobrienint
254117395Skanhx509_certs_start_seq(hx509_context context,
255169689Skan		      hx509_certs certs,
25690075Sobrien		      hx509_cursor *cursor)
25790075Sobrien{
25890075Sobrien    int ret;
25990075Sobrien
260169689Skan    if (certs->ops->iter_start == NULL) {
261169689Skan	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
26290075Sobrien			       "Keyset type %s doesn't support iteration",
263117395Skan			       certs->ops->name);
264117395Skan	return HX509_UNSUPPORTED_OPERATION;
265117395Skan    }
266169689Skan
26790075Sobrien    ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
268117395Skan    if (ret)
26990075Sobrien	return ret;
27090075Sobrien
27190075Sobrien    return 0;
272169689Skan}
273169689Skan
27490075Sobrien/**
275169689Skan * Get next ceritificate from the certificate keystore pointed out by
276169689Skan * cursor.
277169689Skan *
278169689Skan * @param context a hx509 context.
279169689Skan * @param certs certificate store to iterate over.
280169689Skan * @param cursor cursor that keeps track of progress.
281169689Skan * @param cert return certificate next in store, NULL if the store
282169689Skan * contains no more certificates. Free with hx509_cert_free().
283169689Skan *
284169689Skan * @return Returns an hx509 error code.
285169689Skan *
286169689Skan * @ingroup hx509_keyset
287169689Skan */
288169689Skan
289169689Skanint
290169689Skanhx509_certs_next_cert(hx509_context context,
291132718Skan		      hx509_certs certs,
29290075Sobrien		      hx509_cursor cursor,
29390075Sobrien		      hx509_cert *cert)
29490075Sobrien{
29590075Sobrien    *cert = NULL;
29690075Sobrien    return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
297132718Skan}
29890075Sobrien
29990075Sobrien/**
30090075Sobrien * End the iteration over certificates.
30190075Sobrien *
30290075Sobrien * @param context a hx509 context.
30390075Sobrien * @param certs certificate store to iterate over.
30490075Sobrien * @param cursor cursor that will keep track of progress, freed.
30590075Sobrien *
30690075Sobrien * @return Returns an hx509 error code.
307169689Skan *
30890075Sobrien * @ingroup hx509_keyset
30990075Sobrien */
31090075Sobrien
31190075Sobrienint
31290075Sobrienhx509_certs_end_seq(hx509_context context,
31390075Sobrien		    hx509_certs certs,
314132718Skan		    hx509_cursor cursor)
315132718Skan{
31690075Sobrien    (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor);
31790075Sobrien    return 0;
31890075Sobrien}
31990075Sobrien
32090075Sobrien/**
32190075Sobrien * Iterate over all certificates in a keystore and call an function
32290075Sobrien * for each fo them.
32390075Sobrien *
32490075Sobrien * @param context a hx509 context.
32590075Sobrien * @param certs certificate store to iterate over.
32690075Sobrien * @param func function to call for each certificate. The function
32790075Sobrien * should return non-zero to abort the iteration, that value is passed
32890075Sobrien * back to the caller of hx509_certs_iter_f().
32990075Sobrien * @param ctx context variable that will passed to the function.
33090075Sobrien *
33190075Sobrien * @return Returns an hx509 error code.
33290075Sobrien *
33390075Sobrien * @ingroup hx509_keyset
33490075Sobrien */
33590075Sobrien
33690075Sobrienint
33790075Sobrienhx509_certs_iter_f(hx509_context context,
33890075Sobrien		   hx509_certs certs,
33990075Sobrien		   int (*func)(hx509_context, void *, hx509_cert),
34090075Sobrien		   void *ctx)
341169689Skan{
34290075Sobrien    hx509_cursor cursor;
34390075Sobrien    hx509_cert c;
34490075Sobrien    int ret;
34590075Sobrien
34690075Sobrien    ret = hx509_certs_start_seq(context, certs, &cursor);
34790075Sobrien    if (ret)
34890075Sobrien	return ret;
34990075Sobrien
35090075Sobrien    while (1) {
35190075Sobrien	ret = hx509_certs_next_cert(context, certs, cursor, &c);
35290075Sobrien	if (ret)
35390075Sobrien	    break;
35490075Sobrien	if (c == NULL) {
355169689Skan	    ret = 0;
35690075Sobrien	    break;
35790075Sobrien	}
35890075Sobrien	ret = (*func)(context, ctx, c);
35990075Sobrien	hx509_cert_free(c);
36090075Sobrien	if (ret)
36190075Sobrien	    break;
36290075Sobrien    }
36390075Sobrien
36490075Sobrien    hx509_certs_end_seq(context, certs, cursor);
36590075Sobrien
366132718Skan    return ret;
36790075Sobrien}
36890075Sobrien
36990075Sobrien/**
37090075Sobrien * Iterate over all certificates in a keystore and call an function
37190075Sobrien * for each fo them.
37290075Sobrien *
37390075Sobrien * @param context a hx509 context.
37490075Sobrien * @param certs certificate store to iterate over.
375169689Skan * @param func function to call for each certificate. The function
37690075Sobrien * should return non-zero to abort the iteration, that value is passed
37790075Sobrien * back to the caller of hx509_certs_iter().
37890075Sobrien *
37990075Sobrien * @return Returns an hx509 error code.
38090075Sobrien *
38190075Sobrien * @ingroup hx509_keyset
38290075Sobrien */
38390075Sobrien
38490075Sobrien#ifdef __BLOCKS__
38590075Sobrien
38690075Sobrienstatic int
38790075Sobriencerts_iter(hx509_context context, void *ctx, hx509_cert cert)
38890075Sobrien{
38990075Sobrien    int (^func)(hx509_cert) = ctx;
39090075Sobrien    return func(cert);
39190075Sobrien}
39290075Sobrien
39390075Sobrien/**
39490075Sobrien * Iterate over all certificates in a keystore and call an block
39590075Sobrien * for each fo them.
39690075Sobrien *
39790075Sobrien * @param context a hx509 context.
398132718Skan * @param certs certificate store to iterate over.
399169689Skan * @param func block to call for each certificate. The function
400169689Skan * should return non-zero to abort the iteration, that value is passed
401169689Skan * back to the caller of hx509_certs_iter().
402169689Skan *
403132718Skan * @return Returns an hx509 error code.
404169689Skan *
405132718Skan * @ingroup hx509_keyset
406132718Skan */
407132718Skan
408169689Skanint
40990075Sobrienhx509_certs_iter(hx509_context context,
410117395Skan		 hx509_certs certs,
41190075Sobrien		 int (^func)(hx509_cert))
412169689Skan{
413117395Skan    return hx509_certs_iter_f(context, certs, certs_iter, func);
41490075Sobrien}
41590075Sobrien#endif
41690075Sobrien
41790075Sobrien
41890075Sobrien/**
41990075Sobrien * Function to use to hx509_certs_iter_f() as a function argument, the
42090075Sobrien * ctx variable to hx509_certs_iter_f() should be a FILE file descriptor.
42190075Sobrien *
42290075Sobrien * @param context a hx509 context.
42390075Sobrien * @param ctx used by hx509_certs_iter_f().
42490075Sobrien * @param c a certificate
42590075Sobrien *
42690075Sobrien * @return Returns an hx509 error code.
427132718Skan *
42890075Sobrien * @ingroup hx509_keyset
42990075Sobrien */
43090075Sobrien
43190075Sobrienint
43290075Sobrienhx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
433117395Skan{
43490075Sobrien    Certificate *cert;
43590075Sobrien    hx509_name n;
43690075Sobrien    char *s, *i;
43790075Sobrien
43890075Sobrien    cert = _hx509_get_cert(c);
43990075Sobrien
44090075Sobrien    _hx509_name_from_Name(&cert->tbsCertificate.subject, &n);
44190075Sobrien    hx509_name_to_string(n, &s);
44290075Sobrien    hx509_name_free(&n);
44390075Sobrien    _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n);
44490075Sobrien    hx509_name_to_string(n, &i);
44590075Sobrien    hx509_name_free(&n);
44690075Sobrien    fprintf(ctx, "subject: %s\nissuer: %s\n", s, i);
447169689Skan    free(s);
44890075Sobrien    free(i);
44990075Sobrien    return 0;
450117395Skan}
45190075Sobrien
45290075Sobrien/**
45390075Sobrien * Add a certificate to the certificiate store.
45490075Sobrien *
45590075Sobrien * The receiving keyset certs will either increase reference counter
45690075Sobrien * of the cert or make a deep copy, either way, the caller needs to
45790075Sobrien * free the cert itself.
45890075Sobrien *
45990075Sobrien * @param context a hx509 context.
46090075Sobrien * @param certs certificate store to add the certificate to.
46190075Sobrien * @param cert certificate to add.
46290075Sobrien *
46390075Sobrien * @return Returns an hx509 error code.
464117395Skan *
46590075Sobrien * @ingroup hx509_keyset
46690075Sobrien */
46790075Sobrien
46890075Sobrienint
46990075Sobrienhx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
47090075Sobrien{
47190075Sobrien    if (certs->ops->add == NULL) {
47290075Sobrien	hx509_set_error_string(context, 0, ENOENT,
47390075Sobrien			       "Keyset type %s doesn't support add operation",
47490075Sobrien			       certs->ops->name);
47590075Sobrien	return ENOENT;
47690075Sobrien    }
47790075Sobrien
47890075Sobrien    return (*certs->ops->add)(context, certs, certs->ops_data, cert);
47990075Sobrien}
48090075Sobrien
48190075Sobrien/**
48290075Sobrien * Find a certificate matching the query.
48390075Sobrien *
48490075Sobrien * @param context a hx509 context.
48590075Sobrien * @param certs certificate store to search.
48690075Sobrien * @param q query allocated with @ref hx509_query functions.
48790075Sobrien * @param r return certificate (or NULL on error), should be freed
48890075Sobrien * with hx509_cert_free().
48990075Sobrien *
49090075Sobrien * @return Returns an hx509 error code.
491169689Skan *
49290075Sobrien * @ingroup hx509_keyset
49390075Sobrien */
49490075Sobrien
49590075Sobrienint
49690075Sobrienhx509_certs_find(hx509_context context,
497169689Skan		 hx509_certs certs,
49890075Sobrien		 const hx509_query *q,
49990075Sobrien		 hx509_cert *r)
50090075Sobrien{
50190075Sobrien    hx509_cursor cursor;
502117395Skan    hx509_cert c;
50390075Sobrien    int ret;
50490075Sobrien
50590075Sobrien    *r = NULL;
506169689Skan
50790075Sobrien    _hx509_query_statistic(context, 0, q);
508117395Skan
50990075Sobrien    if (certs->ops->query)
51090075Sobrien	return (*certs->ops->query)(context, certs, certs->ops_data, q, r);
51190075Sobrien
51290075Sobrien    ret = hx509_certs_start_seq(context, certs, &cursor);
513169689Skan    if (ret)
51490075Sobrien	return ret;
51590075Sobrien
516169689Skan    c = NULL;
51790075Sobrien    while (1) {
518117395Skan	ret = hx509_certs_next_cert(context, certs, cursor, &c);
519117395Skan	if (ret)
52090075Sobrien	    break;
52190075Sobrien	if (c == NULL)
52290075Sobrien	    break;
52390075Sobrien	if (_hx509_query_match_cert(context, q, c)) {
52490075Sobrien	    *r = c;
52590075Sobrien	    break;
52690075Sobrien	}
52790075Sobrien	hx509_cert_free(c);
52890075Sobrien    }
52990075Sobrien
530117395Skan    hx509_certs_end_seq(context, certs, cursor);
531132718Skan    if (ret)
53290075Sobrien	return ret;
533169689Skan    /**
53490075Sobrien     * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
53590075Sobrien     * the query.
53690075Sobrien     */
537169689Skan    if (c == NULL) {
538117395Skan	hx509_clear_error_string(context);
539117395Skan	return HX509_CERT_NOT_FOUND;
54090075Sobrien    }
541169689Skan
54290075Sobrien    return 0;
54390075Sobrien}
54490075Sobrien
54590075Sobrien/**
54690075Sobrien * Filter certificate matching the query.
54790075Sobrien *
54890075Sobrien * @param context a hx509 context.
54990075Sobrien * @param certs certificate store to search.
550169689Skan * @param q query allocated with @ref hx509_query functions.
551169689Skan * @param result the filtered certificate store, caller must free with
552169689Skan *        hx509_certs_free().
553169689Skan *
554169689Skan * @return Returns an hx509 error code.
555169689Skan *
55690075Sobrien * @ingroup hx509_keyset
55790075Sobrien */
55890075Sobrien
559169689Skanint
560169689Skanhx509_certs_filter(hx509_context context,
561169689Skan		   hx509_certs certs,
562169689Skan		   const hx509_query *q,
563169689Skan		   hx509_certs *result)
564169689Skan{
56590075Sobrien    hx509_cursor cursor;
566169689Skan    hx509_cert c;
56790075Sobrien    int ret, found = 0;
56890075Sobrien
56990075Sobrien    _hx509_query_statistic(context, 0, q);
57090075Sobrien
57190075Sobrien    ret = hx509_certs_init(context, "MEMORY:filter-certs", 0,
57290075Sobrien			   NULL, result);
57390075Sobrien    if (ret)
57490075Sobrien	return ret;
57590075Sobrien
57690075Sobrien    ret = hx509_certs_start_seq(context, certs, &cursor);
57790075Sobrien    if (ret) {
578169689Skan	hx509_certs_free(result);
579169689Skan	return ret;
580169689Skan    }
581169689Skan
58290075Sobrien    c = NULL;
583169689Skan    while (1) {
584169689Skan	ret = hx509_certs_next_cert(context, certs, cursor, &c);
585169689Skan	if (ret)
586169689Skan	    break;
587169689Skan	if (c == NULL)
588169689Skan	    break;
589169689Skan	if (_hx509_query_match_cert(context, q, c)) {
59090075Sobrien	    hx509_certs_add(context, *result, c);
591169689Skan	    found = 1;
592169689Skan	}
593169689Skan	hx509_cert_free(c);
594169689Skan    }
595169689Skan
596169689Skan    hx509_certs_end_seq(context, certs, cursor);
597169689Skan    if (ret) {
598169689Skan	hx509_certs_free(result);
599169689Skan	return ret;
600169689Skan    }
601169689Skan
602169689Skan    /**
603169689Skan     * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
604169689Skan     * the query.
605169689Skan     */
606169689Skan    if (!found) {
607169689Skan	hx509_certs_free(result);
608169689Skan	hx509_clear_error_string(context);
609169689Skan	return HX509_CERT_NOT_FOUND;
610169689Skan    }
611169689Skan
612169689Skan    return 0;
613169689Skan}
614169689Skan
615169689Skan
616169689Skanstatic int
617169689Skancerts_merge_func(hx509_context context, void *ctx, hx509_cert c)
618169689Skan{
619169689Skan    return hx509_certs_add(context, (hx509_certs)ctx, c);
620169689Skan}
621169689Skan
622169689Skan/**
623169689Skan * Merge a certificate store into another. The from store is keep
624169689Skan * intact.
625169689Skan *
626169689Skan * @param context a hx509 context.
627169689Skan * @param to the store to merge into.
628169689Skan * @param from the store to copy the object from.
629169689Skan *
630169689Skan * @return Returns an hx509 error code.
63190075Sobrien *
63290075Sobrien * @ingroup hx509_keyset
63390075Sobrien */
63490075Sobrien
635132718Skanint
63690075Sobrienhx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
637169689Skan{
638132718Skan    if (from == NULL)
639132718Skan	return 0;
640169689Skan    return hx509_certs_iter_f(context, from, certs_merge_func, to);
64190075Sobrien}
64290075Sobrien
64390075Sobrien/**
644132718Skan * Same a hx509_certs_merge() but use a lock and name to describe the
64590075Sobrien * from source.
64690075Sobrien *
647169689Skan * @param context a hx509 context.
64890075Sobrien * @param to the store to merge into.
64990075Sobrien * @param lock a lock that unlocks the certificates store, use NULL to
65090075Sobrien * select no password/certifictes/prompt lock (see @ref page_lock).
65190075Sobrien * @param name name of the source store
65290075Sobrien *
65390075Sobrien * @return Returns an hx509 error code.
65490075Sobrien *
65590075Sobrien * @ingroup hx509_keyset
65690075Sobrien */
65790075Sobrien
65890075Sobrienint
65990075Sobrienhx509_certs_append(hx509_context context,
660132718Skan		   hx509_certs to,
66190075Sobrien		   hx509_lock lock,
66290075Sobrien		   const char *name)
66390075Sobrien{
66490075Sobrien    hx509_certs s;
665117395Skan    int ret;
66690075Sobrien
66790075Sobrien    ret = hx509_certs_init(context, name, 0, lock, &s);
66890075Sobrien    if (ret)
66990075Sobrien	return ret;
67090075Sobrien    ret = hx509_certs_merge(context, to, s);
67190075Sobrien    hx509_certs_free(&s);
67290075Sobrien    return ret;
67390075Sobrien}
674132718Skan
67590075Sobrien/**
67690075Sobrien * Get one random certificate from the certificate store.
67790075Sobrien *
67890075Sobrien * @param context a hx509 context.
67990075Sobrien * @param certs a certificate store to get the certificate from.
68090075Sobrien * @param c return certificate, should be freed with hx509_cert_free().
68190075Sobrien *
68290075Sobrien * @return Returns an hx509 error code.
68390075Sobrien *
68490075Sobrien * @ingroup hx509_keyset
68590075Sobrien */
68690075Sobrien
68790075Sobrienint
68890075Sobrienhx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
68990075Sobrien{
69090075Sobrien    hx509_cursor cursor;
691132718Skan    int ret;
69290075Sobrien
69390075Sobrien    *c = NULL;
69490075Sobrien
69590075Sobrien    ret = hx509_certs_start_seq(context, certs, &cursor);
69690075Sobrien    if (ret)
697169689Skan	return ret;
698169689Skan
699169689Skan    ret = hx509_certs_next_cert(context, certs, cursor, c);
700169689Skan    if (ret)
701169689Skan	return ret;
70290075Sobrien
70390075Sobrien    hx509_certs_end_seq(context, certs, cursor);
70490075Sobrien    return 0;
70590075Sobrien}
70690075Sobrien
70790075Sobrienstatic int
708132718Skancerts_info_stdio(void *ctx, const char *str)
70990075Sobrien{
71090075Sobrien    FILE *f = ctx;
711169689Skan    fprintf(f, "%s\n", str);
71290075Sobrien    return 0;
713169689Skan}
71490075Sobrien
715132718Skan/**
71690075Sobrien * Print some info about the certificate store.
71790075Sobrien *
718169689Skan * @param context a hx509 context.
719169689Skan * @param certs certificate store to print information about.
720169689Skan * @param func function that will get each line of the information, if
721169689Skan * NULL is used the data is printed on a FILE descriptor that should
722169689Skan * be passed in ctx, if ctx also is NULL, stdout is used.
723169689Skan * @param ctx parameter to func.
724169689Skan *
725169689Skan * @return Returns an hx509 error code.
726169689Skan *
727169689Skan * @ingroup hx509_keyset
728169689Skan */
729169689Skan
73090075Sobrienint
73190075Sobrienhx509_certs_info(hx509_context context,
732169689Skan		 hx509_certs certs,
73390075Sobrien		 int (*func)(void *, const char *),
734169689Skan		 void *ctx)
73590075Sobrien{
73690075Sobrien    if (func == NULL) {
737169689Skan	func = certs_info_stdio;
73890075Sobrien	if (ctx == NULL)
739169689Skan	    ctx = stdout;
740169689Skan    }
741169689Skan    if (certs->ops->printinfo == NULL) {
742169689Skan	(*func)(ctx, "No info function for certs");
743169689Skan	return 0;
74490075Sobrien    }
74590075Sobrien    return (*certs->ops->printinfo)(context, certs, certs->ops_data,
746169689Skan				    func, ctx);
747169689Skan}
748169689Skan
74990075Sobrienvoid
75090075Sobrien_hx509_pi_printf(int (*func)(void *, const char *), void *ctx,
751132718Skan		 const char *fmt, ...)
75290075Sobrien{
753117395Skan    va_list ap;
75490075Sobrien    char *str;
755117395Skan
756117395Skan    va_start(ap, fmt);
757117395Skan    vasprintf(&str, fmt, ap);
75890075Sobrien    va_end(ap);
759117395Skan    if (str == NULL)
760117395Skan	return;
761117395Skan    (*func)(ctx, str);
76290075Sobrien    free(str);
763117395Skan}
764117395Skan
76590075Sobrienint
76690075Sobrien_hx509_certs_keys_get(hx509_context context,
767117395Skan		      hx509_certs certs,
768117395Skan		      hx509_private_key **keys)
769117395Skan{
770117395Skan    if (certs->ops->getkeys == NULL) {
77190075Sobrien	*keys = NULL;
77290075Sobrien	return 0;
77390075Sobrien    }
774169689Skan    return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys);
77590075Sobrien}
77690075Sobrien
77790075Sobrienint
778169689Skan_hx509_certs_keys_add(hx509_context context,
779169689Skan		      hx509_certs certs,
780169689Skan		      hx509_private_key key)
781169689Skan{
782169689Skan    if (certs->ops->addkey == NULL) {
78390075Sobrien	hx509_set_error_string(context, 0, EINVAL,
784169689Skan			       "keystore if type %s doesn't support "
785169689Skan			       "key add operation",
786169689Skan			       certs->ops->name);
787169689Skan	return EINVAL;
788169689Skan    }
789169689Skan    return (*certs->ops->addkey)(context, certs, certs->ops_data, key);
790169689Skan}
791169689Skan
792169689Skan
793169689Skanvoid
794169689Skan_hx509_certs_keys_free(hx509_context context,
795169689Skan		       hx509_private_key *keys)
79690075Sobrien{
797169689Skan    int i;
798169689Skan    for (i = 0; keys[i]; i++)
79990075Sobrien	hx509_private_key_free(&keys[i]);
800117395Skan    free(keys);
801117395Skan}
80290075Sobrien