2 * Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
39 typedef enum { USE_PEM
, USE_DER
} outformat
;
52 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
)
58 heim_error_t error
= NULL
;
62 cert
= hx509_cert_init_data(context
, data
, len
, &error
);
64 ret
= heim_error_get_code(error
);
69 ret
= _hx509_collector_certs_add(context
, c
, cert
);
70 hx509_cert_free(cert
);
75 try_decrypt(hx509_context context
,
76 struct hx509_collector
*collector
,
78 const AlgorithmIdentifier
*alg
,
86 heim_octet_string clear
;
91 keylen
= EVP_CIPHER_key_length(c
);
95 hx509_clear_error_string(context
);
99 ret
= EVP_BytesToKey(c
, EVP_md5(), ivdata
,
100 password
, passwordlen
,
103 ret
= HX509_CRYPTO_INTERNAL_ERROR
;
104 hx509_set_error_string(context
, 0, ret
,
105 "Failed to do string2key for private key");
109 clear
.data
= malloc(len
);
110 if (clear
.data
== NULL
) {
111 hx509_set_error_string(context
, 0, ENOMEM
,
112 "Out of memory to decrypt for private key");
120 EVP_CIPHER_CTX_init(&ctx
);
121 EVP_CipherInit_ex(&ctx
, c
, NULL
, key
, ivdata
, 0);
122 EVP_Cipher(&ctx
, clear
.data
, cipher
, len
);
123 EVP_CIPHER_CTX_cleanup(&ctx
);
126 if (!(flags
& HX509_CERTS_NO_PRIVATE_KEYS
))
127 ret
= _hx509_collector_private_key_add(context
, collector
, alg
, NULL
,
130 memset_s(clear
.data
, clear
.length
, 0, clear
.length
);
133 memset_s(key
, keylen
, 0, keylen
);
139 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
)
145 PKCS8PrivateKeyInfo ki
;
146 heim_octet_string keydata
;
149 ret
= decode_PKCS8PrivateKeyInfo(data
, length
, &ki
, NULL
);
153 if (!(flags
& HX509_CERTS_NO_PRIVATE_KEYS
)) {
154 keydata
.data
= rk_UNCONST(data
);
155 keydata
.length
= length
;
156 ret
= _hx509_collector_private_key_add(context
,
158 &ki
.privateKeyAlgorithm
,
163 free_PKCS8PrivateKeyInfo(&ki
);
168 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
)
177 enc
= hx509_pem_find_header(headers
, "Proc-Type");
183 const EVP_CIPHER
*cipher
;
184 const struct _hx509_password
*pw
;
189 lock
= _hx509_collector_get_lock(c
);
191 hx509_set_error_string(context
, 0, HX509_ALG_NOT_SUPP
,
192 "Failed to get password for "
193 "password protected file %s", fn
);
194 return HX509_ALG_NOT_SUPP
;
197 if (strcmp(enc
, "4,ENCRYPTED") != 0) {
198 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
199 "Private key encrypted in unknown method %s "
202 hx509_clear_error_string(context
);
203 return HX509_PARSING_KEY_FAILED
;
206 dek
= hx509_pem_find_header(headers
, "DEK-Info");
208 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
209 "Encrypted private key missing DEK-Info");
210 return HX509_PARSING_KEY_FAILED
;
215 hx509_clear_error_string(context
);
219 iv
= strchr(type
, ',');
222 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
224 return HX509_PARSING_KEY_FAILED
;
230 ivdata
= malloc(size
);
231 if (ivdata
== NULL
) {
232 hx509_clear_error_string(context
);
237 cipher
= EVP_get_cipherbyname(type
);
238 if (cipher
== NULL
) {
240 hx509_set_error_string(context
, 0, HX509_ALG_NOT_SUPP
,
241 "Private key encrypted with "
242 "unsupported cipher: %s",
245 return HX509_ALG_NOT_SUPP
;
248 #define PKCS5_SALT_LEN 8
250 ssize
= hex_decode(iv
, ivdata
, size
);
255 if (ssize
< 0 || ssize
< PKCS5_SALT_LEN
|| ssize
< EVP_CIPHER_iv_length(cipher
)) {
257 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
258 "Salt have wrong length in "
260 return HX509_PARSING_KEY_FAILED
;
263 pw
= _hx509_lock_get_passwords(lock
);
265 const void *password
;
268 for (i
= 0; i
< pw
->len
; i
++) {
269 password
= pw
->val
[i
];
270 passwordlen
= strlen(password
);
272 ret
= try_decrypt(context
, c
, flags
, ai
, cipher
, ivdata
,
273 password
, passwordlen
, data
, len
);
284 memset(&prompt
, 0, sizeof(prompt
));
286 prompt
.prompt
= "Password for keyfile: ";
287 prompt
.type
= HX509_PROMPT_TYPE_PASSWORD
;
288 prompt
.reply
.data
= password
;
289 prompt
.reply
.length
= sizeof(password
);
291 ret
= hx509_lock_prompt(lock
, &prompt
);
293 ret
= try_decrypt(context
, c
, flags
, ai
, cipher
, ivdata
,
294 password
, strlen(password
), data
, len
);
295 /* XXX add password to lock password collection ? */
296 memset_s(password
, sizeof(password
), 0, sizeof(password
));
300 } else if (!(flags
& HX509_CERTS_NO_PRIVATE_KEYS
)) {
301 heim_octet_string keydata
;
303 keydata
.data
= rk_UNCONST(data
);
304 keydata
.length
= len
;
306 ret
= _hx509_collector_private_key_add(context
, c
, ai
, NULL
,
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);
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
}
332 struct hx509_collector
*c
;
336 pem_func(hx509_context context
, const char *type
,
337 const hx509_pem_header
*header
,
338 const void *data
, size_t len
, void *ctx
)
340 struct pem_ctx
*pem_ctx
= (struct pem_ctx
*)ctx
;
344 for (j
= 0; j
< sizeof(formats
)/sizeof(formats
[0]); j
++) {
345 const char *q
= formats
[j
].name
;
346 if (strcasecmp(type
, q
) == 0) {
347 const AlgorithmIdentifier
*ai
= NULL
;
349 if (formats
[j
].ai
!= NULL
)
350 ai
= (*formats
[j
].ai
)();
352 ret
= (*formats
[j
].func
)(context
, NULL
, pem_ctx
->flags
, pem_ctx
->c
,
353 header
, data
, len
, ai
);
354 if (ret
&& (pem_ctx
->flags
& HX509_CERTS_UNPROTECT_ALL
)) {
355 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
356 "Failed parseing PEM format %s", type
);
362 if (j
== sizeof(formats
)/sizeof(formats
[0])) {
363 ret
= HX509_UNSUPPORTED_OPERATION
;
364 hx509_set_error_string(context
, 0, ret
,
365 "Found no matching PEM format for %s", type
);
376 file_init_common(hx509_context context
,
377 hx509_certs certs
, void **data
, int flags
,
378 const char *residue
, hx509_lock lock
, outformat format
)
381 struct ks_file
*ksf
= NULL
;
382 hx509_private_key
*keys
= NULL
;
384 struct pem_ctx pem_ctx
;
386 pem_ctx
.flags
= flags
;
389 if (residue
== NULL
|| residue
[0] == '\0') {
390 hx509_set_error_string(context
, 0, EINVAL
,
391 "PEM file name not specified");
398 lock
= _hx509_empty_lock
;
400 ksf
= calloc(1, sizeof(*ksf
));
402 hx509_clear_error_string(context
);
405 ksf
->format
= format
;
407 ksf
->fn
= strdup(residue
);
408 if (ksf
->fn
== NULL
) {
409 hx509_clear_error_string(context
);
415 * XXX this is broken, the function should parse the file before
419 if (flags
& HX509_CERTS_CREATE
) {
421 * Note that the file creation is deferred until file_store() is
424 ret
= hx509_certs_init(context
, "MEMORY:ks-file-create",
425 0, lock
, &ksf
->certs
);
432 ret
= _hx509_collector_alloc(context
, lock
, &pem_ctx
.c
);
436 for (p
= ksf
->fn
; p
!= NULL
; p
= pnext
) {
439 pnext
= strchr(p
, ',');
444 if ((f
= fopen(p
, "r")) == NULL
) {
446 hx509_set_error_string(context
, 0, ret
,
447 "Failed to open PEM file \"%s\": %s",
453 ret
= hx509_pem_read(context
, f
, pem_func
, &pem_ctx
);
455 if (ret
!= 0 && ret
!= HX509_PARSING_KEY_FAILED
)
457 else if (ret
== HX509_PARSING_KEY_FAILED
) {
462 ret
= rk_undumpdata(p
, &ptr
, &length
);
464 hx509_clear_error_string(context
);
468 for (i
= 0; i
< sizeof(formats
)/sizeof(formats
[0]); i
++) {
469 const AlgorithmIdentifier
*ai
= NULL
;
471 if (formats
[i
].ai
!= NULL
)
472 ai
= (*formats
[i
].ai
)();
474 ret
= (*formats
[i
].func
)(context
, p
, pem_ctx
.flags
, pem_ctx
.c
,
475 NULL
, ptr
, length
, ai
);
481 hx509_clear_error_string(context
);
487 ret
= _hx509_collector_collect_certs(context
, pem_ctx
.c
, &ksf
->certs
);
491 ret
= _hx509_collector_collect_private_keys(context
, pem_ctx
.c
, &keys
);
495 for (i
= 0; keys
[i
]; i
++)
496 _hx509_certs_keys_add(context
, ksf
->certs
, keys
[i
]);
497 _hx509_certs_keys_free(context
, keys
);
509 _hx509_collector_free(pem_ctx
.c
);
515 file_init_pem(hx509_context context
,
516 hx509_certs certs
, void **data
, int flags
,
517 const char *residue
, hx509_lock lock
)
519 return file_init_common(context
, certs
, data
, flags
, residue
, lock
, USE_PEM
);
523 file_init_der(hx509_context context
,
524 hx509_certs certs
, void **data
, int flags
,
525 const char *residue
, hx509_lock lock
)
527 return file_init_common(context
, certs
, data
, flags
, residue
, lock
, USE_DER
);
531 file_free(hx509_certs certs
, void *data
)
533 struct ks_file
*ksf
= data
;
534 hx509_certs_free(&ksf
->certs
);
546 static int HX509_LIB_CALL
547 store_func(hx509_context context
, void *ctx
, hx509_cert c
)
549 struct store_ctx
*sc
= ctx
;
550 heim_octet_string data
;
553 if (hx509_cert_have_private_key_only(c
)) {
557 ret
= hx509_cert_binary(context
, c
, &data
);
562 switch (sc
->format
) {
564 /* Can't store both. Well, we could, but nothing will support it */
566 fwrite(data
.data
, data
.length
, 1, sc
->f
);
567 } else if (_hx509_cert_private_key_exportable(c
) &&
568 !(sc
->store_flags
& HX509_CERTS_STORE_NO_PRIVATE_KEYS
)) {
569 hx509_private_key key
= _hx509_cert_private_key(c
);
574 ret
= _hx509_private_key_export(context
, key
,
575 HX509_KEY_FORMAT_DER
, &data
);
576 if (ret
== 0 && data
.length
)
577 fwrite(data
.data
, data
.length
, 1, sc
->f
);
581 if (_hx509_cert_private_key_exportable(c
) &&
582 !(sc
->store_flags
& HX509_CERTS_STORE_NO_PRIVATE_KEYS
)) {
583 heim_octet_string priv_key
;
584 hx509_private_key key
= _hx509_cert_private_key(c
);
586 ret
= _hx509_private_key_export(context
, key
,
587 HX509_KEY_FORMAT_DER
, &priv_key
);
589 ret
= hx509_pem_write(context
, _hx509_private_pem_name(key
), NULL
,
590 sc
->f
, priv_key
.data
, priv_key
.length
);
593 if (ret
== 0 && data
.data
) {
594 ret
= hx509_pem_write(context
, "CERTIFICATE", NULL
, sc
->f
,
595 data
.data
, data
.length
);
605 mk_temp(const char *fn
, char **tfn
)
616 if ((ds
= _fullpath(buf
, fn
, sizeof(buf
))) == NULL
) {
617 errno
= errno
? errno
: ENAMETOOLONG
;
621 if ((p
= strrchr(ds
, '\\')) == NULL
) {
622 ret
= asprintf(tfn
, ".%s-XXXXXX", ds
); /* XXX can't happen */
625 ret
= asprintf(tfn
, "%s/.%s-XXXXXX", ds
, p
);
629 if ((ds
= strdup(fn
)))
630 ret
= asprintf(tfn
, "%s/.%s-XXXXXX", dirname(ds
), basename(ds
));
635 * Using mkostemp() risks leaving garbage files lying around. To do better
636 * without resorting to file locks (which have their own problems) we need
637 * O_TMPFILE and linkat(2), which only Linux has.
639 return (ret
== -1 || *tfn
== NULL
) ? -1 : mkostemp(*tfn
, O_CLOEXEC
);
643 file_store(hx509_context context
,
644 hx509_certs certs
, void *data
, int flags
, hx509_lock lock
)
646 struct ks_file
*ksf
= data
;
653 fd
= mk_temp(ksf
->fn
, &tfn
);
655 sc
.f
= fdopen(fd
, "w");
657 hx509_set_error_string(context
, 0, ret
= errno
,
658 "Failed to open file %s for writing", ksf
->fn
);
663 rk_cloexec_file(sc
.f
);
664 sc
.store_flags
= flags
;
665 sc
.format
= ksf
->format
;
667 ret
= hx509_certs_iter_f(context
, ksf
->certs
, store_func
, &sc
);
675 (void) rename(tfn
, ksf
->fn
);
681 file_add(hx509_context context
, hx509_certs certs
, void *data
, hx509_cert c
)
683 struct ks_file
*ksf
= data
;
684 return hx509_certs_add(context
, ksf
->certs
, c
);
688 file_iter_start(hx509_context context
,
689 hx509_certs certs
, void *data
, void **cursor
)
691 struct ks_file
*ksf
= data
;
692 return hx509_certs_start_seq(context
, ksf
->certs
, cursor
);
696 file_iter(hx509_context context
,
697 hx509_certs certs
, void *data
, void *iter
, hx509_cert
*cert
)
699 struct ks_file
*ksf
= data
;
700 return hx509_certs_next_cert(context
, ksf
->certs
, iter
, cert
);
704 file_iter_end(hx509_context context
,
709 struct ks_file
*ksf
= data
;
710 return hx509_certs_end_seq(context
, ksf
->certs
, cursor
);
714 file_getkeys(hx509_context context
,
717 hx509_private_key
**keys
)
719 struct ks_file
*ksf
= data
;
720 return _hx509_certs_keys_get(context
, ksf
->certs
, keys
);
724 file_addkey(hx509_context context
,
727 hx509_private_key key
)
729 struct ks_file
*ksf
= data
;
730 return _hx509_certs_keys_add(context
, ksf
->certs
, key
);
734 file_destroy(hx509_context context
,
738 struct ks_file
*ksf
= data
;
739 return _hx509_erase_file(context
, ksf
->fn
);
742 static struct hx509_keyset_ops keyset_file
= {
759 static struct hx509_keyset_ops keyset_pemfile
= {
776 static struct hx509_keyset_ops keyset_derfile
= {
794 HX509_LIB_FUNCTION
void HX509_LIB_CALL
795 _hx509_ks_file_register(hx509_context context
)
797 _hx509_ks_register(context
, &keyset_file
);
798 _hx509_ks_register(context
, &keyset_pemfile
);
799 _hx509_ks_register(context
, &keyset_derfile
);