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