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