1/*	$NetBSD: keyset.c,v 1.2 2017/01/28 21:31:48 christos Exp $	*/
2
3/*
4 * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of the Institute nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#include "hx_locl.h"
39
40/**
41 * @page page_keyset Certificate store operations
42 *
43 * Type of certificates store:
44 * - MEMORY
45 *   In memory based format. Doesnt support storing.
46 * - FILE
47 *   FILE supports raw DER certicates and PEM certicates. When PEM is
48 *   used the file can contain may certificates and match private
49 *   keys. Support storing the certificates. DER format only supports
50 *   on certificate and no private key.
51 * - PEM-FILE
52 *   Same as FILE, defaulting to PEM encoded certificates.
53 * - PEM-FILE
54 *   Same as FILE, defaulting to DER encoded certificates.
55 * - PKCS11
56 * - PKCS12
57 * - DIR
58 * - KEYCHAIN
59 *   Apple Mac OS X KeyChain backed keychain object.
60 *
61 * See the library functions here: @ref hx509_keyset
62 */
63
64struct hx509_certs_data {
65    unsigned int ref;
66    struct hx509_keyset_ops *ops;
67    void *ops_data;
68};
69
70static struct hx509_keyset_ops *
71_hx509_ks_type(hx509_context context, const char *type)
72{
73    int i;
74
75    for (i = 0; i < context->ks_num_ops; i++)
76	if (strcasecmp(type, context->ks_ops[i]->name) == 0)
77	    return context->ks_ops[i];
78
79    return NULL;
80}
81
82void
83_hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
84{
85    struct hx509_keyset_ops **val;
86
87    if (_hx509_ks_type(context, ops->name))
88	return;
89
90    val = realloc(context->ks_ops,
91		  (context->ks_num_ops + 1) * sizeof(context->ks_ops[0]));
92    if (val == NULL)
93	return;
94    val[context->ks_num_ops] = ops;
95    context->ks_ops = val;
96    context->ks_num_ops++;
97}
98
99/**
100 * Open or creates a new hx509 certificate store.
101 *
102 * @param context A hx509 context
103 * @param name name of the store, format is TYPE:type-specific-string,
104 * if NULL is used the MEMORY store is used.
105 * @param flags list of flags:
106 * - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
107 * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
108 * @param lock a lock that unlocks the certificates store, use NULL to
109 * select no password/certifictes/prompt lock (see @ref page_lock).
110 * @param certs return pointer, free with hx509_certs_free().
111 *
112 * @return Returns an hx509 error code.
113 *
114 * @ingroup hx509_keyset
115 */
116
117int
118hx509_certs_init(hx509_context context,
119		 const char *name, int flags,
120		 hx509_lock lock, hx509_certs *certs)
121{
122    struct hx509_keyset_ops *ops;
123    const char *residue;
124    hx509_certs c;
125    char *type;
126    int ret;
127
128    *certs = NULL;
129
130    residue = strchr(name, ':');
131    if (residue) {
132	type = malloc(residue - name + 1);
133	if (type)
134	    strlcpy(type, name, residue - name + 1);
135	residue++;
136	if (residue[0] == '\0')
137	    residue = NULL;
138    } else {
139	type = strdup("MEMORY");
140	residue = name;
141    }
142    if (type == NULL) {
143	hx509_clear_error_string(context);
144	return ENOMEM;
145    }
146
147    ops = _hx509_ks_type(context, type);
148    if (ops == NULL) {
149	hx509_set_error_string(context, 0, ENOENT,
150			       "Keyset type %s is not supported", type);
151	free(type);
152	return ENOENT;
153    }
154    free(type);
155    c = calloc(1, sizeof(*c));
156    if (c == NULL) {
157	hx509_clear_error_string(context);
158	return ENOMEM;
159    }
160    c->ops = ops;
161    c->ref = 1;
162
163    ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
164    if (ret) {
165	free(c);
166	return ret;
167    }
168
169    *certs = c;
170    return 0;
171}
172
173/**
174 * Write the certificate store to stable storage.
175 *
176 * @param context A hx509 context.
177 * @param certs a certificate store to store.
178 * @param flags currently unused, use 0.
179 * @param lock a lock that unlocks the certificates store, use NULL to
180 * select no password/certifictes/prompt lock (see @ref page_lock).
181 *
182 * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
183 * the certificate store doesn't support the store operation.
184 *
185 * @ingroup hx509_keyset
186 */
187
188int
189hx509_certs_store(hx509_context context,
190		  hx509_certs certs,
191		  int flags,
192		  hx509_lock lock)
193{
194    if (certs->ops->store == NULL) {
195	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
196			       "keystore if type %s doesn't support "
197			       "store operation",
198			       certs->ops->name);
199	return HX509_UNSUPPORTED_OPERATION;
200    }
201
202    return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
203}
204
205
206hx509_certs
207hx509_certs_ref(hx509_certs certs)
208{
209    if (certs == NULL)
210	return NULL;
211    if (certs->ref == 0)
212	_hx509_abort("certs refcount == 0 on ref");
213    if (certs->ref == UINT_MAX)
214	_hx509_abort("certs refcount == UINT_MAX on ref");
215    certs->ref++;
216    return certs;
217}
218
219/**
220 * Free a certificate store.
221 *
222 * @param certs certificate store to free.
223 *
224 * @ingroup hx509_keyset
225 */
226
227void
228hx509_certs_free(hx509_certs *certs)
229{
230    if (*certs) {
231	if ((*certs)->ref == 0)
232	    _hx509_abort("cert refcount == 0 on free");
233	if (--(*certs)->ref > 0)
234	    return;
235
236	(*(*certs)->ops->free)(*certs, (*certs)->ops_data);
237	free(*certs);
238	*certs = NULL;
239    }
240}
241
242/**
243 * Start the integration
244 *
245 * @param context a hx509 context.
246 * @param certs certificate store to iterate over
247 * @param cursor cursor that will keep track of progress, free with
248 * hx509_certs_end_seq().
249 *
250 * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is
251 * returned if the certificate store doesn't support the iteration
252 * operation.
253 *
254 * @ingroup hx509_keyset
255 */
256
257int
258hx509_certs_start_seq(hx509_context context,
259		      hx509_certs certs,
260		      hx509_cursor *cursor)
261{
262    int ret;
263
264    if (certs->ops->iter_start == NULL) {
265	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
266			       "Keyset type %s doesn't support iteration",
267			       certs->ops->name);
268	return HX509_UNSUPPORTED_OPERATION;
269    }
270
271    ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
272    if (ret)
273	return ret;
274
275    return 0;
276}
277
278/**
279 * Get next ceritificate from the certificate keystore pointed out by
280 * cursor.
281 *
282 * @param context a hx509 context.
283 * @param certs certificate store to iterate over.
284 * @param cursor cursor that keeps track of progress.
285 * @param cert return certificate next in store, NULL if the store
286 * contains no more certificates. Free with hx509_cert_free().
287 *
288 * @return Returns an hx509 error code.
289 *
290 * @ingroup hx509_keyset
291 */
292
293int
294hx509_certs_next_cert(hx509_context context,
295		      hx509_certs certs,
296		      hx509_cursor cursor,
297		      hx509_cert *cert)
298{
299    *cert = NULL;
300    return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
301}
302
303/**
304 * End the iteration over certificates.
305 *
306 * @param context a hx509 context.
307 * @param certs certificate store to iterate over.
308 * @param cursor cursor that will keep track of progress, freed.
309 *
310 * @return Returns an hx509 error code.
311 *
312 * @ingroup hx509_keyset
313 */
314
315int
316hx509_certs_end_seq(hx509_context context,
317		    hx509_certs certs,
318		    hx509_cursor cursor)
319{
320    (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor);
321    return 0;
322}
323
324/**
325 * Iterate over all certificates in a keystore and call a function
326 * for each of them.
327 *
328 * @param context a hx509 context.
329 * @param certs certificate store to iterate over.
330 * @param func function to call for each certificate. The function
331 * should return non-zero to abort the iteration, that value is passed
332 * back to the caller of hx509_certs_iter_f().
333 * @param ctx context variable that will passed to the function.
334 *
335 * @return Returns an hx509 error code.
336 *
337 * @ingroup hx509_keyset
338 */
339
340int
341hx509_certs_iter_f(hx509_context context,
342		   hx509_certs certs,
343		   int (*func)(hx509_context, void *, hx509_cert),
344		   void *ctx)
345{
346    hx509_cursor cursor;
347    hx509_cert c;
348    int ret;
349
350    ret = hx509_certs_start_seq(context, certs, &cursor);
351    if (ret)
352	return ret;
353
354    while (1) {
355	ret = hx509_certs_next_cert(context, certs, cursor, &c);
356	if (ret)
357	    break;
358	if (c == NULL) {
359	    ret = 0;
360	    break;
361	}
362	ret = (*func)(context, ctx, c);
363	hx509_cert_free(c);
364	if (ret)
365	    break;
366    }
367
368    hx509_certs_end_seq(context, certs, cursor);
369
370    return ret;
371}
372
373#ifdef __BLOCKS__
374
375static int
376certs_iter(hx509_context context, void *ctx, hx509_cert cert)
377{
378    int (^func)(hx509_cert) = ctx;
379    return func(cert);
380}
381
382/**
383 * Iterate over all certificates in a keystore and call a block
384 * for each of them.
385 *
386 * @param context a hx509 context.
387 * @param certs certificate store to iterate over.
388 * @param func block to call for each certificate. The function
389 * should return non-zero to abort the iteration, that value is passed
390 * back to the caller of hx509_certs_iter().
391 *
392 * @return Returns an hx509 error code.
393 *
394 * @ingroup hx509_keyset
395 */
396
397int
398hx509_certs_iter(hx509_context context,
399		 hx509_certs certs,
400		 int (^func)(hx509_cert))
401{
402    return hx509_certs_iter_f(context, certs, certs_iter, func);
403}
404#endif
405
406
407/**
408 * Function to use to hx509_certs_iter_f() as a function argument, the
409 * ctx variable to hx509_certs_iter_f() should be a FILE file descriptor.
410 *
411 * @param context a hx509 context.
412 * @param ctx used by hx509_certs_iter_f().
413 * @param c a certificate
414 *
415 * @return Returns an hx509 error code.
416 *
417 * @ingroup hx509_keyset
418 */
419
420int
421hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
422{
423    Certificate *cert;
424    hx509_name n;
425    char *s, *i;
426
427    cert = _hx509_get_cert(c);
428
429    _hx509_name_from_Name(&cert->tbsCertificate.subject, &n);
430    hx509_name_to_string(n, &s);
431    hx509_name_free(&n);
432    _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n);
433    hx509_name_to_string(n, &i);
434    hx509_name_free(&n);
435    fprintf(ctx, "subject: %s\nissuer: %s\n", s, i);
436    free(s);
437    free(i);
438    return 0;
439}
440
441/**
442 * Add a certificate to the certificiate store.
443 *
444 * The receiving keyset certs will either increase reference counter
445 * of the cert or make a deep copy, either way, the caller needs to
446 * free the cert itself.
447 *
448 * @param context a hx509 context.
449 * @param certs certificate store to add the certificate to.
450 * @param cert certificate to add.
451 *
452 * @return Returns an hx509 error code.
453 *
454 * @ingroup hx509_keyset
455 */
456
457int
458hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
459{
460    if (certs->ops->add == NULL) {
461	hx509_set_error_string(context, 0, ENOENT,
462			       "Keyset type %s doesn't support add operation",
463			       certs->ops->name);
464	return ENOENT;
465    }
466
467    return (*certs->ops->add)(context, certs, certs->ops_data, cert);
468}
469
470/**
471 * Find a certificate matching the query.
472 *
473 * @param context a hx509 context.
474 * @param certs certificate store to search.
475 * @param q query allocated with @ref hx509_query functions.
476 * @param r return certificate (or NULL on error), should be freed
477 * with hx509_cert_free().
478 *
479 * @return Returns an hx509 error code.
480 *
481 * @ingroup hx509_keyset
482 */
483
484int
485hx509_certs_find(hx509_context context,
486		 hx509_certs certs,
487		 const hx509_query *q,
488		 hx509_cert *r)
489{
490    hx509_cursor cursor;
491    hx509_cert c;
492    int ret;
493
494    *r = NULL;
495
496    _hx509_query_statistic(context, 0, q);
497
498    if (certs->ops->query)
499	return (*certs->ops->query)(context, certs, certs->ops_data, q, r);
500
501    ret = hx509_certs_start_seq(context, certs, &cursor);
502    if (ret)
503	return ret;
504
505    c = NULL;
506    while (1) {
507	ret = hx509_certs_next_cert(context, certs, cursor, &c);
508	if (ret)
509	    break;
510	if (c == NULL)
511	    break;
512	if (_hx509_query_match_cert(context, q, c)) {
513	    *r = c;
514	    break;
515	}
516	hx509_cert_free(c);
517    }
518
519    hx509_certs_end_seq(context, certs, cursor);
520    if (ret)
521	return ret;
522    /**
523     * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
524     * the query.
525     */
526    if (c == NULL) {
527	hx509_clear_error_string(context);
528	return HX509_CERT_NOT_FOUND;
529    }
530
531    return 0;
532}
533
534/**
535 * Filter certificate matching the query.
536 *
537 * @param context a hx509 context.
538 * @param certs certificate store to search.
539 * @param q query allocated with @ref hx509_query functions.
540 * @param result the filtered certificate store, caller must free with
541 *        hx509_certs_free().
542 *
543 * @return Returns an hx509 error code.
544 *
545 * @ingroup hx509_keyset
546 */
547
548int
549hx509_certs_filter(hx509_context context,
550		   hx509_certs certs,
551		   const hx509_query *q,
552		   hx509_certs *result)
553{
554    hx509_cursor cursor;
555    hx509_cert c;
556    int ret, found = 0;
557
558    _hx509_query_statistic(context, 0, q);
559
560    ret = hx509_certs_init(context, "MEMORY:filter-certs", 0,
561			   NULL, result);
562    if (ret)
563	return ret;
564
565    ret = hx509_certs_start_seq(context, certs, &cursor);
566    if (ret) {
567	hx509_certs_free(result);
568	return ret;
569    }
570
571    c = NULL;
572    while (1) {
573	ret = hx509_certs_next_cert(context, certs, cursor, &c);
574	if (ret)
575	    break;
576	if (c == NULL)
577	    break;
578	if (_hx509_query_match_cert(context, q, c)) {
579	    hx509_certs_add(context, *result, c);
580	    found = 1;
581	}
582	hx509_cert_free(c);
583    }
584
585    hx509_certs_end_seq(context, certs, cursor);
586    if (ret) {
587	hx509_certs_free(result);
588	return ret;
589    }
590
591    /**
592     * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
593     * the query.
594     */
595    if (!found) {
596	hx509_certs_free(result);
597	hx509_clear_error_string(context);
598	return HX509_CERT_NOT_FOUND;
599    }
600
601    return 0;
602}
603
604
605static int
606certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
607{
608    return hx509_certs_add(context, (hx509_certs)ctx, c);
609}
610
611/**
612 * Merge a certificate store into another. The from store is keep
613 * intact.
614 *
615 * @param context a hx509 context.
616 * @param to the store to merge into.
617 * @param from the store to copy the object from.
618 *
619 * @return Returns an hx509 error code.
620 *
621 * @ingroup hx509_keyset
622 */
623
624int
625hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
626{
627    if (from == NULL)
628	return 0;
629    return hx509_certs_iter_f(context, from, certs_merge_func, to);
630}
631
632/**
633 * Same a hx509_certs_merge() but use a lock and name to describe the
634 * from source.
635 *
636 * @param context a hx509 context.
637 * @param to the store to merge into.
638 * @param lock a lock that unlocks the certificates store, use NULL to
639 * select no password/certifictes/prompt lock (see @ref page_lock).
640 * @param name name of the source store
641 *
642 * @return Returns an hx509 error code.
643 *
644 * @ingroup hx509_keyset
645 */
646
647int
648hx509_certs_append(hx509_context context,
649		   hx509_certs to,
650		   hx509_lock lock,
651		   const char *name)
652{
653    hx509_certs s;
654    int ret;
655
656    ret = hx509_certs_init(context, name, 0, lock, &s);
657    if (ret)
658	return ret;
659    ret = hx509_certs_merge(context, to, s);
660    hx509_certs_free(&s);
661    return ret;
662}
663
664/**
665 * Get one random certificate from the certificate store.
666 *
667 * @param context a hx509 context.
668 * @param certs a certificate store to get the certificate from.
669 * @param c return certificate, should be freed with hx509_cert_free().
670 *
671 * @return Returns an hx509 error code.
672 *
673 * @ingroup hx509_keyset
674 */
675
676int
677hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
678{
679    hx509_cursor cursor;
680    int ret;
681
682    *c = NULL;
683
684    ret = hx509_certs_start_seq(context, certs, &cursor);
685    if (ret)
686	return ret;
687
688    ret = hx509_certs_next_cert(context, certs, cursor, c);
689    if (ret)
690	return ret;
691
692    hx509_certs_end_seq(context, certs, cursor);
693    return 0;
694}
695
696static int
697certs_info_stdio(void *ctx, const char *str)
698{
699    FILE *f = ctx;
700    fprintf(f, "%s\n", str);
701    return 0;
702}
703
704/**
705 * Print some info about the certificate store.
706 *
707 * @param context a hx509 context.
708 * @param certs certificate store to print information about.
709 * @param func function that will get each line of the information, if
710 * NULL is used the data is printed on a FILE descriptor that should
711 * be passed in ctx, if ctx also is NULL, stdout is used.
712 * @param ctx parameter to func.
713 *
714 * @return Returns an hx509 error code.
715 *
716 * @ingroup hx509_keyset
717 */
718
719int
720hx509_certs_info(hx509_context context,
721		 hx509_certs certs,
722		 int (*func)(void *, const char *),
723		 void *ctx)
724{
725    if (func == NULL) {
726	func = certs_info_stdio;
727	if (ctx == NULL)
728	    ctx = stdout;
729    }
730    if (certs->ops->printinfo == NULL) {
731	(*func)(ctx, "No info function for certs");
732	return 0;
733    }
734    return (*certs->ops->printinfo)(context, certs, certs->ops_data,
735				    func, ctx);
736}
737
738void
739_hx509_pi_printf(int (*func)(void *, const char *), void *ctx,
740		 const char *fmt, ...)
741{
742    va_list ap;
743    char *str;
744    int ret;
745
746    va_start(ap, fmt);
747    ret = vasprintf(&str, fmt, ap);
748    va_end(ap);
749    if (ret == -1 || str == NULL)
750	return;
751    (*func)(ctx, str);
752    free(str);
753}
754
755int
756_hx509_certs_keys_get(hx509_context context,
757		      hx509_certs certs,
758		      hx509_private_key **keys)
759{
760    if (certs->ops->getkeys == NULL) {
761	*keys = NULL;
762	return 0;
763    }
764    return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys);
765}
766
767int
768_hx509_certs_keys_add(hx509_context context,
769		      hx509_certs certs,
770		      hx509_private_key key)
771{
772    if (certs->ops->addkey == NULL) {
773	hx509_set_error_string(context, 0, EINVAL,
774			       "keystore if type %s doesn't support "
775			       "key add operation",
776			       certs->ops->name);
777	return EINVAL;
778    }
779    return (*certs->ops->addkey)(context, certs, certs->ops_data, key);
780}
781
782
783void
784_hx509_certs_keys_free(hx509_context context,
785		       hx509_private_key *keys)
786{
787    int i;
788    for (i = 0; keys[i]; i++)
789	hx509_private_key_free(&keys[i]);
790    free(keys);
791}
792