xref: /freebsd/crypto/heimdal/lib/hx509/keyset.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
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 }
678