r20640: Commit part 2/2
[metze/samba/wip.git] / source4 / heimdal / lib / hx509 / ks_p12.c
1 /*
2  * Copyright (c) 2004 - 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 RCSID("$Id: ks_p12.c,v 1.18 2007/01/09 10:52:11 lha Exp $");
36
37 struct ks_pkcs12 {
38     hx509_certs certs;
39     char *fn;
40 };
41
42 typedef int (*collector_func)(hx509_context,
43                               struct hx509_collector *,
44                               const void *, size_t,
45                               const PKCS12_Attributes *);
46
47 struct type {
48     const heim_oid * (*oid)(void);
49     collector_func func;
50 };
51
52 static void
53 parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *, 
54                   const void *, size_t, const PKCS12_Attributes *);
55
56
57 static const PKCS12_Attribute *
58 find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
59 {
60     int i;
61     if (attrs == NULL)
62         return NULL;
63     for (i = 0; i < attrs->len; i++)
64         if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)
65             return &attrs->val[i];
66     return NULL;
67 }
68
69 static int
70 keyBag_parser(hx509_context context,
71               struct hx509_collector *c, 
72               const void *data, size_t length,
73               const PKCS12_Attributes *attrs)
74 {
75     const PKCS12_Attribute *attr;
76     PKCS8PrivateKeyInfo ki;
77     const heim_octet_string *os = NULL;
78     int ret;
79
80     attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId());
81     if (attr)
82         os = &attr->attrValues;
83
84     ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
85     if (ret)
86         return ret;
87     
88     _hx509_collector_private_key_add(context,
89                                      c,
90                                      &ki.privateKeyAlgorithm,
91                                      NULL,
92                                      &ki.privateKey,
93                                      &attr->attrValues);
94     free_PKCS8PrivateKeyInfo(&ki);
95     return 0;
96 }
97
98 static int
99 ShroudedKeyBag_parser(hx509_context context,
100                       struct hx509_collector *c, 
101                       const void *data, size_t length,
102                       const PKCS12_Attributes *attrs)
103 {
104     PKCS8EncryptedPrivateKeyInfo pk;
105     heim_octet_string content;
106     int ret;
107     
108     memset(&pk, 0, sizeof(pk));
109     
110     ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);
111     if (ret)
112         return ret;
113
114     ret = _hx509_pbe_decrypt(context,
115                              _hx509_collector_get_lock(c),
116                              &pk.encryptionAlgorithm,
117                              &pk.encryptedData,
118                              &content);
119     free_PKCS8EncryptedPrivateKeyInfo(&pk);
120     if (ret)
121         return ret;
122
123     ret = keyBag_parser(context, c, content.data, content.length, attrs);
124     der_free_octet_string(&content);
125     return ret;
126 }
127
128 static int
129 certBag_parser(hx509_context context,
130                struct hx509_collector *c, 
131                const void *data, size_t length,
132                const PKCS12_Attributes *attrs)
133 {
134     heim_octet_string os;
135     Certificate t;
136     hx509_cert cert;
137     PKCS12_CertBag cb;
138     int ret;
139
140     ret = decode_PKCS12_CertBag(data, length, &cb, NULL);
141     if (ret)
142         return ret;
143
144     if (der_heim_oid_cmp(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType)) {
145         free_PKCS12_CertBag(&cb);
146         return 0;
147     }
148
149     ret = decode_PKCS12_OctetString(cb.certValue.data, 
150                                     cb.certValue.length,
151                                     &os,
152                                     NULL);
153     free_PKCS12_CertBag(&cb);
154     if (ret)
155         return ret;
156
157     ret = decode_Certificate(os.data, os.length, &t, NULL);
158     der_free_octet_string(&os);
159     if (ret)
160         return ret;
161
162     ret = hx509_cert_init(context, &t, &cert);
163     free_Certificate(&t);
164     if (ret)
165         return ret;
166
167     ret = _hx509_collector_certs_add(context, c, cert);
168     if (ret) {
169         hx509_cert_free(cert);
170         return ret;
171     }
172
173     {
174         const PKCS12_Attribute *attr;
175         const heim_oid * (*oids[])(void) = {
176             oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName
177         };
178         int i;
179
180         for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {
181             const heim_oid *oid = (*(oids[i]))();
182             attr = find_attribute(attrs, oid);
183             if (attr)
184                 _hx509_set_cert_attribute(context, cert, oid,
185                                           &attr->attrValues);
186         }       
187     }
188
189     hx509_cert_free(cert);
190
191     return 0;
192 }
193
194 static int
195 parse_safe_content(hx509_context context,
196                    struct hx509_collector *c, 
197                    const unsigned char *p, size_t len)
198 {
199     PKCS12_SafeContents sc;
200     int ret, i;
201
202     memset(&sc, 0, sizeof(sc));
203
204     ret = decode_PKCS12_SafeContents(p, len, &sc, NULL);
205     if (ret)
206         return ret;
207
208     for (i = 0; i < sc.len ; i++)
209         parse_pkcs12_type(context,
210                           c,
211                           &sc.val[i].bagId,
212                           sc.val[i].bagValue.data,
213                           sc.val[i].bagValue.length,
214                           sc.val[i].bagAttributes);
215
216     free_PKCS12_SafeContents(&sc);
217     return 0;
218 }
219
220 static int
221 safeContent_parser(hx509_context context,
222                    struct hx509_collector *c, 
223                    const void *data, size_t length,
224                    const PKCS12_Attributes *attrs)
225 {
226     heim_octet_string os;
227     int ret;
228
229     ret = decode_PKCS12_OctetString(data, length, &os, NULL);
230     if (ret)
231         return ret;
232     ret = parse_safe_content(context, c, os.data, os.length);
233     der_free_octet_string(&os);
234     return ret;
235 }
236
237 static int
238 encryptedData_parser(hx509_context context,
239                      struct hx509_collector *c,
240                      const void *data, size_t length,
241                      const PKCS12_Attributes *attrs)
242 {
243     heim_octet_string content;
244     heim_oid contentType;
245     int ret;
246                 
247     memset(&contentType, 0, sizeof(contentType));
248
249     ret = hx509_cms_decrypt_encrypted(context,
250                                       _hx509_collector_get_lock(c),
251                                       data, length,
252                                       &contentType,
253                                       &content);
254     if (ret)
255         return ret;
256
257     if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0)
258         ret = parse_safe_content(context, c, content.data, content.length);
259
260     der_free_octet_string(&content);
261     der_free_oid(&contentType);
262     return ret;
263 }
264
265 static int
266 envelopedData_parser(hx509_context context,
267                      struct hx509_collector *c,
268                      const void *data, size_t length,
269                      const PKCS12_Attributes *attrs)
270 {
271     heim_octet_string content;
272     heim_oid contentType;
273     hx509_lock lock;
274     int ret;
275                 
276     memset(&contentType, 0, sizeof(contentType));
277
278     lock = _hx509_collector_get_lock(c);
279
280     ret = hx509_cms_unenvelope(context,
281                                _hx509_lock_unlock_certs(lock),
282                                0,
283                                data, length,
284                                NULL,
285                                &contentType,
286                                &content);
287     if (ret) {
288         hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 
289                                "PKCS12 failed to unenvelope");
290         return ret;
291     }
292
293     if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0)
294         ret = parse_safe_content(context, c, content.data, content.length);
295
296     der_free_octet_string(&content);
297     der_free_oid(&contentType);
298
299     return ret;
300 }
301
302
303 struct type bagtypes[] = {
304     { oid_id_pkcs12_keyBag, keyBag_parser },
305     { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },
306     { oid_id_pkcs12_certBag, certBag_parser },
307     { oid_id_pkcs7_data, safeContent_parser },
308     { oid_id_pkcs7_encryptedData, encryptedData_parser },
309     { oid_id_pkcs7_envelopedData, envelopedData_parser }
310 };
311
312 static void
313 parse_pkcs12_type(hx509_context context,
314                   struct hx509_collector *c,
315                   const heim_oid *oid, 
316                   const void *data, size_t length,
317                   const PKCS12_Attributes *attrs)
318 {
319     int i;
320
321     for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
322         if (der_heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0)
323             (*bagtypes[i].func)(context, c, data, length, attrs);
324 }
325
326 static int
327 p12_init(hx509_context context,
328          hx509_certs certs, void **data, int flags, 
329          const char *residue, hx509_lock lock)
330 {
331     struct ks_pkcs12 *p12;
332     size_t len;
333     void *buf;
334     PKCS12_PFX pfx;
335     PKCS12_AuthenticatedSafe as;
336     int ret, i;
337     struct hx509_collector *c;
338
339     *data = NULL;
340
341     if (lock == NULL)
342         lock = _hx509_empty_lock;
343
344     c = _hx509_collector_alloc(context, lock);
345     if (c == NULL)
346         return ENOMEM;
347
348     p12 = calloc(1, sizeof(*p12));
349     if (p12 == NULL) {
350         ret = ENOMEM;
351         goto out;
352     }
353
354     p12->fn = strdup(residue);
355     if (p12->fn == NULL) {
356         ret = ENOMEM;
357         goto out;
358     }
359
360     if (flags & HX509_CERTS_CREATE) {
361         ret = hx509_certs_init(context, "MEMORY:ks-file-create", 
362                                0, lock, &p12->certs);
363         if (ret)
364             goto out;
365         *data = p12;
366         return 0;
367     }
368
369     ret = _hx509_map_file(residue, &buf, &len, NULL);
370     if (ret)
371         goto out;
372
373     ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);
374     _hx509_unmap_file(buf, len);
375     if (ret)
376         goto out;
377
378     if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) {
379         free_PKCS12_PFX(&pfx);
380         ret = EINVAL;
381         hx509_set_error_string(context, 0, ret,
382                                "PKCS PFX isn't a pkcs7-data container");
383         goto out;
384     }
385
386     if (pfx.authSafe.content == NULL) {
387         free_PKCS12_PFX(&pfx);
388         ret = EINVAL;
389         hx509_set_error_string(context, 0, ret,
390                                "PKCS PFX missing data");
391         goto out;
392     }
393
394     {
395         heim_octet_string asdata;
396
397         ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,
398                                         pfx.authSafe.content->length,
399                                         &asdata,
400                                         NULL);
401         free_PKCS12_PFX(&pfx);
402         if (ret) {
403             hx509_clear_error_string(context);
404             goto out;
405         }
406         ret = decode_PKCS12_AuthenticatedSafe(asdata.data, 
407                                               asdata.length,
408                                               &as,
409                                               NULL);
410         der_free_octet_string(&asdata);
411         if (ret) {
412             hx509_clear_error_string(context);
413             goto out;
414         }
415     }
416
417     for (i = 0; i < as.len; i++)
418         parse_pkcs12_type(context,
419                           c,
420                           &as.val[i].contentType,
421                           as.val[i].content->data,
422                           as.val[i].content->length,
423                           NULL);
424
425     free_PKCS12_AuthenticatedSafe(&as);
426
427     ret = _hx509_collector_collect_certs(context, c, &p12->certs);
428     if (ret == 0)
429         *data = p12;
430
431 out:
432     _hx509_collector_free(c);
433
434     if (ret) {
435         if (p12->certs)
436             hx509_certs_free(&p12->certs);
437         free(p12);
438     }
439
440     return ret;
441 }
442
443 static int
444 addBag(hx509_context context,
445        PKCS12_AuthenticatedSafe *as,
446        const heim_oid *oid,
447        void *data,
448        size_t length)
449 {
450     void *ptr;
451     int ret;
452
453     ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
454     if (ptr == NULL) {
455         hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
456         return ENOMEM;
457     }
458     as->val = ptr;
459
460     ret = der_copy_oid(oid, &as->val[as->len].contentType);
461     
462     as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
463     if (as->val[as->len].content == NULL) {
464         hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
465         return ENOMEM;
466     }
467
468     as->val[as->len].content->data = data;
469     as->val[as->len].content->length = length;
470
471     as->len++;
472
473     return 0;
474 }
475
476 static int
477 store_func(hx509_context context, void *ctx, hx509_cert c)
478 {
479     PKCS12_AuthenticatedSafe *as = ctx;
480     PKCS12_OctetString os;
481     PKCS12_CertBag cb;
482     size_t size;
483     int ret;
484
485     memset(&os, 0, sizeof(os));
486     memset(&cb, 0, sizeof(cb));
487
488     os.data = NULL;
489     os.length = 0;
490
491     ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, 
492                        _hx509_get_cert(c), &size, ret);
493     if (ret)
494         goto out;
495     ASN1_MALLOC_ENCODE(PKCS12_OctetString, 
496                        cb.certValue.data,cb.certValue.length,
497                        &os, &size, ret);
498     free(os.data);
499     if (ret)
500         goto out;
501     ret = der_copy_oid(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType);
502     if (ret) {
503         free_PKCS12_CertBag(&cb);
504         goto out;
505     }
506     ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
507                        &cb, &size, ret);
508     free(cb.certValue.data);
509     if (ret)
510         goto out;
511
512     ret = addBag(context, as, oid_id_pkcs12_certBag(), os.data, os.length);
513
514     if (_hx509_cert_private_key_exportable(c)) {
515         hx509_private_key key = _hx509_cert_private_key(c);
516         PKCS8PrivateKeyInfo pki;
517
518         memset(&pki, 0, sizeof(pki));
519
520         ret = der_parse_hex_heim_integer("00", &pki.version);
521         if (ret)
522             return ret;
523         ret = _hx509_private_key_oid(context, key, 
524                                      &pki.privateKeyAlgorithm.algorithm);
525         if (ret) {
526             free_PKCS8PrivateKeyInfo(&pki);
527             return ret;
528         }
529         ret = _hx509_private_key_export(context,
530                                         _hx509_cert_private_key(c),
531                                         &pki.privateKey);
532         if (ret) {
533             free_PKCS8PrivateKeyInfo(&pki);
534             return ret;
535         }
536         /* set attribute, oid_id_pkcs_9_at_localKeyId() */
537
538         ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
539                            &pki, &size, ret);
540         free_PKCS8PrivateKeyInfo(&pki);
541         if (ret)
542             return ret;
543
544         ret = addBag(context, as, oid_id_pkcs12_keyBag(), os.data, os.length);
545         if (ret)
546             return ret;
547     }
548
549 out:
550     return ret;
551 }
552
553 static int
554 p12_store(hx509_context context, 
555           hx509_certs certs, void *data, int flags, hx509_lock lock)
556 {
557     struct ks_pkcs12 *p12 = data;
558     PKCS12_PFX pfx;
559     PKCS12_AuthenticatedSafe as;
560     PKCS12_OctetString asdata;
561     size_t size;
562     int ret;
563
564     memset(&as, 0, sizeof(as));
565     memset(&pfx, 0, sizeof(pfx));
566
567     ret = hx509_certs_iter(context, p12->certs, store_func, &as);
568     if (ret)
569         goto out;
570
571     ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
572                        &as, &size, ret);
573     free_PKCS12_AuthenticatedSafe(&as);
574     if (ret)
575         return ret;
576                        
577     ret = der_parse_hex_heim_integer("03", &pfx.version);
578     if (ret) {
579         free(asdata.data);
580         goto out;
581     }
582
583     pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));
584
585     ASN1_MALLOC_ENCODE(PKCS12_OctetString, 
586                        pfx.authSafe.content->data,
587                        pfx.authSafe.content->length,
588                        &asdata, &size, ret);
589     free(asdata.data);
590     if (ret)
591         goto out;
592
593     ret = der_copy_oid(oid_id_pkcs7_data(), &pfx.authSafe.contentType);
594     if (ret)
595         goto out;
596
597     ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
598                        &pfx, &size, ret);
599     if (ret)
600         goto out;
601
602 #if 0
603     const struct _hx509_password *pw;
604
605     pw = _hx509_lock_get_passwords(lock);
606     if (pw != NULL) {
607         pfx.macData = calloc(1, sizeof(*pfx.macData));
608         if (pfx.macData == NULL) {
609             ret = ENOMEM;
610             hx509_set_error_string(context, 0, ret, "malloc out of memory");
611             return ret;
612         }
613         if (pfx.macData == NULL) {
614             free(asdata.data);
615             goto out;
616         }
617     }
618     ret = calculate_hash(&aspath, pw, pfx.macData);
619 #endif
620
621     rk_dumpdata(p12->fn, asdata.data, asdata.length);
622     free(asdata.data);
623
624 out:
625     free_PKCS12_AuthenticatedSafe(&as);
626     free_PKCS12_PFX(&pfx);
627
628     return ret;
629 }
630
631
632 static int
633 p12_free(hx509_certs certs, void *data)
634 {
635     struct ks_pkcs12 *p12 = data;
636     hx509_certs_free(&p12->certs);
637     free(p12->fn);
638     free(p12);
639     return 0;
640 }
641
642 static int 
643 p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
644 {
645     struct ks_pkcs12 *p12 = data;
646     return hx509_certs_add(context, p12->certs, c);
647 }
648
649 static int 
650 p12_iter_start(hx509_context context,
651                hx509_certs certs,
652                void *data,
653                void **cursor)
654 {
655     struct ks_pkcs12 *p12 = data;
656     return hx509_certs_start_seq(context, p12->certs, cursor);
657 }
658
659 static int
660 p12_iter(hx509_context context,
661          hx509_certs certs,
662          void *data,
663          void *cursor,
664          hx509_cert *cert)
665 {
666     struct ks_pkcs12 *p12 = data;
667     return hx509_certs_next_cert(context, p12->certs, cursor, cert);
668 }
669
670 static int
671 p12_iter_end(hx509_context context,
672              hx509_certs certs,
673              void *data,
674              void *cursor)
675 {
676     struct ks_pkcs12 *p12 = data;
677     return hx509_certs_end_seq(context, p12->certs, cursor);
678 }
679
680 static struct hx509_keyset_ops keyset_pkcs12 = {
681     "PKCS12",
682     0,
683     p12_init,
684     p12_store,
685     p12_free,
686     p12_add,
687     NULL,
688     p12_iter_start,
689     p12_iter,
690     p12_iter_end
691 };
692
693 void
694 _hx509_ks_pkcs12_register(hx509_context context)
695 {
696     _hx509_ks_register(context, &keyset_pkcs12);
697 }