]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/hx509/keyset.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / lib / hx509 / keyset.c
1 /*
2  * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "hx_locl.h"
35 RCSID("$Id: keyset.c 22466 2008-01-16 14:26:35Z lha $");
36
37 /**
38  * @page page_keyset Certificate store operations
39  *
40  * Type of certificates store:
41  * - MEMORY
42  *   In memory based format. Doesnt support storing.
43  * - FILE 
44  *   FILE supports raw DER certicates and PEM certicates. When PEM is
45  *   used the file can contain may certificates and match private
46  *   keys. Support storing the certificates. DER format only supports
47  *   on certificate and no private key.
48  * - PEM-FILE
49  *   Same as FILE, defaulting to PEM encoded certificates.
50  * - PEM-FILE
51  *   Same as FILE, defaulting to DER encoded certificates.
52  * - PKCS11
53  * - PKCS12
54  * - DIR
55  * - KEYCHAIN
56  *   Apple Mac OS X KeyChain backed keychain object.
57  *
58  * See the library functions here: @ref hx509_keyset
59  */
60
61 struct hx509_certs_data {
62     int ref;
63     struct hx509_keyset_ops *ops;
64     void *ops_data;
65 };
66
67 static struct hx509_keyset_ops *
68 _hx509_ks_type(hx509_context context, const char *type)
69 {
70     int i;
71
72     for (i = 0; i < context->ks_num_ops; i++)
73         if (strcasecmp(type, context->ks_ops[i]->name) == 0)
74             return context->ks_ops[i];
75
76     return NULL;
77 }
78
79 void
80 _hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
81 {
82     struct hx509_keyset_ops **val;
83
84     if (_hx509_ks_type(context, ops->name))
85         return;
86
87     val = realloc(context->ks_ops, 
88                   (context->ks_num_ops + 1) * sizeof(context->ks_ops[0]));
89     if (val == NULL)
90         return;
91     val[context->ks_num_ops] = ops;
92     context->ks_ops = val;
93     context->ks_num_ops++;
94 }
95
96 /**
97  * Open or creates a new hx509 certificate store.
98  *
99  * @param context A hx509 context
100  * @param name name of the store, format is TYPE:type-specific-string,
101  * if NULL is used the MEMORY store is used.
102  * @param flags list of flags:
103  * - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
104  * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
105  * @param lock a lock that unlocks the certificates store, use NULL to
106  * select no password/certifictes/prompt lock (see @ref page_lock).
107  * @param certs return pointer, free with hx509_certs_free().
108  *
109  * @ingroup hx509_keyset
110  */
111
112 int
113 hx509_certs_init(hx509_context context,
114                  const char *name, int flags,
115                  hx509_lock lock, hx509_certs *certs)
116 {
117     struct hx509_keyset_ops *ops;
118     const char *residue;
119     hx509_certs c;
120     char *type;
121     int ret;
122
123     *certs = NULL;
124
125     residue = strchr(name, ':');
126     if (residue) {
127         type = malloc(residue - name + 1);
128         if (type)
129             strlcpy(type, name, residue - name + 1);
130         residue++;
131         if (residue[0] == '\0')
132             residue = NULL;
133     } else {
134         type = strdup("MEMORY");
135         residue = name;
136     }
137     if (type == NULL) {
138         hx509_clear_error_string(context);
139         return ENOMEM;
140     }
141     
142     ops = _hx509_ks_type(context, type);
143     if (ops == NULL) {
144         hx509_set_error_string(context, 0, ENOENT, 
145                                "Keyset type %s is not supported", type);
146         free(type);
147         return ENOENT;
148     }
149     free(type);
150     c = calloc(1, sizeof(*c));
151     if (c == NULL) {
152         hx509_clear_error_string(context);
153         return ENOMEM;
154     }
155     c->ops = ops;
156     c->ref = 1;
157
158     ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
159     if (ret) {
160         free(c);
161         return ret;
162     }
163
164     *certs = c;
165     return 0;
166 }
167
168 /**
169  * Write the certificate store to stable storage.
170  *
171  * @param context A hx509 context.
172  * @param certs a certificate store to store.
173  * @param flags currently unused, use 0.
174  * @param lock a lock that unlocks the certificates store, use NULL to
175  * select no password/certifictes/prompt lock (see @ref page_lock).
176  *
177  * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
178  * the certificate store doesn't support the store operation.
179  *
180  * @ingroup hx509_keyset
181  */
182
183 int
184 hx509_certs_store(hx509_context context,
185                   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
201 hx509_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
222 void
223 hx509_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
252 int
253 hx509_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
288 int
289 hx509_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
310 int
311 hx509_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
335 int
336 hx509_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
382 int
383 hx509_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
419 int
420 hx509_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
446 int
447 hx509_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
492 static int
493 certs_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
511 int
512 hx509_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
534 int
535 hx509_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
563 int
564 hx509_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
583 static int
584 certs_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
606 int
607 hx509_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
625 void
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
641 int
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
653 int
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
669 void
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 }