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