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
37 typedef enum { USE_PEM
, USE_DER
} outformat
;
50 parse_certificate(hx509_context context
, const char *fn
,
51 struct hx509_collector
*c
,
52 const hx509_pem_header
*headers
,
53 const void *data
, size_t len
)
58 ret
= hx509_cert_init_data(context
, data
, len
, &cert
);
62 ret
= _hx509_collector_certs_add(context
, c
, cert
);
63 hx509_cert_free(cert
);
68 try_decrypt(hx509_context context
,
69 struct hx509_collector
*collector
,
70 const AlgorithmIdentifier
*alg
,
78 heim_octet_string clear
;
83 keylen
= EVP_CIPHER_key_length(c
);
87 hx509_clear_error_string(context
);
91 ret
= EVP_BytesToKey(c
, EVP_md5(), ivdata
,
92 password
, passwordlen
,
95 hx509_set_error_string(context
, 0, HX509_CRYPTO_INTERNAL_ERROR
,
96 "Failed to do string2key for private key");
97 return HX509_CRYPTO_INTERNAL_ERROR
;
100 clear
.data
= malloc(len
);
101 if (clear
.data
== NULL
) {
102 hx509_set_error_string(context
, 0, ENOMEM
,
103 "Out of memory to decrypt for private key");
111 EVP_CIPHER_CTX_init(&ctx
);
112 EVP_CipherInit_ex(&ctx
, c
, NULL
, key
, ivdata
, 0);
113 EVP_Cipher(&ctx
, clear
.data
, cipher
, len
);
114 EVP_CIPHER_CTX_cleanup(&ctx
);
117 ret
= _hx509_collector_private_key_add(context
,
124 memset(clear
.data
, 0, clear
.length
);
127 memset(key
, 0, keylen
);
133 parse_rsa_private_key(hx509_context context
, const char *fn
,
134 struct hx509_collector
*c
,
135 const hx509_pem_header
*headers
,
136 const void *data
, size_t len
)
141 enc
= hx509_pem_find_header(headers
, "Proc-Type");
147 const EVP_CIPHER
*cipher
;
148 const struct _hx509_password
*pw
;
150 int i
, decrypted
= 0;
152 lock
= _hx509_collector_get_lock(c
);
154 hx509_set_error_string(context
, 0, HX509_ALG_NOT_SUPP
,
155 "Failed to get password for "
156 "password protected file %s", fn
);
157 return HX509_ALG_NOT_SUPP
;
160 if (strcmp(enc
, "4,ENCRYPTED") != 0) {
161 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
162 "RSA key encrypted in unknown method %s "
165 hx509_clear_error_string(context
);
166 return HX509_PARSING_KEY_FAILED
;
169 dek
= hx509_pem_find_header(headers
, "DEK-Info");
171 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
172 "Encrypted RSA missing DEK-Info");
173 return HX509_PARSING_KEY_FAILED
;
178 hx509_clear_error_string(context
);
182 iv
= strchr(type
, ',');
185 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
187 return HX509_PARSING_KEY_FAILED
;
193 ivdata
= malloc(size
);
194 if (ivdata
== NULL
) {
195 hx509_clear_error_string(context
);
200 cipher
= EVP_get_cipherbyname(type
);
201 if (cipher
== NULL
) {
203 hx509_set_error_string(context
, 0, HX509_ALG_NOT_SUPP
,
204 "RSA key encrypted with "
205 "unsupported cipher: %s",
208 return HX509_ALG_NOT_SUPP
;
211 #define PKCS5_SALT_LEN 8
213 ssize
= hex_decode(iv
, ivdata
, size
);
218 if (ssize
< 0 || ssize
< PKCS5_SALT_LEN
|| ssize
< EVP_CIPHER_iv_length(cipher
)) {
220 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
221 "Salt have wrong length in RSA key file");
222 return HX509_PARSING_KEY_FAILED
;
225 pw
= _hx509_lock_get_passwords(lock
);
227 const void *password
;
230 for (i
= 0; i
< pw
->len
; i
++) {
231 password
= pw
->val
[i
];
232 passwordlen
= strlen(password
);
234 ret
= try_decrypt(context
, c
, hx509_signature_rsa(),
235 cipher
, ivdata
, password
, passwordlen
,
247 memset(&prompt
, 0, sizeof(prompt
));
249 prompt
.prompt
= "Password for keyfile: ";
250 prompt
.type
= HX509_PROMPT_TYPE_PASSWORD
;
251 prompt
.reply
.data
= password
;
252 prompt
.reply
.length
= sizeof(password
);
254 ret
= hx509_lock_prompt(lock
, &prompt
);
256 ret
= try_decrypt(context
, c
, hx509_signature_rsa(),
257 cipher
, ivdata
, password
, strlen(password
),
259 /* XXX add password to lock password collection ? */
260 memset(password
, 0, sizeof(password
));
265 heim_octet_string keydata
;
267 keydata
.data
= rk_UNCONST(data
);
268 keydata
.length
= len
;
270 ret
= _hx509_collector_private_key_add(context
,
272 hx509_signature_rsa(),
284 int (*func
)(hx509_context
, const char *, struct hx509_collector
*,
285 const hx509_pem_header
*, const void *, size_t);
287 { "CERTIFICATE", parse_certificate
},
288 { "RSA PRIVATE KEY", parse_rsa_private_key
}
294 struct hx509_collector
*c
;
298 pem_func(hx509_context context
, const char *type
,
299 const hx509_pem_header
*header
,
300 const void *data
, size_t len
, void *ctx
)
302 struct pem_ctx
*pem_ctx
= (struct pem_ctx
*)ctx
;
305 for (j
= 0; j
< sizeof(formats
)/sizeof(formats
[0]); j
++) {
306 const char *q
= formats
[j
].name
;
307 if (strcasecmp(type
, q
) == 0) {
308 ret
= (*formats
[j
].func
)(context
, NULL
, pem_ctx
->c
, header
, data
, len
);
313 if (j
== sizeof(formats
)/sizeof(formats
[0])) {
314 ret
= HX509_UNSUPPORTED_OPERATION
;
315 hx509_set_error_string(context
, 0, ret
,
316 "Found no matching PEM format for %s", type
);
319 if (ret
&& (pem_ctx
->flags
& HX509_CERTS_UNPROTECT_ALL
))
329 file_init_common(hx509_context context
,
330 hx509_certs certs
, void **data
, int flags
,
331 const char *residue
, hx509_lock lock
, outformat format
)
334 struct ks_file
*f
= NULL
;
335 hx509_private_key
*keys
= NULL
;
337 struct pem_ctx pem_ctx
;
339 pem_ctx
.flags
= flags
;
345 lock
= _hx509_empty_lock
;
347 f
= calloc(1, sizeof(*f
));
349 hx509_clear_error_string(context
);
354 f
->fn
= strdup(residue
);
356 hx509_clear_error_string(context
);
362 * XXX this is broken, the function should parse the file before
366 if (flags
& HX509_CERTS_CREATE
) {
367 ret
= hx509_certs_init(context
, "MEMORY:ks-file-create",
375 ret
= _hx509_collector_alloc(context
, lock
, &pem_ctx
.c
);
379 for (p
= f
->fn
; p
!= NULL
; p
= pnext
) {
382 pnext
= strchr(p
, ',');
387 if ((f
= fopen(p
, "r")) == NULL
) {
389 hx509_set_error_string(context
, 0, ret
,
390 "Failed to open PEM file \"%s\": %s",
395 ret
= hx509_pem_read(context
, f
, pem_func
, &pem_ctx
);
397 if (ret
!= 0 && ret
!= HX509_PARSING_KEY_FAILED
)
399 else if (ret
== HX509_PARSING_KEY_FAILED
) {
404 ret
= _hx509_map_file(p
, &ptr
, &length
, NULL
);
406 hx509_clear_error_string(context
);
410 for (i
= 0; i
< sizeof(formats
)/sizeof(formats
[0]); i
++) {
411 ret
= (*formats
[i
].func
)(context
, p
, pem_ctx
.c
, NULL
, ptr
, length
);
415 _hx509_unmap_file(ptr
, length
);
421 ret
= _hx509_collector_collect_certs(context
, pem_ctx
.c
, &f
->certs
);
425 ret
= _hx509_collector_collect_private_keys(context
, pem_ctx
.c
, &keys
);
429 for (i
= 0; keys
[i
]; i
++)
430 _hx509_certs_keys_add(context
, f
->certs
, keys
[i
]);
431 _hx509_certs_keys_free(context
, keys
);
443 _hx509_collector_free(pem_ctx
.c
);
449 file_init_pem(hx509_context context
,
450 hx509_certs certs
, void **data
, int flags
,
451 const char *residue
, hx509_lock lock
)
453 return file_init_common(context
, certs
, data
, flags
, residue
, lock
, USE_PEM
);
457 file_init_der(hx509_context context
,
458 hx509_certs certs
, void **data
, int flags
,
459 const char *residue
, hx509_lock lock
)
461 return file_init_common(context
, certs
, data
, flags
, residue
, lock
, USE_DER
);
465 file_free(hx509_certs certs
, void *data
)
467 struct ks_file
*f
= data
;
468 hx509_certs_free(&f
->certs
);
480 store_func(hx509_context context
, void *ctx
, hx509_cert c
)
482 struct store_ctx
*sc
= ctx
;
483 heim_octet_string data
;
486 ret
= hx509_cert_binary(context
, c
, &data
);
490 switch (sc
->format
) {
492 fwrite(data
.data
, data
.length
, 1, sc
->f
);
496 hx509_pem_write(context
, "CERTIFICATE", NULL
, sc
->f
,
497 data
.data
, data
.length
);
499 if (_hx509_cert_private_key_exportable(c
)) {
500 hx509_private_key key
= _hx509_cert_private_key(c
);
501 ret
= _hx509_private_key_export(context
, key
, &data
);
504 hx509_pem_write(context
, _hx509_private_pem_name(key
), NULL
, sc
->f
,
505 data
.data
, data
.length
);
515 file_store(hx509_context context
,
516 hx509_certs certs
, void *data
, int flags
, hx509_lock lock
)
518 struct ks_file
*f
= data
;
522 sc
.f
= fopen(f
->fn
, "w");
524 hx509_set_error_string(context
, 0, ENOENT
,
525 "Failed to open file %s for writing");
528 sc
.format
= f
->format
;
530 ret
= hx509_certs_iter(context
, f
->certs
, store_func
, &sc
);
536 file_add(hx509_context context
, hx509_certs certs
, void *data
, hx509_cert c
)
538 struct ks_file
*f
= data
;
539 return hx509_certs_add(context
, f
->certs
, c
);
543 file_iter_start(hx509_context context
,
544 hx509_certs certs
, void *data
, void **cursor
)
546 struct ks_file
*f
= data
;
547 return hx509_certs_start_seq(context
, f
->certs
, cursor
);
551 file_iter(hx509_context context
,
552 hx509_certs certs
, void *data
, void *iter
, hx509_cert
*cert
)
554 struct ks_file
*f
= data
;
555 return hx509_certs_next_cert(context
, f
->certs
, iter
, cert
);
559 file_iter_end(hx509_context context
,
564 struct ks_file
*f
= data
;
565 return hx509_certs_end_seq(context
, f
->certs
, cursor
);
569 file_getkeys(hx509_context context
,
572 hx509_private_key
**keys
)
574 struct ks_file
*f
= data
;
575 return _hx509_certs_keys_get(context
, f
->certs
, keys
);
579 file_addkey(hx509_context context
,
582 hx509_private_key key
)
584 struct ks_file
*f
= data
;
585 return _hx509_certs_keys_add(context
, f
->certs
, key
);
588 static struct hx509_keyset_ops keyset_file
= {
604 static struct hx509_keyset_ops keyset_pemfile
= {
620 static struct hx509_keyset_ops keyset_derfile
= {
638 _hx509_ks_file_register(hx509_context context
)
640 _hx509_ks_register(context
, &keyset_file
);
641 _hx509_ks_register(context
, &keyset_pemfile
);
642 _hx509_ks_register(context
, &keyset_derfile
);