1 /* $NetBSD: ks_file.c,v 1.1.1.2 2014/04/24 12:45:41 pettai Exp $ */
4 * Copyright (c) 2005 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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
38 typedef enum { USE_PEM
, USE_DER
} outformat
;
51 parse_certificate(hx509_context context
, const char *fn
,
52 struct hx509_collector
*c
,
53 const hx509_pem_header
*headers
,
54 const void *data
, size_t len
,
55 const AlgorithmIdentifier
*ai
)
60 ret
= hx509_cert_init_data(context
, data
, len
, &cert
);
64 ret
= _hx509_collector_certs_add(context
, c
, cert
);
65 hx509_cert_free(cert
);
70 try_decrypt(hx509_context context
,
71 struct hx509_collector
*collector
,
72 const AlgorithmIdentifier
*alg
,
80 heim_octet_string clear
;
85 keylen
= EVP_CIPHER_key_length(c
);
89 hx509_clear_error_string(context
);
93 ret
= EVP_BytesToKey(c
, EVP_md5(), ivdata
,
94 password
, passwordlen
,
97 hx509_set_error_string(context
, 0, HX509_CRYPTO_INTERNAL_ERROR
,
98 "Failed to do string2key for private key");
99 return HX509_CRYPTO_INTERNAL_ERROR
;
102 clear
.data
= malloc(len
);
103 if (clear
.data
== NULL
) {
104 hx509_set_error_string(context
, 0, ENOMEM
,
105 "Out of memory to decrypt for private key");
113 EVP_CIPHER_CTX_init(&ctx
);
114 EVP_CipherInit_ex(&ctx
, c
, NULL
, key
, ivdata
, 0);
115 EVP_Cipher(&ctx
, clear
.data
, cipher
, len
);
116 EVP_CIPHER_CTX_cleanup(&ctx
);
119 ret
= _hx509_collector_private_key_add(context
,
126 memset(clear
.data
, 0, clear
.length
);
129 memset(key
, 0, keylen
);
135 parse_pkcs8_private_key(hx509_context context
, const char *fn
,
136 struct hx509_collector
*c
,
137 const hx509_pem_header
*headers
,
138 const void *data
, size_t length
,
139 const AlgorithmIdentifier
*ai
)
141 PKCS8PrivateKeyInfo ki
;
142 heim_octet_string keydata
;
146 ret
= decode_PKCS8PrivateKeyInfo(data
, length
, &ki
, NULL
);
150 keydata
.data
= rk_UNCONST(data
);
151 keydata
.length
= length
;
153 ret
= _hx509_collector_private_key_add(context
,
155 &ki
.privateKeyAlgorithm
,
159 free_PKCS8PrivateKeyInfo(&ki
);
164 parse_pem_private_key(hx509_context context
, const char *fn
,
165 struct hx509_collector
*c
,
166 const hx509_pem_header
*headers
,
167 const void *data
, size_t len
,
168 const AlgorithmIdentifier
*ai
)
173 enc
= hx509_pem_find_header(headers
, "Proc-Type");
179 const EVP_CIPHER
*cipher
;
180 const struct _hx509_password
*pw
;
185 lock
= _hx509_collector_get_lock(c
);
187 hx509_set_error_string(context
, 0, HX509_ALG_NOT_SUPP
,
188 "Failed to get password for "
189 "password protected file %s", fn
);
190 return HX509_ALG_NOT_SUPP
;
193 if (strcmp(enc
, "4,ENCRYPTED") != 0) {
194 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
195 "Private key encrypted in unknown method %s "
198 hx509_clear_error_string(context
);
199 return HX509_PARSING_KEY_FAILED
;
202 dek
= hx509_pem_find_header(headers
, "DEK-Info");
204 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
205 "Encrypted private key missing DEK-Info");
206 return HX509_PARSING_KEY_FAILED
;
211 hx509_clear_error_string(context
);
215 iv
= strchr(type
, ',');
218 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
220 return HX509_PARSING_KEY_FAILED
;
226 ivdata
= malloc(size
);
227 if (ivdata
== NULL
) {
228 hx509_clear_error_string(context
);
233 cipher
= EVP_get_cipherbyname(type
);
234 if (cipher
== NULL
) {
236 hx509_set_error_string(context
, 0, HX509_ALG_NOT_SUPP
,
237 "Private key encrypted with "
238 "unsupported cipher: %s",
241 return HX509_ALG_NOT_SUPP
;
244 #define PKCS5_SALT_LEN 8
246 ssize
= hex_decode(iv
, ivdata
, size
);
251 if (ssize
< 0 || ssize
< PKCS5_SALT_LEN
|| ssize
< EVP_CIPHER_iv_length(cipher
)) {
253 hx509_set_error_string(context
, 0, HX509_PARSING_KEY_FAILED
,
254 "Salt have wrong length in "
256 return HX509_PARSING_KEY_FAILED
;
259 pw
= _hx509_lock_get_passwords(lock
);
261 const void *password
;
264 for (i
= 0; i
< pw
->len
; i
++) {
265 password
= pw
->val
[i
];
266 passwordlen
= strlen(password
);
268 ret
= try_decrypt(context
, c
, ai
, cipher
, ivdata
,
269 password
, passwordlen
, data
, len
);
280 memset(&prompt
, 0, sizeof(prompt
));
282 prompt
.prompt
= "Password for keyfile: ";
283 prompt
.type
= HX509_PROMPT_TYPE_PASSWORD
;
284 prompt
.reply
.data
= password
;
285 prompt
.reply
.length
= sizeof(password
);
287 ret
= hx509_lock_prompt(lock
, &prompt
);
289 ret
= try_decrypt(context
, c
, ai
, cipher
, ivdata
, password
,
290 strlen(password
), data
, len
);
291 /* XXX add password to lock password collection ? */
292 memset(password
, 0, sizeof(password
));
297 heim_octet_string keydata
;
299 keydata
.data
= rk_UNCONST(data
);
300 keydata
.length
= len
;
302 ret
= _hx509_collector_private_key_add(context
, c
, ai
, NULL
,
312 int (*func
)(hx509_context
, const char *, struct hx509_collector
*,
313 const hx509_pem_header
*, const void *, size_t,
314 const AlgorithmIdentifier
*);
315 const AlgorithmIdentifier
*(*ai
)(void);
317 { "CERTIFICATE", parse_certificate
, NULL
},
318 { "PRIVATE KEY", parse_pkcs8_private_key
, NULL
},
319 { "RSA PRIVATE KEY", parse_pem_private_key
, hx509_signature_rsa
},
320 { "EC PRIVATE KEY", parse_pem_private_key
, hx509_signature_ecPublicKey
}
326 struct hx509_collector
*c
;
330 pem_func(hx509_context context
, const char *type
,
331 const hx509_pem_header
*header
,
332 const void *data
, size_t len
, void *ctx
)
334 struct pem_ctx
*pem_ctx
= (struct pem_ctx
*)ctx
;
338 for (j
= 0; j
< sizeof(formats
)/sizeof(formats
[0]); j
++) {
339 const char *q
= formats
[j
].name
;
340 if (strcasecmp(type
, q
) == 0) {
341 const AlgorithmIdentifier
*ai
= NULL
;
342 if (formats
[j
].ai
!= NULL
)
343 ai
= (*formats
[j
].ai
)();
345 ret
= (*formats
[j
].func
)(context
, NULL
, pem_ctx
->c
,
346 header
, data
, len
, ai
);
347 if (ret
&& (pem_ctx
->flags
& HX509_CERTS_UNPROTECT_ALL
)) {
348 hx509_set_error_string(context
, HX509_ERROR_APPEND
, ret
,
349 "Failed parseing PEM format %s", type
);
355 if (j
== sizeof(formats
)/sizeof(formats
[0])) {
356 ret
= HX509_UNSUPPORTED_OPERATION
;
357 hx509_set_error_string(context
, 0, ret
,
358 "Found no matching PEM format for %s", type
);
369 file_init_common(hx509_context context
,
370 hx509_certs certs
, void **data
, int flags
,
371 const char *residue
, hx509_lock lock
, outformat format
)
374 struct ks_file
*ksf
= NULL
;
375 hx509_private_key
*keys
= NULL
;
377 struct pem_ctx pem_ctx
;
379 pem_ctx
.flags
= flags
;
385 lock
= _hx509_empty_lock
;
387 ksf
= calloc(1, sizeof(*ksf
));
389 hx509_clear_error_string(context
);
392 ksf
->format
= format
;
394 ksf
->fn
= strdup(residue
);
395 if (ksf
->fn
== NULL
) {
396 hx509_clear_error_string(context
);
402 * XXX this is broken, the function should parse the file before
406 if (flags
& HX509_CERTS_CREATE
) {
407 ret
= hx509_certs_init(context
, "MEMORY:ks-file-create",
408 0, lock
, &ksf
->certs
);
415 ret
= _hx509_collector_alloc(context
, lock
, &pem_ctx
.c
);
419 for (p
= ksf
->fn
; p
!= NULL
; p
= pnext
) {
422 pnext
= strchr(p
, ',');
427 if ((f
= fopen(p
, "r")) == NULL
) {
429 hx509_set_error_string(context
, 0, ret
,
430 "Failed to open PEM file \"%s\": %s",
436 ret
= hx509_pem_read(context
, f
, pem_func
, &pem_ctx
);
438 if (ret
!= 0 && ret
!= HX509_PARSING_KEY_FAILED
)
440 else if (ret
== HX509_PARSING_KEY_FAILED
) {
445 ret
= rk_undumpdata(p
, &ptr
, &length
);
447 hx509_clear_error_string(context
);
451 for (i
= 0; i
< sizeof(formats
)/sizeof(formats
[0]); i
++) {
452 const AlgorithmIdentifier
*ai
= NULL
;
453 if (formats
[i
].ai
!= NULL
)
454 ai
= (*formats
[i
].ai
)();
456 ret
= (*formats
[i
].func
)(context
, p
, pem_ctx
.c
, NULL
, ptr
, length
, ai
);
462 hx509_clear_error_string(context
);
468 ret
= _hx509_collector_collect_certs(context
, pem_ctx
.c
, &ksf
->certs
);
472 ret
= _hx509_collector_collect_private_keys(context
, pem_ctx
.c
, &keys
);
476 for (i
= 0; keys
[i
]; i
++)
477 _hx509_certs_keys_add(context
, ksf
->certs
, keys
[i
]);
478 _hx509_certs_keys_free(context
, keys
);
490 _hx509_collector_free(pem_ctx
.c
);
496 file_init_pem(hx509_context context
,
497 hx509_certs certs
, void **data
, int flags
,
498 const char *residue
, hx509_lock lock
)
500 return file_init_common(context
, certs
, data
, flags
, residue
, lock
, USE_PEM
);
504 file_init_der(hx509_context context
,
505 hx509_certs certs
, void **data
, int flags
,
506 const char *residue
, hx509_lock lock
)
508 return file_init_common(context
, certs
, data
, flags
, residue
, lock
, USE_DER
);
512 file_free(hx509_certs certs
, void *data
)
514 struct ks_file
*ksf
= data
;
515 hx509_certs_free(&ksf
->certs
);
527 store_func(hx509_context context
, void *ctx
, hx509_cert c
)
529 struct store_ctx
*sc
= ctx
;
530 heim_octet_string data
;
533 ret
= hx509_cert_binary(context
, c
, &data
);
537 switch (sc
->format
) {
539 fwrite(data
.data
, data
.length
, 1, sc
->f
);
543 hx509_pem_write(context
, "CERTIFICATE", NULL
, sc
->f
,
544 data
.data
, data
.length
);
546 if (_hx509_cert_private_key_exportable(c
)) {
547 hx509_private_key key
= _hx509_cert_private_key(c
);
548 ret
= _hx509_private_key_export(context
, key
,
549 HX509_KEY_FORMAT_DER
, &data
);
552 hx509_pem_write(context
, _hx509_private_pem_name(key
), NULL
, sc
->f
,
553 data
.data
, data
.length
);
563 file_store(hx509_context context
,
564 hx509_certs certs
, void *data
, int flags
, hx509_lock lock
)
566 struct ks_file
*ksf
= data
;
570 sc
.f
= fopen(ksf
->fn
, "w");
572 hx509_set_error_string(context
, 0, ENOENT
,
573 "Failed to open file %s for writing");
576 rk_cloexec_file(sc
.f
);
577 sc
.format
= ksf
->format
;
579 ret
= hx509_certs_iter_f(context
, ksf
->certs
, store_func
, &sc
);
585 file_add(hx509_context context
, hx509_certs certs
, void *data
, hx509_cert c
)
587 struct ks_file
*ksf
= data
;
588 return hx509_certs_add(context
, ksf
->certs
, c
);
592 file_iter_start(hx509_context context
,
593 hx509_certs certs
, void *data
, void **cursor
)
595 struct ks_file
*ksf
= data
;
596 return hx509_certs_start_seq(context
, ksf
->certs
, cursor
);
600 file_iter(hx509_context context
,
601 hx509_certs certs
, void *data
, void *iter
, hx509_cert
*cert
)
603 struct ks_file
*ksf
= data
;
604 return hx509_certs_next_cert(context
, ksf
->certs
, iter
, cert
);
608 file_iter_end(hx509_context context
,
613 struct ks_file
*ksf
= data
;
614 return hx509_certs_end_seq(context
, ksf
->certs
, cursor
);
618 file_getkeys(hx509_context context
,
621 hx509_private_key
**keys
)
623 struct ks_file
*ksf
= data
;
624 return _hx509_certs_keys_get(context
, ksf
->certs
, keys
);
628 file_addkey(hx509_context context
,
631 hx509_private_key key
)
633 struct ks_file
*ksf
= data
;
634 return _hx509_certs_keys_add(context
, ksf
->certs
, key
);
637 static struct hx509_keyset_ops keyset_file
= {
653 static struct hx509_keyset_ops keyset_pemfile
= {
669 static struct hx509_keyset_ops keyset_derfile
= {
687 _hx509_ks_file_register(hx509_context context
)
689 _hx509_ks_register(context
, &keyset_file
);
690 _hx509_ks_register(context
, &keyset_pemfile
);
691 _hx509_ks_register(context
, &keyset_derfile
);