xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hx509/keyset.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
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 
64 struct hx509_certs_data {
65     unsigned int ref;
66     struct hx509_keyset_ops *ops;
67     void *ops_data;
68 };
69 
70 static struct hx509_keyset_ops *
_hx509_ks_type(hx509_context context,const char * type)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 
82 void
_hx509_ks_register(hx509_context context,struct hx509_keyset_ops * ops)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 
117 int
hx509_certs_init(hx509_context context,const char * name,int flags,hx509_lock lock,hx509_certs * certs)118 hx509_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 
188 int
hx509_certs_store(hx509_context context,hx509_certs certs,int flags,hx509_lock lock)189 hx509_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 
206 hx509_certs
hx509_certs_ref(hx509_certs certs)207 hx509_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 
227 void
hx509_certs_free(hx509_certs * certs)228 hx509_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 
257 int
hx509_certs_start_seq(hx509_context context,hx509_certs certs,hx509_cursor * cursor)258 hx509_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 
293 int
hx509_certs_next_cert(hx509_context context,hx509_certs certs,hx509_cursor cursor,hx509_cert * cert)294 hx509_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 
315 int
hx509_certs_end_seq(hx509_context context,hx509_certs certs,hx509_cursor cursor)316 hx509_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 
340 int
hx509_certs_iter_f(hx509_context context,hx509_certs certs,int (* func)(hx509_context,void *,hx509_cert),void * ctx)341 hx509_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 
375 static int
certs_iter(hx509_context context,void * ctx,hx509_cert cert)376 certs_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 
397 int
398 hx509_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 
420 int
hx509_ci_print_names(hx509_context context,void * ctx,hx509_cert c)421 hx509_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 
457 int
hx509_certs_add(hx509_context context,hx509_certs certs,hx509_cert cert)458 hx509_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 
484 int
hx509_certs_find(hx509_context context,hx509_certs certs,const hx509_query * q,hx509_cert * r)485 hx509_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 
548 int
hx509_certs_filter(hx509_context context,hx509_certs certs,const hx509_query * q,hx509_certs * result)549 hx509_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 
605 static int
certs_merge_func(hx509_context context,void * ctx,hx509_cert c)606 certs_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 
624 int
hx509_certs_merge(hx509_context context,hx509_certs to,hx509_certs from)625 hx509_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 
647 int
hx509_certs_append(hx509_context context,hx509_certs to,hx509_lock lock,const char * name)648 hx509_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 
676 int
hx509_get_one_cert(hx509_context context,hx509_certs certs,hx509_cert * c)677 hx509_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 
696 static int
certs_info_stdio(void * ctx,const char * str)697 certs_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 
719 int
hx509_certs_info(hx509_context context,hx509_certs certs,int (* func)(void *,const char *),void * ctx)720 hx509_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 
738 void
_hx509_pi_printf(int (* func)(void *,const char *),void * ctx,const char * fmt,...)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 
755 int
_hx509_certs_keys_get(hx509_context context,hx509_certs certs,hx509_private_key ** keys)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 
767 int
_hx509_certs_keys_add(hx509_context context,hx509_certs certs,hx509_private_key key)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 
783 void
_hx509_certs_keys_free(hx509_context context,hx509_private_key * keys)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