keyset.c revision 178825
1290001Sglebius/*
2290001Sglebius * Copyright (c) 2004 - 2007 Kungliga Tekniska H�gskolan
3290001Sglebius * (Royal Institute of Technology, Stockholm, Sweden).
4290001Sglebius * All rights reserved.
5290001Sglebius *
6290001Sglebius * Redistribution and use in source and binary forms, with or without
7290001Sglebius * modification, are permitted provided that the following conditions
8290001Sglebius * are met:
9290001Sglebius *
10290001Sglebius * 1. Redistributions of source code must retain the above copyright
11290001Sglebius *    notice, this list of conditions and the following disclaimer.
12290001Sglebius *
13290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
14290001Sglebius *    notice, this list of conditions and the following disclaimer in the
15290001Sglebius *    documentation and/or other materials provided with the distribution.
16290001Sglebius *
17290001Sglebius * 3. Neither the name of the Institute nor the names of its contributors
18290001Sglebius *    may be used to endorse or promote products derived from this software
19290001Sglebius *    without specific prior written permission.
20290001Sglebius *
21290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22290001Sglebius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23290001Sglebius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24290001Sglebius * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25290001Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26290001Sglebius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27290001Sglebius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28290001Sglebius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29290001Sglebius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30290001Sglebius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31290001Sglebius * SUCH DAMAGE.
32290001Sglebius */
33290001Sglebius
34290001Sglebius#include "hx_locl.h"
35290001SglebiusRCSID("$Id: keyset.c 22466 2008-01-16 14:26:35Z lha $");
36290001Sglebius
37290001Sglebius/**
38290001Sglebius * @page page_keyset Certificate store operations
39290001Sglebius *
40290001Sglebius * Type of certificates store:
41290001Sglebius * - MEMORY
42290001Sglebius *   In memory based format. Doesnt support storing.
43290001Sglebius * - FILE
44290001Sglebius *   FILE supports raw DER certicates and PEM certicates. When PEM is
45290001Sglebius *   used the file can contain may certificates and match private
46290001Sglebius *   keys. Support storing the certificates. DER format only supports
47290001Sglebius *   on certificate and no private key.
48290001Sglebius * - PEM-FILE
49290001Sglebius *   Same as FILE, defaulting to PEM encoded certificates.
50290001Sglebius * - PEM-FILE
51290001Sglebius *   Same as FILE, defaulting to DER encoded certificates.
52290001Sglebius * - PKCS11
53290001Sglebius * - PKCS12
54290001Sglebius * - DIR
55290001Sglebius * - KEYCHAIN
56290001Sglebius *   Apple Mac OS X KeyChain backed keychain object.
57290001Sglebius *
58290001Sglebius * See the library functions here: @ref hx509_keyset
59290001Sglebius */
60290001Sglebius
61290001Sglebiusstruct hx509_certs_data {
62290001Sglebius    int ref;
63290001Sglebius    struct hx509_keyset_ops *ops;
64290001Sglebius    void *ops_data;
65290001Sglebius};
66290001Sglebius
67290001Sglebiusstatic struct hx509_keyset_ops *
68290001Sglebius_hx509_ks_type(hx509_context context, const char *type)
69290001Sglebius{
70290001Sglebius    int i;
71290001Sglebius
72290001Sglebius    for (i = 0; i < context->ks_num_ops; i++)
73290001Sglebius	if (strcasecmp(type, context->ks_ops[i]->name) == 0)
74290001Sglebius	    return context->ks_ops[i];
75290001Sglebius
76290001Sglebius    return NULL;
77290001Sglebius}
78290001Sglebius
79290001Sglebiusvoid
80290001Sglebius_hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
81290001Sglebius{
82290001Sglebius    struct hx509_keyset_ops **val;
83290001Sglebius
84290001Sglebius    if (_hx509_ks_type(context, ops->name))
85290001Sglebius	return;
86290001Sglebius
87290001Sglebius    val = realloc(context->ks_ops,
88290001Sglebius		  (context->ks_num_ops + 1) * sizeof(context->ks_ops[0]));
89290001Sglebius    if (val == NULL)
90290001Sglebius	return;
91290001Sglebius    val[context->ks_num_ops] = ops;
92290001Sglebius    context->ks_ops = val;
93290001Sglebius    context->ks_num_ops++;
94290001Sglebius}
95290001Sglebius
96290001Sglebius/**
97290001Sglebius * Open or creates a new hx509 certificate store.
98290001Sglebius *
99290001Sglebius * @param context A hx509 context
100290001Sglebius * @param name name of the store, format is TYPE:type-specific-string,
101290001Sglebius * if NULL is used the MEMORY store is used.
102290001Sglebius * @param flags list of flags:
103290001Sglebius * - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
104290001Sglebius * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
105290001Sglebius * @param lock a lock that unlocks the certificates store, use NULL to
106290001Sglebius * select no password/certifictes/prompt lock (see @ref page_lock).
107290001Sglebius * @param certs return pointer, free with hx509_certs_free().
108290001Sglebius *
109290001Sglebius * @ingroup hx509_keyset
110290001Sglebius */
111290001Sglebius
112290001Sglebiusint
113290001Sglebiushx509_certs_init(hx509_context context,
114290001Sglebius		 const char *name, int flags,
115290001Sglebius		 hx509_lock lock, hx509_certs *certs)
116290001Sglebius{
117290001Sglebius    struct hx509_keyset_ops *ops;
118290001Sglebius    const char *residue;
119290001Sglebius    hx509_certs c;
120290001Sglebius    char *type;
121290001Sglebius    int ret;
122290001Sglebius
123290001Sglebius    *certs = NULL;
124290001Sglebius
125290001Sglebius    residue = strchr(name, ':');
126290001Sglebius    if (residue) {
127290001Sglebius	type = malloc(residue - name + 1);
128290001Sglebius	if (type)
129290001Sglebius	    strlcpy(type, name, residue - name + 1);
130290001Sglebius	residue++;
131290001Sglebius	if (residue[0] == '\0')
132290001Sglebius	    residue = NULL;
133290001Sglebius    } else {
134290001Sglebius	type = strdup("MEMORY");
135290001Sglebius	residue = name;
136290001Sglebius    }
137290001Sglebius    if (type == NULL) {
138290001Sglebius	hx509_clear_error_string(context);
139290001Sglebius	return ENOMEM;
140290001Sglebius    }
141290001Sglebius
142290001Sglebius    ops = _hx509_ks_type(context, type);
143290001Sglebius    if (ops == NULL) {
144290001Sglebius	hx509_set_error_string(context, 0, ENOENT,
145290001Sglebius			       "Keyset type %s is not supported", type);
146290001Sglebius	free(type);
147290001Sglebius	return ENOENT;
148290001Sglebius    }
149290001Sglebius    free(type);
150290001Sglebius    c = calloc(1, sizeof(*c));
151290001Sglebius    if (c == NULL) {
152290001Sglebius	hx509_clear_error_string(context);
153290001Sglebius	return ENOMEM;
154290001Sglebius    }
155290001Sglebius    c->ops = ops;
156290001Sglebius    c->ref = 1;
157290001Sglebius
158290001Sglebius    ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
159290001Sglebius    if (ret) {
160290001Sglebius	free(c);
161290001Sglebius	return ret;
162290001Sglebius    }
163290001Sglebius
164290001Sglebius    *certs = c;
165290001Sglebius    return 0;
166290001Sglebius}
167290001Sglebius
168290001Sglebius/**
169290001Sglebius * Write the certificate store to stable storage.
170290001Sglebius *
171290001Sglebius * @param context A hx509 context.
172290001Sglebius * @param certs a certificate store to store.
173290001Sglebius * @param flags currently unused, use 0.
174290001Sglebius * @param lock a lock that unlocks the certificates store, use NULL to
175290001Sglebius * select no password/certifictes/prompt lock (see @ref page_lock).
176290001Sglebius *
177290001Sglebius * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
178290001Sglebius * the certificate store doesn't support the store operation.
179290001Sglebius *
180290001Sglebius * @ingroup hx509_keyset
181290001Sglebius */
182290001Sglebius
183290001Sglebiusint
184290001Sglebiushx509_certs_store(hx509_context context,
185290001Sglebius		  hx509_certs certs,
186		  int flags,
187		  hx509_lock lock)
188{
189    if (certs->ops->store == NULL) {
190	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
191			       "keystore if type %s doesn't support "
192			       "store operation",
193			       certs->ops->name);
194	return HX509_UNSUPPORTED_OPERATION;
195    }
196
197    return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
198}
199
200
201hx509_certs
202_hx509_certs_ref(hx509_certs certs)
203{
204    if (certs == NULL)
205	return NULL;
206    if (certs->ref <= 0)
207	_hx509_abort("certs refcount <= 0");
208    certs->ref++;
209    if (certs->ref == 0)
210	_hx509_abort("certs refcount == 0");
211    return certs;
212}
213
214/**
215 * Free a certificate store.
216 *
217 * @param certs certificate store to free.
218 *
219 * @ingroup hx509_keyset
220 */
221
222void
223hx509_certs_free(hx509_certs *certs)
224{
225    if (*certs) {
226	if ((*certs)->ref <= 0)
227	    _hx509_abort("refcount <= 0");
228	if (--(*certs)->ref > 0)
229	    return;
230
231	(*(*certs)->ops->free)(*certs, (*certs)->ops_data);
232	free(*certs);
233	*certs = NULL;
234    }
235}
236
237/**
238 * Start the integration
239 *
240 * @param context a hx509 context.
241 * @param certs certificate store to iterate over
242 * @param cursor cursor that will keep track of progress, free with
243 * hx509_certs_end_seq().
244 *
245 * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is
246 * returned if the certificate store doesn't support the iteration
247 * operation.
248 *
249 * @ingroup hx509_keyset
250 */
251
252int
253hx509_certs_start_seq(hx509_context context,
254		      hx509_certs certs,
255		      hx509_cursor *cursor)
256{
257    int ret;
258
259    if (certs->ops->iter_start == NULL) {
260	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
261			       "Keyset type %s doesn't support iteration",
262			       certs->ops->name);
263	return HX509_UNSUPPORTED_OPERATION;
264    }
265
266    ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
267    if (ret)
268	return ret;
269
270    return 0;
271}
272
273/**
274 * Get next ceritificate from the certificate keystore pointed out by
275 * cursor.
276 *
277 * @param context a hx509 context.
278 * @param certs certificate store to iterate over.
279 * @param cursor cursor that keeps track of progress.
280 * @param cert return certificate next in store, NULL if the store
281 * contains no more certificates. Free with hx509_cert_free().
282 *
283 * @return Returns an hx509 error code.
284 *
285 * @ingroup hx509_keyset
286 */
287
288int
289hx509_certs_next_cert(hx509_context context,
290		      hx509_certs certs,
291		      hx509_cursor cursor,
292		      hx509_cert *cert)
293{
294    *cert = NULL;
295    return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
296}
297
298/**
299 * End the iteration over certificates.
300 *
301 * @param context a hx509 context.
302 * @param certs certificate store to iterate over.
303 * @param cursor cursor that will keep track of progress, freed.
304 *
305 * @return Returns an hx509 error code.
306 *
307 * @ingroup hx509_keyset
308 */
309
310int
311hx509_certs_end_seq(hx509_context context,
312		    hx509_certs certs,
313		    hx509_cursor cursor)
314{
315    (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor);
316    return 0;
317}
318
319/**
320 * Iterate over all certificates in a keystore and call an function
321 * for each fo them.
322 *
323 * @param context a hx509 context.
324 * @param certs certificate store to iterate over.
325 * @param func function to call for each certificate. The function
326 * should return non-zero to abort the iteration, that value is passed
327 * back to te caller of hx509_certs_iter().
328 * @param ctx context variable that will passed to the function.
329 *
330 * @return Returns an hx509 error code.
331 *
332 * @ingroup hx509_keyset
333 */
334
335int
336hx509_certs_iter(hx509_context context,
337		 hx509_certs certs,
338		 int (*func)(hx509_context, void *, hx509_cert),
339		 void *ctx)
340{
341    hx509_cursor cursor;
342    hx509_cert c;
343    int ret;
344
345    ret = hx509_certs_start_seq(context, certs, &cursor);
346    if (ret)
347	return ret;
348
349    while (1) {
350	ret = hx509_certs_next_cert(context, certs, cursor, &c);
351	if (ret)
352	    break;
353	if (c == NULL) {
354	    ret = 0;
355	    break;
356	}
357	ret = (*func)(context, ctx, c);
358	hx509_cert_free(c);
359	if (ret)
360	    break;
361    }
362
363    hx509_certs_end_seq(context, certs, cursor);
364
365    return ret;
366}
367
368
369/**
370 * Function to use to hx509_certs_iter() as a function argument, the
371 * ctx variable to hx509_certs_iter() should be a FILE file descriptor.
372 *
373 * @param context a hx509 context.
374 * @param ctx used by hx509_certs_iter().
375 * @param c a certificate
376 *
377 * @return Returns an hx509 error code.
378 *
379 * @ingroup hx509_keyset
380 */
381
382int
383hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
384{
385    Certificate *cert;
386    hx509_name n;
387    char *s, *i;
388
389    cert = _hx509_get_cert(c);
390
391    _hx509_name_from_Name(&cert->tbsCertificate.subject, &n);
392    hx509_name_to_string(n, &s);
393    hx509_name_free(&n);
394    _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n);
395    hx509_name_to_string(n, &i);
396    hx509_name_free(&n);
397    fprintf(ctx, "subject: %s\nissuer: %s\n", s, i);
398    free(s);
399    free(i);
400    return 0;
401}
402
403/**
404 * Add a certificate to the certificiate store.
405 *
406 * The receiving keyset certs will either increase reference counter
407 * of the cert or make a deep copy, either way, the caller needs to
408 * free the cert itself.
409 *
410 * @param context a hx509 context.
411 * @param certs certificate store to add the certificate to.
412 * @param cert certificate to add.
413 *
414 * @return Returns an hx509 error code.
415 *
416 * @ingroup hx509_keyset
417 */
418
419int
420hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
421{
422    if (certs->ops->add == NULL) {
423	hx509_set_error_string(context, 0, ENOENT,
424			       "Keyset type %s doesn't support add operation",
425			       certs->ops->name);
426	return ENOENT;
427    }
428
429    return (*certs->ops->add)(context, certs, certs->ops_data, cert);
430}
431
432/**
433 * Find a certificate matching the query.
434 *
435 * @param context a hx509 context.
436 * @param certs certificate store to search.
437 * @param q query allocated with @ref hx509_query functions.
438 * @param r return certificate (or NULL on error), should be freed
439 * with hx509_cert_free().
440 *
441 * @return Returns an hx509 error code.
442 *
443 * @ingroup hx509_keyset
444 */
445
446int
447hx509_certs_find(hx509_context context,
448		 hx509_certs certs,
449		 const hx509_query *q,
450		 hx509_cert *r)
451{
452    hx509_cursor cursor;
453    hx509_cert c;
454    int ret;
455
456    *r = NULL;
457
458    _hx509_query_statistic(context, 0, q);
459
460    if (certs->ops->query)
461	return (*certs->ops->query)(context, certs, certs->ops_data, q, r);
462
463    ret = hx509_certs_start_seq(context, certs, &cursor);
464    if (ret)
465	return ret;
466
467    c = NULL;
468    while (1) {
469	ret = hx509_certs_next_cert(context, certs, cursor, &c);
470	if (ret)
471	    break;
472	if (c == NULL)
473	    break;
474	if (_hx509_query_match_cert(context, q, c)) {
475	    *r = c;
476	    break;
477	}
478	hx509_cert_free(c);
479    }
480
481    hx509_certs_end_seq(context, certs, cursor);
482    if (ret)
483	return ret;
484    if (c == NULL) {
485	hx509_clear_error_string(context);
486	return HX509_CERT_NOT_FOUND;
487    }
488
489    return 0;
490}
491
492static int
493certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
494{
495    return hx509_certs_add(context, (hx509_certs)ctx, c);
496}
497
498/**
499 * Merge a certificate store into another. The from store is keep
500 * intact.
501 *
502 * @param context a hx509 context.
503 * @param to the store to merge into.
504 * @param from the store to copy the object from.
505 *
506 * @return Returns an hx509 error code.
507 *
508 * @ingroup hx509_keyset
509 */
510
511int
512hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
513{
514    if (from == NULL)
515	return 0;
516    return hx509_certs_iter(context, from, certs_merge_func, to);
517}
518
519/**
520 * Same a hx509_certs_merge() but use a lock and name to describe the
521 * from source.
522 *
523 * @param context a hx509 context.
524 * @param to the store to merge into.
525 * @param lock a lock that unlocks the certificates store, use NULL to
526 * select no password/certifictes/prompt lock (see @ref page_lock).
527 * @param name name of the source store
528 *
529 * @return Returns an hx509 error code.
530 *
531 * @ingroup hx509_keyset
532 */
533
534int
535hx509_certs_append(hx509_context context,
536		   hx509_certs to,
537		   hx509_lock lock,
538		   const char *name)
539{
540    hx509_certs s;
541    int ret;
542
543    ret = hx509_certs_init(context, name, 0, lock, &s);
544    if (ret)
545	return ret;
546    ret = hx509_certs_merge(context, to, s);
547    hx509_certs_free(&s);
548    return ret;
549}
550
551/**
552 * Get one random certificate from the certificate store.
553 *
554 * @param context a hx509 context.
555 * @param certs a certificate store to get the certificate from.
556 * @param c return certificate, should be freed with hx509_cert_free().
557 *
558 * @return Returns an hx509 error code.
559 *
560 * @ingroup hx509_keyset
561 */
562
563int
564hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
565{
566    hx509_cursor cursor;
567    int ret;
568
569    *c = NULL;
570
571    ret = hx509_certs_start_seq(context, certs, &cursor);
572    if (ret)
573	return ret;
574
575    ret = hx509_certs_next_cert(context, certs, cursor, c);
576    if (ret)
577	return ret;
578
579    hx509_certs_end_seq(context, certs, cursor);
580    return 0;
581}
582
583static int
584certs_info_stdio(void *ctx, const char *str)
585{
586    FILE *f = ctx;
587    fprintf(f, "%s\n", str);
588    return 0;
589}
590
591/**
592 * Print some info about the certificate store.
593 *
594 * @param context a hx509 context.
595 * @param certs certificate store to print information about.
596 * @param func function that will get each line of the information, if
597 * NULL is used the data is printed on a FILE descriptor that should
598 * be passed in ctx, if ctx also is NULL, stdout is used.
599 * @param ctx parameter to func.
600 *
601 * @return Returns an hx509 error code.
602 *
603 * @ingroup hx509_keyset
604 */
605
606int
607hx509_certs_info(hx509_context context,
608		 hx509_certs certs,
609		 int (*func)(void *, const char *),
610		 void *ctx)
611{
612    if (func == NULL) {
613	func = certs_info_stdio;
614	if (ctx == NULL)
615	    ctx = stdout;
616    }
617    if (certs->ops->printinfo == NULL) {
618	(*func)(ctx, "No info function for certs");
619	return 0;
620    }
621    return (*certs->ops->printinfo)(context, certs, certs->ops_data,
622				    func, ctx);
623}
624
625void
626_hx509_pi_printf(int (*func)(void *, const char *), void *ctx,
627		 const char *fmt, ...)
628{
629    va_list ap;
630    char *str;
631
632    va_start(ap, fmt);
633    vasprintf(&str, fmt, ap);
634    va_end(ap);
635    if (str == NULL)
636	return;
637    (*func)(ctx, str);
638    free(str);
639}
640
641int
642_hx509_certs_keys_get(hx509_context context,
643		      hx509_certs certs,
644		      hx509_private_key **keys)
645{
646    if (certs->ops->getkeys == NULL) {
647	*keys = NULL;
648	return 0;
649    }
650    return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys);
651}
652
653int
654_hx509_certs_keys_add(hx509_context context,
655		      hx509_certs certs,
656		      hx509_private_key key)
657{
658    if (certs->ops->addkey == NULL) {
659	hx509_set_error_string(context, 0, EINVAL,
660			       "keystore if type %s doesn't support "
661			       "key add operation",
662			       certs->ops->name);
663	return EINVAL;
664    }
665    return (*certs->ops->addkey)(context, certs, certs->ops_data, key);
666}
667
668
669void
670_hx509_certs_keys_free(hx509_context context,
671		       hx509_private_key *keys)
672{
673    int i;
674    for (i = 0; keys[i]; i++)
675	_hx509_private_key_free(&keys[i]);
676    free(keys);
677}
678