Line data Source code
1 : /*
2 : * Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "hx_locl.h"
35 : #ifndef WIN32
36 : #include <libgen.h>
37 : #endif
38 :
39 : typedef enum { USE_PEM, USE_DER } outformat;
40 :
41 : struct ks_file {
42 : hx509_certs certs;
43 : char *fn;
44 : outformat format;
45 : };
46 :
47 : /*
48 : *
49 : */
50 :
51 : static int
52 249 : parse_certificate(hx509_context context, const char *fn, int flags,
53 : struct hx509_collector *c,
54 : const hx509_pem_header *headers,
55 : const void *data, size_t len,
56 : const AlgorithmIdentifier *ai)
57 : {
58 249 : heim_error_t error = NULL;
59 16 : hx509_cert cert;
60 16 : int ret;
61 :
62 249 : cert = hx509_cert_init_data(context, data, len, &error);
63 249 : if (cert == NULL) {
64 0 : ret = heim_error_get_code(error);
65 0 : heim_release(error);
66 0 : return ret;
67 : }
68 :
69 249 : ret = _hx509_collector_certs_add(context, c, cert);
70 249 : hx509_cert_free(cert);
71 249 : return ret;
72 : }
73 :
74 : static int
75 0 : try_decrypt(hx509_context context,
76 : struct hx509_collector *collector,
77 : int flags,
78 : const AlgorithmIdentifier *alg,
79 : const EVP_CIPHER *c,
80 : const void *ivdata,
81 : const void *password,
82 : size_t passwordlen,
83 : const void *cipher,
84 : size_t len)
85 : {
86 0 : heim_octet_string clear;
87 0 : size_t keylen;
88 0 : void *key;
89 0 : int ret;
90 :
91 0 : keylen = EVP_CIPHER_key_length(c);
92 :
93 0 : key = malloc(keylen);
94 0 : if (key == NULL) {
95 0 : hx509_clear_error_string(context);
96 0 : return ENOMEM;
97 : }
98 :
99 0 : ret = EVP_BytesToKey(c, EVP_md5(), ivdata,
100 : password, passwordlen,
101 : 1, key, NULL);
102 0 : if (ret <= 0) {
103 0 : ret = HX509_CRYPTO_INTERNAL_ERROR;
104 0 : hx509_set_error_string(context, 0, ret,
105 : "Failed to do string2key for private key");
106 0 : goto out;
107 : }
108 :
109 0 : clear.data = malloc(len);
110 0 : if (clear.data == NULL) {
111 0 : hx509_set_error_string(context, 0, ENOMEM,
112 : "Out of memory to decrypt for private key");
113 0 : ret = ENOMEM;
114 0 : goto out;
115 : }
116 0 : clear.length = len;
117 :
118 : {
119 0 : EVP_CIPHER_CTX ctx;
120 0 : EVP_CIPHER_CTX_init(&ctx);
121 0 : EVP_CipherInit_ex(&ctx, c, NULL, key, ivdata, 0);
122 0 : EVP_Cipher(&ctx, clear.data, cipher, len);
123 0 : EVP_CIPHER_CTX_cleanup(&ctx);
124 : }
125 :
126 0 : if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS))
127 0 : ret = _hx509_collector_private_key_add(context, collector, alg, NULL,
128 : &clear, NULL);
129 :
130 0 : memset_s(clear.data, clear.length, 0, clear.length);
131 0 : free(clear.data);
132 0 : out:
133 0 : memset_s(key, keylen, 0, keylen);
134 0 : free(key);
135 0 : return ret;
136 : }
137 :
138 : static int
139 0 : parse_pkcs8_private_key(hx509_context context, const char *fn, int flags,
140 : struct hx509_collector *c,
141 : const hx509_pem_header *headers,
142 : const void *data, size_t length,
143 : const AlgorithmIdentifier *ai)
144 : {
145 0 : PKCS8PrivateKeyInfo ki;
146 0 : heim_octet_string keydata;
147 0 : int ret;
148 :
149 0 : ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
150 0 : if (ret)
151 0 : return ret;
152 :
153 0 : if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
154 0 : keydata.data = rk_UNCONST(data);
155 0 : keydata.length = length;
156 0 : ret = _hx509_collector_private_key_add(context,
157 : c,
158 : &ki.privateKeyAlgorithm,
159 : NULL,
160 : &ki.privateKey,
161 : &keydata);
162 : }
163 0 : free_PKCS8PrivateKeyInfo(&ki);
164 0 : return ret;
165 : }
166 :
167 : static int
168 74 : parse_pem_private_key(hx509_context context, const char *fn, int flags,
169 : struct hx509_collector *c,
170 : const hx509_pem_header *headers,
171 : const void *data, size_t len,
172 : const AlgorithmIdentifier *ai)
173 : {
174 74 : int ret = 0;
175 8 : const char *enc;
176 :
177 74 : enc = hx509_pem_find_header(headers, "Proc-Type");
178 74 : if (enc) {
179 0 : const char *dek;
180 0 : char *type, *iv;
181 0 : ssize_t ssize, size;
182 0 : void *ivdata;
183 0 : const EVP_CIPHER *cipher;
184 0 : const struct _hx509_password *pw;
185 0 : hx509_lock lock;
186 0 : int decrypted = 0;
187 0 : size_t i;
188 :
189 0 : lock = _hx509_collector_get_lock(c);
190 0 : if (lock == NULL) {
191 0 : hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
192 : "Failed to get password for "
193 : "password protected file %s", fn);
194 0 : return HX509_ALG_NOT_SUPP;
195 : }
196 :
197 0 : if (strcmp(enc, "4,ENCRYPTED") != 0) {
198 0 : hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
199 : "Private key encrypted in unknown method %s "
200 : "in file %s",
201 : enc, fn);
202 0 : hx509_clear_error_string(context);
203 0 : return HX509_PARSING_KEY_FAILED;
204 : }
205 :
206 0 : dek = hx509_pem_find_header(headers, "DEK-Info");
207 0 : if (dek == NULL) {
208 0 : hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
209 : "Encrypted private key missing DEK-Info");
210 0 : return HX509_PARSING_KEY_FAILED;
211 : }
212 :
213 0 : type = strdup(dek);
214 0 : if (type == NULL) {
215 0 : hx509_clear_error_string(context);
216 0 : return ENOMEM;
217 : }
218 :
219 0 : iv = strchr(type, ',');
220 0 : if (iv == NULL) {
221 0 : free(type);
222 0 : hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
223 : "IV missing");
224 0 : return HX509_PARSING_KEY_FAILED;
225 : }
226 :
227 0 : *iv++ = '\0';
228 :
229 0 : size = strlen(iv);
230 0 : ivdata = malloc(size);
231 0 : if (ivdata == NULL) {
232 0 : hx509_clear_error_string(context);
233 0 : free(type);
234 0 : return ENOMEM;
235 : }
236 :
237 0 : cipher = EVP_get_cipherbyname(type);
238 0 : if (cipher == NULL) {
239 0 : free(ivdata);
240 0 : hx509_set_error_string(context, 0, HX509_ALG_NOT_SUPP,
241 : "Private key encrypted with "
242 : "unsupported cipher: %s",
243 : type);
244 0 : free(type);
245 0 : return HX509_ALG_NOT_SUPP;
246 : }
247 :
248 : #define PKCS5_SALT_LEN 8
249 :
250 0 : ssize = hex_decode(iv, ivdata, size);
251 0 : free(type);
252 0 : type = NULL;
253 0 : iv = NULL;
254 :
255 0 : if (ssize < 0 || ssize < PKCS5_SALT_LEN || ssize < EVP_CIPHER_iv_length(cipher)) {
256 0 : free(ivdata);
257 0 : hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
258 : "Salt have wrong length in "
259 : "private key file");
260 0 : return HX509_PARSING_KEY_FAILED;
261 : }
262 :
263 0 : pw = _hx509_lock_get_passwords(lock);
264 0 : if (pw != NULL) {
265 : const void *password;
266 : size_t passwordlen;
267 :
268 0 : for (i = 0; i < pw->len; i++) {
269 0 : password = pw->val[i];
270 0 : passwordlen = strlen(password);
271 :
272 0 : ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
273 : password, passwordlen, data, len);
274 0 : if (ret == 0) {
275 0 : decrypted = 1;
276 0 : break;
277 : }
278 : }
279 : }
280 0 : if (!decrypted) {
281 0 : hx509_prompt prompt;
282 0 : char password[128];
283 :
284 0 : memset(&prompt, 0, sizeof(prompt));
285 :
286 0 : prompt.prompt = "Password for keyfile: ";
287 0 : prompt.type = HX509_PROMPT_TYPE_PASSWORD;
288 0 : prompt.reply.data = password;
289 0 : prompt.reply.length = sizeof(password);
290 :
291 0 : ret = hx509_lock_prompt(lock, &prompt);
292 0 : if (ret == 0)
293 0 : ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
294 : password, strlen(password), data, len);
295 : /* XXX add password to lock password collection ? */
296 0 : memset_s(password, sizeof(password), 0, sizeof(password));
297 : }
298 0 : free(ivdata);
299 :
300 74 : } else if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
301 8 : heim_octet_string keydata;
302 :
303 74 : keydata.data = rk_UNCONST(data);
304 74 : keydata.length = len;
305 :
306 74 : ret = _hx509_collector_private_key_add(context, c, ai, NULL,
307 : &keydata, NULL);
308 : }
309 :
310 66 : return ret;
311 : }
312 :
313 :
314 : struct pem_formats {
315 : const char *name;
316 : int (*func)(hx509_context, const char *, int, struct hx509_collector *,
317 : const hx509_pem_header *, const void *, size_t,
318 : const AlgorithmIdentifier *);
319 : const AlgorithmIdentifier *(*ai)(void);
320 : } formats[] = {
321 : { "CERTIFICATE", parse_certificate, NULL },
322 : { "PRIVATE KEY", parse_pkcs8_private_key, NULL },
323 : { "RSA PRIVATE KEY", parse_pem_private_key, hx509_signature_rsa },
324 : #ifdef HAVE_HCRYPTO_W_OPENSSL
325 : { "EC PRIVATE KEY", parse_pem_private_key, hx509_signature_ecPublicKey }
326 : #endif
327 : };
328 :
329 :
330 : struct pem_ctx {
331 : int flags;
332 : struct hx509_collector *c;
333 : };
334 :
335 : static int
336 323 : pem_func(hx509_context context, const char *type,
337 : const hx509_pem_header *header,
338 : const void *data, size_t len, void *ctx)
339 : {
340 323 : struct pem_ctx *pem_ctx = (struct pem_ctx*)ctx;
341 323 : int ret = 0;
342 24 : size_t j;
343 :
344 471 : for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
345 471 : const char *q = formats[j].name;
346 471 : if (strcasecmp(type, q) == 0) {
347 323 : const AlgorithmIdentifier *ai = NULL;
348 :
349 323 : if (formats[j].ai != NULL)
350 74 : ai = (*formats[j].ai)();
351 :
352 323 : ret = (*formats[j].func)(context, NULL, pem_ctx->flags, pem_ctx->c,
353 : header, data, len, ai);
354 323 : if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL)) {
355 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
356 : "Failed parseing PEM format %s", type);
357 0 : return ret;
358 : }
359 299 : break;
360 : }
361 : }
362 323 : if (j == sizeof(formats)/sizeof(formats[0])) {
363 0 : ret = HX509_UNSUPPORTED_OPERATION;
364 0 : hx509_set_error_string(context, 0, ret,
365 : "Found no matching PEM format for %s", type);
366 0 : return ret;
367 : }
368 299 : return 0;
369 : }
370 :
371 : /*
372 : *
373 : */
374 :
375 : static int
376 288 : file_init_common(hx509_context context,
377 : hx509_certs certs, void **data, int flags,
378 : const char *residue, hx509_lock lock, outformat format)
379 : {
380 16 : char *p, *pnext;
381 288 : struct ks_file *ksf = NULL;
382 288 : hx509_private_key *keys = NULL;
383 16 : int ret;
384 16 : struct pem_ctx pem_ctx;
385 :
386 288 : pem_ctx.flags = flags;
387 288 : pem_ctx.c = NULL;
388 :
389 288 : if (residue == NULL || residue[0] == '\0') {
390 0 : hx509_set_error_string(context, 0, EINVAL,
391 : "PEM file name not specified");
392 0 : return EINVAL;
393 : }
394 :
395 288 : *data = NULL;
396 :
397 288 : if (lock == NULL)
398 175 : lock = _hx509_empty_lock;
399 :
400 288 : ksf = calloc(1, sizeof(*ksf));
401 288 : if (ksf == NULL) {
402 0 : hx509_clear_error_string(context);
403 0 : return ENOMEM;
404 : }
405 288 : ksf->format = format;
406 :
407 288 : ksf->fn = strdup(residue);
408 288 : if (ksf->fn == NULL) {
409 0 : hx509_clear_error_string(context);
410 0 : ret = ENOMEM;
411 0 : goto out;
412 : }
413 :
414 : /*
415 : * XXX this is broken, the function should parse the file before
416 : * overwriting it
417 : */
418 :
419 288 : if (flags & HX509_CERTS_CREATE) {
420 : /*
421 : * Note that the file creation is deferred until file_store() is
422 : * called.
423 : */
424 0 : ret = hx509_certs_init(context, "MEMORY:ks-file-create",
425 : 0, lock, &ksf->certs);
426 0 : if (ret)
427 0 : goto out;
428 0 : *data = ksf;
429 0 : return 0;
430 : }
431 :
432 288 : ret = _hx509_collector_alloc(context, lock, &pem_ctx.c);
433 288 : if (ret)
434 0 : goto out;
435 :
436 611 : for (p = ksf->fn; p != NULL; p = pnext) {
437 24 : FILE *f;
438 :
439 362 : pnext = strchr(p, ',');
440 362 : if (pnext)
441 113 : *pnext++ = '\0';
442 :
443 :
444 362 : if ((f = fopen(p, "r")) == NULL) {
445 39 : ret = ENOENT;
446 39 : hx509_set_error_string(context, 0, ret,
447 : "Failed to open PEM file \"%s\": %s",
448 39 : p, strerror(errno));
449 39 : goto out;
450 : }
451 323 : rk_cloexec_file(f);
452 :
453 323 : ret = hx509_pem_read(context, f, pem_func, &pem_ctx);
454 323 : fclose(f);
455 323 : if (ret != 0 && ret != HX509_PARSING_KEY_FAILED)
456 0 : goto out;
457 323 : else if (ret == HX509_PARSING_KEY_FAILED) {
458 0 : size_t length;
459 0 : void *ptr;
460 0 : size_t i;
461 :
462 0 : ret = rk_undumpdata(p, &ptr, &length);
463 0 : if (ret) {
464 0 : hx509_clear_error_string(context);
465 0 : goto out;
466 : }
467 :
468 0 : for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
469 0 : const AlgorithmIdentifier *ai = NULL;
470 :
471 0 : if (formats[i].ai != NULL)
472 0 : ai = (*formats[i].ai)();
473 :
474 0 : ret = (*formats[i].func)(context, p, pem_ctx.flags, pem_ctx.c,
475 : NULL, ptr, length, ai);
476 0 : if (ret == 0)
477 0 : break;
478 : }
479 0 : rk_xfree(ptr);
480 0 : if (ret) {
481 0 : hx509_clear_error_string(context);
482 0 : goto out;
483 : }
484 : }
485 : }
486 :
487 249 : ret = _hx509_collector_collect_certs(context, pem_ctx.c, &ksf->certs);
488 249 : if (ret)
489 0 : goto out;
490 :
491 249 : ret = _hx509_collector_collect_private_keys(context, pem_ctx.c, &keys);
492 249 : if (ret == 0) {
493 : int i;
494 :
495 323 : for (i = 0; keys[i]; i++)
496 74 : _hx509_certs_keys_add(context, ksf->certs, keys[i]);
497 249 : _hx509_certs_keys_free(context, keys);
498 : }
499 :
500 0 : out:
501 288 : if (ret == 0)
502 249 : *data = ksf;
503 : else {
504 39 : if (ksf->fn)
505 39 : free(ksf->fn);
506 39 : free(ksf);
507 : }
508 288 : if (pem_ctx.c)
509 288 : _hx509_collector_free(pem_ctx.c);
510 :
511 272 : return ret;
512 : }
513 :
514 : static int
515 288 : file_init_pem(hx509_context context,
516 : hx509_certs certs, void **data, int flags,
517 : const char *residue, hx509_lock lock)
518 : {
519 288 : return file_init_common(context, certs, data, flags, residue, lock, USE_PEM);
520 : }
521 :
522 : static int
523 0 : file_init_der(hx509_context context,
524 : hx509_certs certs, void **data, int flags,
525 : const char *residue, hx509_lock lock)
526 : {
527 0 : return file_init_common(context, certs, data, flags, residue, lock, USE_DER);
528 : }
529 :
530 : static int
531 141 : file_free(hx509_certs certs, void *data)
532 : {
533 141 : struct ks_file *ksf = data;
534 141 : hx509_certs_free(&ksf->certs);
535 141 : free(ksf->fn);
536 141 : free(ksf);
537 141 : return 0;
538 : }
539 :
540 : struct store_ctx {
541 : FILE *f;
542 : outformat format;
543 : int store_flags;
544 : };
545 :
546 : static int HX509_LIB_CALL
547 0 : store_func(hx509_context context, void *ctx, hx509_cert c)
548 : {
549 0 : struct store_ctx *sc = ctx;
550 0 : heim_octet_string data;
551 0 : int ret = 0;
552 :
553 0 : if ((sc->store_flags & HX509_CERTS_STORE_NO_ROOTS)) {
554 0 : int self_signed = 0;
555 :
556 0 : ret = hx509_cert_is_self_signed(context, c, &self_signed);
557 0 : if (ret || self_signed)
558 0 : return ret;
559 : }
560 :
561 0 : if (hx509_cert_have_private_key_only(c)) {
562 0 : data.length = 0;
563 0 : data.data = NULL;
564 : } else {
565 0 : ret = hx509_cert_binary(context, c, &data);
566 0 : if (ret)
567 0 : return ret;
568 : }
569 :
570 0 : switch (sc->format) {
571 0 : case USE_DER:
572 : /* Can't store both. Well, we could, but nothing will support it */
573 0 : if (data.data) {
574 0 : fwrite(data.data, data.length, 1, sc->f);
575 0 : } else if (_hx509_cert_private_key_exportable(c) &&
576 0 : !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
577 0 : hx509_private_key key = _hx509_cert_private_key(c);
578 :
579 0 : free(data.data);
580 0 : data.length = 0;
581 0 : data.data = NULL;
582 0 : ret = _hx509_private_key_export(context, key,
583 : HX509_KEY_FORMAT_DER, &data);
584 0 : if (ret == 0 && data.length)
585 0 : fwrite(data.data, data.length, 1, sc->f);
586 : }
587 0 : break;
588 0 : case USE_PEM:
589 0 : if (_hx509_cert_private_key_exportable(c) &&
590 0 : !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
591 0 : heim_octet_string priv_key;
592 0 : hx509_private_key key = _hx509_cert_private_key(c);
593 :
594 0 : ret = _hx509_private_key_export(context, key,
595 : HX509_KEY_FORMAT_DER, &priv_key);
596 0 : if (ret == 0)
597 0 : ret = hx509_pem_write(context, _hx509_private_pem_name(key), NULL,
598 0 : sc->f, priv_key.data, priv_key.length);
599 0 : free(priv_key.data);
600 : }
601 0 : if (ret == 0 && data.data) {
602 0 : ret = hx509_pem_write(context, "CERTIFICATE", NULL, sc->f,
603 0 : data.data, data.length);
604 : }
605 0 : break;
606 : }
607 :
608 0 : free(data.data);
609 0 : return ret;
610 : }
611 :
612 : static int
613 0 : mk_temp(const char *fn, char **tfn)
614 : {
615 0 : char *ds;
616 0 : int ret = -1;
617 :
618 : #ifdef WIN32
619 : char buf[PATH_MAX];
620 : char *p;
621 :
622 : *tfn = NULL;
623 :
624 : if ((ds = _fullpath(buf, fn, sizeof(buf))) == NULL) {
625 : errno = errno ? errno : ENAMETOOLONG;
626 : return -1;
627 : }
628 :
629 : if ((p = strrchr(ds, '\\')) == NULL) {
630 : ret = asprintf(tfn, ".%s-XXXXXX", ds); /* XXX can't happen */
631 : } else {
632 : *(p++) = '\0';
633 : ret = asprintf(tfn, "%s/.%s-XXXXXX", ds, p);
634 : }
635 : #else
636 0 : *tfn = NULL;
637 0 : if ((ds = strdup(fn)))
638 0 : ret = asprintf(tfn, "%s/.%s-XXXXXX", dirname(ds), basename(ds));
639 0 : free(ds);
640 : #endif
641 :
642 : /*
643 : * Using mkostemp() risks leaving garbage files lying around. To do better
644 : * without resorting to file locks (which have their own problems) we need
645 : * O_TMPFILE and linkat(2), which only Linux has.
646 : */
647 0 : return (ret == -1 || *tfn == NULL) ? -1 : mkostemp(*tfn, O_CLOEXEC);
648 : }
649 :
650 : static int
651 0 : file_store(hx509_context context,
652 : hx509_certs certs, void *data, int flags, hx509_lock lock)
653 : {
654 0 : struct ks_file *ksf = data;
655 0 : struct store_ctx sc;
656 0 : char *tfn;
657 0 : int ret;
658 0 : int fd;
659 :
660 0 : sc.f = NULL;
661 0 : fd = mk_temp(ksf->fn, &tfn);
662 0 : if (fd > -1)
663 0 : sc.f = fdopen(fd, "w");
664 0 : if (sc.f == NULL) {
665 0 : hx509_set_error_string(context, 0, ret = errno,
666 : "Failed to open file %s for writing", ksf->fn);
667 0 : if (fd > -1)
668 0 : (void) close(fd);
669 0 : return ret;
670 : }
671 0 : rk_cloexec_file(sc.f);
672 0 : sc.store_flags = flags;
673 0 : sc.format = ksf->format;
674 :
675 0 : ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc);
676 0 : if (ret == 0)
677 0 : ret = fclose(sc.f);
678 : else
679 0 : (void) fclose(sc.f);
680 0 : if (ret)
681 0 : (void) unlink(tfn);
682 : else
683 0 : (void) rename(tfn, ksf->fn);
684 0 : free(tfn);
685 0 : return ret;
686 : }
687 :
688 : static int
689 0 : file_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
690 : {
691 0 : struct ks_file *ksf = data;
692 0 : return hx509_certs_add(context, ksf->certs, c);
693 : }
694 :
695 : static int
696 395 : file_iter_start(hx509_context context,
697 : hx509_certs certs, void *data, void **cursor)
698 : {
699 395 : struct ks_file *ksf = data;
700 395 : return hx509_certs_start_seq(context, ksf->certs, cursor);
701 : }
702 :
703 : static int
704 645 : file_iter(hx509_context context,
705 : hx509_certs certs, void *data, void *iter, hx509_cert *cert)
706 : {
707 645 : struct ks_file *ksf = data;
708 645 : return hx509_certs_next_cert(context, ksf->certs, iter, cert);
709 : }
710 :
711 : static int
712 395 : file_iter_end(hx509_context context,
713 : hx509_certs certs,
714 : void *data,
715 : void *cursor)
716 : {
717 395 : struct ks_file *ksf = data;
718 395 : return hx509_certs_end_seq(context, ksf->certs, cursor);
719 : }
720 :
721 : static int
722 0 : file_getkeys(hx509_context context,
723 : hx509_certs certs,
724 : void *data,
725 : hx509_private_key **keys)
726 : {
727 0 : struct ks_file *ksf = data;
728 0 : return _hx509_certs_keys_get(context, ksf->certs, keys);
729 : }
730 :
731 : static int
732 0 : file_addkey(hx509_context context,
733 : hx509_certs certs,
734 : void *data,
735 : hx509_private_key key)
736 : {
737 0 : struct ks_file *ksf = data;
738 0 : return _hx509_certs_keys_add(context, ksf->certs, key);
739 : }
740 :
741 : static int
742 0 : file_destroy(hx509_context context,
743 : hx509_certs certs,
744 : void *data)
745 : {
746 0 : struct ks_file *ksf = data;
747 0 : return _hx509_erase_file(context, ksf->fn);
748 : }
749 :
750 : static struct hx509_keyset_ops keyset_file = {
751 : "FILE",
752 : 0,
753 : file_init_pem,
754 : file_store,
755 : file_free,
756 : file_add,
757 : NULL,
758 : file_iter_start,
759 : file_iter,
760 : file_iter_end,
761 : NULL,
762 : file_getkeys,
763 : file_addkey,
764 : file_destroy
765 : };
766 :
767 : static struct hx509_keyset_ops keyset_pemfile = {
768 : "PEM-FILE",
769 : 0,
770 : file_init_pem,
771 : file_store,
772 : file_free,
773 : file_add,
774 : NULL,
775 : file_iter_start,
776 : file_iter,
777 : file_iter_end,
778 : NULL,
779 : file_getkeys,
780 : file_addkey,
781 : file_destroy
782 : };
783 :
784 : static struct hx509_keyset_ops keyset_derfile = {
785 : "DER-FILE",
786 : 0,
787 : file_init_der,
788 : file_store,
789 : file_free,
790 : file_add,
791 : NULL,
792 : file_iter_start,
793 : file_iter,
794 : file_iter_end,
795 : NULL,
796 : file_getkeys,
797 : file_addkey,
798 : file_destroy
799 : };
800 :
801 :
802 : HX509_LIB_FUNCTION void HX509_LIB_CALL
803 792004 : _hx509_ks_file_register(hx509_context context)
804 : {
805 792004 : _hx509_ks_register(context, &keyset_file);
806 792004 : _hx509_ks_register(context, &keyset_pemfile);
807 792004 : _hx509_ks_register(context, &keyset_derfile);
808 792004 : }
|