1 /*	$NetBSD: keyset.c,v 1.1.1.1 2011/04/13 18:15:11 elric 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  * @ingroup hx509_keyset
113  */
114 
115 int
hx509_certs_init(hx509_context context,const char * name,int flags,hx509_lock lock,hx509_certs * certs)116 hx509_certs_init(hx509_context context,
117 		 const char *name, int flags,
118 		 hx509_lock lock, hx509_certs *certs)
119 {
120     struct hx509_keyset_ops *ops;
121     const char *residue;
122     hx509_certs c;
123     char *type;
124     int ret;
125 
126     *certs = NULL;
127 
128     residue = strchr(name, ':');
129     if (residue) {
130 	type = malloc(residue - name + 1);
131 	if (type)
132 	    strlcpy(type, name, residue - name + 1);
133 	residue++;
134 	if (residue[0] == '\0')
135 	    residue = NULL;
136     } else {
137 	type = strdup("MEMORY");
138 	residue = name;
139     }
140     if (type == NULL) {
141 	hx509_clear_error_string(context);
142 	return ENOMEM;
143     }
144 
145     ops = _hx509_ks_type(context, type);
146     if (ops == NULL) {
147 	hx509_set_error_string(context, 0, ENOENT,
148 			       "Keyset type %s is not supported", type);
149 	free(type);
150 	return ENOENT;
151     }
152     free(type);
153     c = calloc(1, sizeof(*c));
154     if (c == NULL) {
155 	hx509_clear_error_string(context);
156 	return ENOMEM;
157     }
158     c->ops = ops;
159     c->ref = 1;
160 
161     ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock);
162     if (ret) {
163 	free(c);
164 	return ret;
165     }
166 
167     *certs = c;
168     return 0;
169 }
170 
171 /**
172  * Write the certificate store to stable storage.
173  *
174  * @param context A hx509 context.
175  * @param certs a certificate store to store.
176  * @param flags currently unused, use 0.
177  * @param lock a lock that unlocks the certificates store, use NULL to
178  * select no password/certifictes/prompt lock (see @ref page_lock).
179  *
180  * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION if
181  * the certificate store doesn't support the store operation.
182  *
183  * @ingroup hx509_keyset
184  */
185 
186 int
hx509_certs_store(hx509_context context,hx509_certs certs,int flags,hx509_lock lock)187 hx509_certs_store(hx509_context context,
188 		  hx509_certs certs,
189 		  int flags,
190 		  hx509_lock lock)
191 {
192     if (certs->ops->store == NULL) {
193 	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
194 			       "keystore if type %s doesn't support "
195 			       "store operation",
196 			       certs->ops->name);
197 	return HX509_UNSUPPORTED_OPERATION;
198     }
199 
200     return (*certs->ops->store)(context, certs, certs->ops_data, flags, lock);
201 }
202 
203 
204 hx509_certs
hx509_certs_ref(hx509_certs certs)205 hx509_certs_ref(hx509_certs certs)
206 {
207     if (certs == NULL)
208 	return NULL;
209     if (certs->ref == 0)
210 	_hx509_abort("certs refcount == 0 on ref");
211     if (certs->ref == UINT_MAX)
212 	_hx509_abort("certs refcount == UINT_MAX on ref");
213     certs->ref++;
214     return certs;
215 }
216 
217 /**
218  * Free a certificate store.
219  *
220  * @param certs certificate store to free.
221  *
222  * @ingroup hx509_keyset
223  */
224 
225 void
hx509_certs_free(hx509_certs * certs)226 hx509_certs_free(hx509_certs *certs)
227 {
228     if (*certs) {
229 	if ((*certs)->ref == 0)
230 	    _hx509_abort("cert refcount == 0 on free");
231 	if (--(*certs)->ref > 0)
232 	    return;
233 
234 	(*(*certs)->ops->free)(*certs, (*certs)->ops_data);
235 	free(*certs);
236 	*certs = NULL;
237     }
238 }
239 
240 /**
241  * Start the integration
242  *
243  * @param context a hx509 context.
244  * @param certs certificate store to iterate over
245  * @param cursor cursor that will keep track of progress, free with
246  * hx509_certs_end_seq().
247  *
248  * @return Returns an hx509 error code. HX509_UNSUPPORTED_OPERATION is
249  * returned if the certificate store doesn't support the iteration
250  * operation.
251  *
252  * @ingroup hx509_keyset
253  */
254 
255 int
hx509_certs_start_seq(hx509_context context,hx509_certs certs,hx509_cursor * cursor)256 hx509_certs_start_seq(hx509_context context,
257 		      hx509_certs certs,
258 		      hx509_cursor *cursor)
259 {
260     int ret;
261 
262     if (certs->ops->iter_start == NULL) {
263 	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
264 			       "Keyset type %s doesn't support iteration",
265 			       certs->ops->name);
266 	return HX509_UNSUPPORTED_OPERATION;
267     }
268 
269     ret = (*certs->ops->iter_start)(context, certs, certs->ops_data, cursor);
270     if (ret)
271 	return ret;
272 
273     return 0;
274 }
275 
276 /**
277  * Get next ceritificate from the certificate keystore pointed out by
278  * cursor.
279  *
280  * @param context a hx509 context.
281  * @param certs certificate store to iterate over.
282  * @param cursor cursor that keeps track of progress.
283  * @param cert return certificate next in store, NULL if the store
284  * contains no more certificates. Free with hx509_cert_free().
285  *
286  * @return Returns an hx509 error code.
287  *
288  * @ingroup hx509_keyset
289  */
290 
291 int
hx509_certs_next_cert(hx509_context context,hx509_certs certs,hx509_cursor cursor,hx509_cert * cert)292 hx509_certs_next_cert(hx509_context context,
293 		      hx509_certs certs,
294 		      hx509_cursor cursor,
295 		      hx509_cert *cert)
296 {
297     *cert = NULL;
298     return (*certs->ops->iter)(context, certs, certs->ops_data, cursor, cert);
299 }
300 
301 /**
302  * End the iteration over certificates.
303  *
304  * @param context a hx509 context.
305  * @param certs certificate store to iterate over.
306  * @param cursor cursor that will keep track of progress, freed.
307  *
308  * @return Returns an hx509 error code.
309  *
310  * @ingroup hx509_keyset
311  */
312 
313 int
hx509_certs_end_seq(hx509_context context,hx509_certs certs,hx509_cursor cursor)314 hx509_certs_end_seq(hx509_context context,
315 		    hx509_certs certs,
316 		    hx509_cursor cursor)
317 {
318     (*certs->ops->iter_end)(context, certs, certs->ops_data, cursor);
319     return 0;
320 }
321 
322 /**
323  * Iterate over all certificates in a keystore and call an function
324  * for each fo them.
325  *
326  * @param context a hx509 context.
327  * @param certs certificate store to iterate over.
328  * @param func function to call for each certificate. The function
329  * should return non-zero to abort the iteration, that value is passed
330  * back to the caller of hx509_certs_iter_f().
331  * @param ctx context variable that will passed to the function.
332  *
333  * @return Returns an hx509 error code.
334  *
335  * @ingroup hx509_keyset
336  */
337 
338 int
hx509_certs_iter_f(hx509_context context,hx509_certs certs,int (* func)(hx509_context,void *,hx509_cert),void * ctx)339 hx509_certs_iter_f(hx509_context context,
340 		   hx509_certs certs,
341 		   int (*func)(hx509_context, void *, hx509_cert),
342 		   void *ctx)
343 {
344     hx509_cursor cursor;
345     hx509_cert c;
346     int ret;
347 
348     ret = hx509_certs_start_seq(context, certs, &cursor);
349     if (ret)
350 	return ret;
351 
352     while (1) {
353 	ret = hx509_certs_next_cert(context, certs, cursor, &c);
354 	if (ret)
355 	    break;
356 	if (c == NULL) {
357 	    ret = 0;
358 	    break;
359 	}
360 	ret = (*func)(context, ctx, c);
361 	hx509_cert_free(c);
362 	if (ret)
363 	    break;
364     }
365 
366     hx509_certs_end_seq(context, certs, cursor);
367 
368     return ret;
369 }
370 
371 /**
372  * Iterate over all certificates in a keystore and call an function
373  * for each fo them.
374  *
375  * @param context a hx509 context.
376  * @param certs certificate store to iterate over.
377  * @param func function to call for each certificate. The function
378  * should return non-zero to abort the iteration, that value is passed
379  * back to the caller of hx509_certs_iter().
380  *
381  * @return Returns an hx509 error code.
382  *
383  * @ingroup hx509_keyset
384  */
385 
386 #ifdef __BLOCKS__
387 
388 static int
certs_iter(hx509_context context,void * ctx,hx509_cert cert)389 certs_iter(hx509_context context, void *ctx, hx509_cert cert)
390 {
391     int (^func)(hx509_cert) = ctx;
392     return func(cert);
393 }
394 
395 /**
396  * Iterate over all certificates in a keystore and call an block
397  * for each fo them.
398  *
399  * @param context a hx509 context.
400  * @param certs certificate store to iterate over.
401  * @param func block to call for each certificate. The function
402  * should return non-zero to abort the iteration, that value is passed
403  * back to the caller of hx509_certs_iter().
404  *
405  * @return Returns an hx509 error code.
406  *
407  * @ingroup hx509_keyset
408  */
409 
410 int
411 hx509_certs_iter(hx509_context context,
412 		 hx509_certs certs,
413 		 int (^func)(hx509_cert))
414 {
415     return hx509_certs_iter_f(context, certs, certs_iter, func);
416 }
417 #endif
418 
419 
420 /**
421  * Function to use to hx509_certs_iter_f() as a function argument, the
422  * ctx variable to hx509_certs_iter_f() should be a FILE file descriptor.
423  *
424  * @param context a hx509 context.
425  * @param ctx used by hx509_certs_iter_f().
426  * @param c a certificate
427  *
428  * @return Returns an hx509 error code.
429  *
430  * @ingroup hx509_keyset
431  */
432 
433 int
hx509_ci_print_names(hx509_context context,void * ctx,hx509_cert c)434 hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
435 {
436     Certificate *cert;
437     hx509_name n;
438     char *s, *i;
439 
440     cert = _hx509_get_cert(c);
441 
442     _hx509_name_from_Name(&cert->tbsCertificate.subject, &n);
443     hx509_name_to_string(n, &s);
444     hx509_name_free(&n);
445     _hx509_name_from_Name(&cert->tbsCertificate.issuer, &n);
446     hx509_name_to_string(n, &i);
447     hx509_name_free(&n);
448     fprintf(ctx, "subject: %s\nissuer: %s\n", s, i);
449     free(s);
450     free(i);
451     return 0;
452 }
453 
454 /**
455  * Add a certificate to the certificiate store.
456  *
457  * The receiving keyset certs will either increase reference counter
458  * of the cert or make a deep copy, either way, the caller needs to
459  * free the cert itself.
460  *
461  * @param context a hx509 context.
462  * @param certs certificate store to add the certificate to.
463  * @param cert certificate to add.
464  *
465  * @return Returns an hx509 error code.
466  *
467  * @ingroup hx509_keyset
468  */
469 
470 int
hx509_certs_add(hx509_context context,hx509_certs certs,hx509_cert cert)471 hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
472 {
473     if (certs->ops->add == NULL) {
474 	hx509_set_error_string(context, 0, ENOENT,
475 			       "Keyset type %s doesn't support add operation",
476 			       certs->ops->name);
477 	return ENOENT;
478     }
479 
480     return (*certs->ops->add)(context, certs, certs->ops_data, cert);
481 }
482 
483 /**
484  * Find a certificate matching the query.
485  *
486  * @param context a hx509 context.
487  * @param certs certificate store to search.
488  * @param q query allocated with @ref hx509_query functions.
489  * @param r return certificate (or NULL on error), should be freed
490  * with hx509_cert_free().
491  *
492  * @return Returns an hx509 error code.
493  *
494  * @ingroup hx509_keyset
495  */
496 
497 int
hx509_certs_find(hx509_context context,hx509_certs certs,const hx509_query * q,hx509_cert * r)498 hx509_certs_find(hx509_context context,
499 		 hx509_certs certs,
500 		 const hx509_query *q,
501 		 hx509_cert *r)
502 {
503     hx509_cursor cursor;
504     hx509_cert c;
505     int ret;
506 
507     *r = NULL;
508 
509     _hx509_query_statistic(context, 0, q);
510 
511     if (certs->ops->query)
512 	return (*certs->ops->query)(context, certs, certs->ops_data, q, r);
513 
514     ret = hx509_certs_start_seq(context, certs, &cursor);
515     if (ret)
516 	return ret;
517 
518     c = NULL;
519     while (1) {
520 	ret = hx509_certs_next_cert(context, certs, cursor, &c);
521 	if (ret)
522 	    break;
523 	if (c == NULL)
524 	    break;
525 	if (_hx509_query_match_cert(context, q, c)) {
526 	    *r = c;
527 	    break;
528 	}
529 	hx509_cert_free(c);
530     }
531 
532     hx509_certs_end_seq(context, certs, cursor);
533     if (ret)
534 	return ret;
535     /**
536      * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
537      * the query.
538      */
539     if (c == NULL) {
540 	hx509_clear_error_string(context);
541 	return HX509_CERT_NOT_FOUND;
542     }
543 
544     return 0;
545 }
546 
547 /**
548  * Filter certificate matching the query.
549  *
550  * @param context a hx509 context.
551  * @param certs certificate store to search.
552  * @param q query allocated with @ref hx509_query functions.
553  * @param result the filtered certificate store, caller must free with
554  *        hx509_certs_free().
555  *
556  * @return Returns an hx509 error code.
557  *
558  * @ingroup hx509_keyset
559  */
560 
561 int
hx509_certs_filter(hx509_context context,hx509_certs certs,const hx509_query * q,hx509_certs * result)562 hx509_certs_filter(hx509_context context,
563 		   hx509_certs certs,
564 		   const hx509_query *q,
565 		   hx509_certs *result)
566 {
567     hx509_cursor cursor;
568     hx509_cert c;
569     int ret, found = 0;
570 
571     _hx509_query_statistic(context, 0, q);
572 
573     ret = hx509_certs_init(context, "MEMORY:filter-certs", 0,
574 			   NULL, result);
575     if (ret)
576 	return ret;
577 
578     ret = hx509_certs_start_seq(context, certs, &cursor);
579     if (ret) {
580 	hx509_certs_free(result);
581 	return ret;
582     }
583 
584     c = NULL;
585     while (1) {
586 	ret = hx509_certs_next_cert(context, certs, cursor, &c);
587 	if (ret)
588 	    break;
589 	if (c == NULL)
590 	    break;
591 	if (_hx509_query_match_cert(context, q, c)) {
592 	    hx509_certs_add(context, *result, c);
593 	    found = 1;
594 	}
595 	hx509_cert_free(c);
596     }
597 
598     hx509_certs_end_seq(context, certs, cursor);
599     if (ret) {
600 	hx509_certs_free(result);
601 	return ret;
602     }
603 
604     /**
605      * Return HX509_CERT_NOT_FOUND if no certificate in certs matched
606      * the query.
607      */
608     if (!found) {
609 	hx509_certs_free(result);
610 	hx509_clear_error_string(context);
611 	return HX509_CERT_NOT_FOUND;
612     }
613 
614     return 0;
615 }
616 
617 
618 static int
certs_merge_func(hx509_context context,void * ctx,hx509_cert c)619 certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
620 {
621     return hx509_certs_add(context, (hx509_certs)ctx, c);
622 }
623 
624 /**
625  * Merge a certificate store into another. The from store is keep
626  * intact.
627  *
628  * @param context a hx509 context.
629  * @param to the store to merge into.
630  * @param from the store to copy the object from.
631  *
632  * @return Returns an hx509 error code.
633  *
634  * @ingroup hx509_keyset
635  */
636 
637 int
hx509_certs_merge(hx509_context context,hx509_certs to,hx509_certs from)638 hx509_certs_merge(hx509_context context, hx509_certs to, hx509_certs from)
639 {
640     if (from == NULL)
641 	return 0;
642     return hx509_certs_iter_f(context, from, certs_merge_func, to);
643 }
644 
645 /**
646  * Same a hx509_certs_merge() but use a lock and name to describe the
647  * from source.
648  *
649  * @param context a hx509 context.
650  * @param to the store to merge into.
651  * @param lock a lock that unlocks the certificates store, use NULL to
652  * select no password/certifictes/prompt lock (see @ref page_lock).
653  * @param name name of the source store
654  *
655  * @return Returns an hx509 error code.
656  *
657  * @ingroup hx509_keyset
658  */
659 
660 int
hx509_certs_append(hx509_context context,hx509_certs to,hx509_lock lock,const char * name)661 hx509_certs_append(hx509_context context,
662 		   hx509_certs to,
663 		   hx509_lock lock,
664 		   const char *name)
665 {
666     hx509_certs s;
667     int ret;
668 
669     ret = hx509_certs_init(context, name, 0, lock, &s);
670     if (ret)
671 	return ret;
672     ret = hx509_certs_merge(context, to, s);
673     hx509_certs_free(&s);
674     return ret;
675 }
676 
677 /**
678  * Get one random certificate from the certificate store.
679  *
680  * @param context a hx509 context.
681  * @param certs a certificate store to get the certificate from.
682  * @param c return certificate, should be freed with hx509_cert_free().
683  *
684  * @return Returns an hx509 error code.
685  *
686  * @ingroup hx509_keyset
687  */
688 
689 int
hx509_get_one_cert(hx509_context context,hx509_certs certs,hx509_cert * c)690 hx509_get_one_cert(hx509_context context, hx509_certs certs, hx509_cert *c)
691 {
692     hx509_cursor cursor;
693     int ret;
694 
695     *c = NULL;
696 
697     ret = hx509_certs_start_seq(context, certs, &cursor);
698     if (ret)
699 	return ret;
700 
701     ret = hx509_certs_next_cert(context, certs, cursor, c);
702     if (ret)
703 	return ret;
704 
705     hx509_certs_end_seq(context, certs, cursor);
706     return 0;
707 }
708 
709 static int
certs_info_stdio(void * ctx,const char * str)710 certs_info_stdio(void *ctx, const char *str)
711 {
712     FILE *f = ctx;
713     fprintf(f, "%s\n", str);
714     return 0;
715 }
716 
717 /**
718  * Print some info about the certificate store.
719  *
720  * @param context a hx509 context.
721  * @param certs certificate store to print information about.
722  * @param func function that will get each line of the information, if
723  * NULL is used the data is printed on a FILE descriptor that should
724  * be passed in ctx, if ctx also is NULL, stdout is used.
725  * @param ctx parameter to func.
726  *
727  * @return Returns an hx509 error code.
728  *
729  * @ingroup hx509_keyset
730  */
731 
732 int
hx509_certs_info(hx509_context context,hx509_certs certs,int (* func)(void *,const char *),void * ctx)733 hx509_certs_info(hx509_context context,
734 		 hx509_certs certs,
735 		 int (*func)(void *, const char *),
736 		 void *ctx)
737 {
738     if (func == NULL) {
739 	func = certs_info_stdio;
740 	if (ctx == NULL)
741 	    ctx = stdout;
742     }
743     if (certs->ops->printinfo == NULL) {
744 	(*func)(ctx, "No info function for certs");
745 	return 0;
746     }
747     return (*certs->ops->printinfo)(context, certs, certs->ops_data,
748 				    func, ctx);
749 }
750 
751 void
_hx509_pi_printf(int (* func)(void *,const char *),void * ctx,const char * fmt,...)752 _hx509_pi_printf(int (*func)(void *, const char *), void *ctx,
753 		 const char *fmt, ...)
754 {
755     va_list ap;
756     char *str;
757 
758     va_start(ap, fmt);
759     vasprintf(&str, fmt, ap);
760     va_end(ap);
761     if (str == NULL)
762 	return;
763     (*func)(ctx, str);
764     free(str);
765 }
766 
767 int
_hx509_certs_keys_get(hx509_context context,hx509_certs certs,hx509_private_key ** keys)768 _hx509_certs_keys_get(hx509_context context,
769 		      hx509_certs certs,
770 		      hx509_private_key **keys)
771 {
772     if (certs->ops->getkeys == NULL) {
773 	*keys = NULL;
774 	return 0;
775     }
776     return (*certs->ops->getkeys)(context, certs, certs->ops_data, keys);
777 }
778 
779 int
_hx509_certs_keys_add(hx509_context context,hx509_certs certs,hx509_private_key key)780 _hx509_certs_keys_add(hx509_context context,
781 		      hx509_certs certs,
782 		      hx509_private_key key)
783 {
784     if (certs->ops->addkey == NULL) {
785 	hx509_set_error_string(context, 0, EINVAL,
786 			       "keystore if type %s doesn't support "
787 			       "key add operation",
788 			       certs->ops->name);
789 	return EINVAL;
790     }
791     return (*certs->ops->addkey)(context, certs, certs->ops_data, key);
792 }
793 
794 
795 void
_hx509_certs_keys_free(hx509_context context,hx509_private_key * keys)796 _hx509_certs_keys_free(hx509_context context,
797 		       hx509_private_key *keys)
798 {
799     int i;
800     for (i = 0; keys[i]; i++)
801 	hx509_private_key_free(&keys[i]);
802     free(keys);
803 }
804