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