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