Fix spelling
[heimdal.git] / lib / hx509 / ks_p12.c
blob1e9a92a4ff54bef4e731af6303ad57cf0ae72589
1 /*
2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "hx_locl.h"
36 struct ks_pkcs12 {
37 hx509_certs certs;
38 char *fn;
39 unsigned int store_no_priv_keys;
42 typedef int (*collector_func)(hx509_context,
43 struct hx509_collector *,
44 int,
45 const void *, size_t,
46 const PKCS12_Attributes *);
48 struct type {
49 const heim_oid *oid;
50 collector_func func;
53 static void
54 parse_pkcs12_type(hx509_context, struct hx509_collector *, int,
55 const heim_oid *, const void *, size_t,
56 const PKCS12_Attributes *);
59 static const PKCS12_Attribute *
60 find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
62 size_t i;
63 if (attrs == NULL)
64 return NULL;
65 for (i = 0; i < attrs->len; i++)
66 if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)
67 return &attrs->val[i];
68 return NULL;
71 static int
72 keyBag_parser(hx509_context context,
73 struct hx509_collector *c,
74 int flags,
75 const void *data, size_t length,
76 const PKCS12_Attributes *attrs)
78 const PKCS12_Attribute *attr;
79 PKCS8PrivateKeyInfo ki;
80 const heim_octet_string *os = NULL;
81 int ret;
83 if (flags & HX509_CERTS_NO_PRIVATE_KEYS)
84 return 0;
86 attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId);
87 if (attr)
88 os = &attr->attrValues;
90 ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
91 if (ret)
92 return ret;
94 ret = _hx509_collector_private_key_add(context,
96 &ki.privateKeyAlgorithm,
97 NULL,
98 &ki.privateKey,
99 os);
100 free_PKCS8PrivateKeyInfo(&ki);
101 return ret;
104 static int
105 ShroudedKeyBag_parser(hx509_context context,
106 struct hx509_collector *c,
107 int flags,
108 const void *data, size_t length,
109 const PKCS12_Attributes *attrs)
111 PKCS8EncryptedPrivateKeyInfo pk;
112 heim_octet_string content;
113 int ret;
115 memset(&pk, 0, sizeof(pk));
117 ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);
118 if (ret)
119 return ret;
121 ret = _hx509_pbe_decrypt(context,
122 _hx509_collector_get_lock(c),
123 &pk.encryptionAlgorithm,
124 &pk.encryptedData,
125 &content);
126 free_PKCS8EncryptedPrivateKeyInfo(&pk);
127 if (ret)
128 return ret;
130 ret = keyBag_parser(context, c, flags, content.data, content.length,
131 attrs);
132 der_free_octet_string(&content);
133 return ret;
136 static int
137 certBag_parser(hx509_context context,
138 struct hx509_collector *c,
139 int flags,
140 const void *data, size_t length,
141 const PKCS12_Attributes *attrs)
143 heim_error_t error = NULL;
144 heim_octet_string os;
145 hx509_cert cert;
146 PKCS12_CertBag cb;
147 int ret;
149 ret = decode_PKCS12_CertBag(data, length, &cb, NULL);
150 if (ret)
151 return ret;
153 if (der_heim_oid_cmp(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType)) {
154 free_PKCS12_CertBag(&cb);
155 return 0;
158 ret = decode_PKCS12_OctetString(cb.certValue.data,
159 cb.certValue.length,
160 &os,
161 NULL);
162 free_PKCS12_CertBag(&cb);
163 if (ret)
164 return ret;
166 cert = hx509_cert_init_data(context, os.data, os.length, &error);
167 der_free_octet_string(&os);
168 if (cert == NULL) {
169 ret = heim_error_get_code(error);
170 heim_release(error);
171 return ret;
174 ret = _hx509_collector_certs_add(context, c, cert);
175 if (ret) {
176 hx509_cert_free(cert);
177 return ret;
181 const PKCS12_Attribute *attr;
182 const heim_oid *oids[] = {
183 &asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName
185 size_t i;
187 for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {
188 const heim_oid *oid = oids[i];
189 attr = find_attribute(attrs, oid);
190 if (attr)
191 _hx509_set_cert_attribute(context, cert, oid,
192 &attr->attrValues);
196 hx509_cert_free(cert);
198 return 0;
201 static int
202 parse_safe_content(hx509_context context,
203 struct hx509_collector *c,
204 int flags,
205 const unsigned char *p, size_t len)
207 PKCS12_SafeContents sc;
208 int ret;
209 size_t i;
211 memset(&sc, 0, sizeof(sc));
213 ret = decode_PKCS12_SafeContents(p, len, &sc, NULL);
214 if (ret)
215 return ret;
217 for (i = 0; i < sc.len ; i++)
218 parse_pkcs12_type(context,
220 flags,
221 &sc.val[i].bagId,
222 sc.val[i].bagValue.data,
223 sc.val[i].bagValue.length,
224 sc.val[i].bagAttributes);
226 free_PKCS12_SafeContents(&sc);
227 return 0;
230 static int
231 safeContent_parser(hx509_context context,
232 struct hx509_collector *c,
233 int flags,
234 const void *data, size_t length,
235 const PKCS12_Attributes *attrs)
237 heim_octet_string os;
238 int ret;
240 ret = decode_PKCS12_OctetString(data, length, &os, NULL);
241 if (ret)
242 return ret;
243 ret = parse_safe_content(context, c, flags, os.data, os.length);
244 der_free_octet_string(&os);
245 return ret;
248 static int
249 encryptedData_parser(hx509_context context,
250 struct hx509_collector *c,
251 int flags,
252 const void *data, size_t length,
253 const PKCS12_Attributes *attrs)
255 heim_octet_string content;
256 heim_oid contentType;
257 int ret;
259 memset(&contentType, 0, sizeof(contentType));
261 ret = hx509_cms_decrypt_encrypted(context,
262 _hx509_collector_get_lock(c),
263 data, length,
264 &contentType,
265 &content);
266 if (ret)
267 return ret;
269 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
270 ret = parse_safe_content(context, c, flags,
271 content.data, content.length);
273 der_free_octet_string(&content);
274 der_free_oid(&contentType);
275 return ret;
278 static int
279 envelopedData_parser(hx509_context context,
280 struct hx509_collector *c,
281 int flags,
282 const void *data, size_t length,
283 const PKCS12_Attributes *attrs)
285 heim_octet_string content;
286 heim_oid contentType;
287 hx509_lock lock;
288 int ret;
290 memset(&contentType, 0, sizeof(contentType));
292 lock = _hx509_collector_get_lock(c);
294 ret = hx509_cms_unenvelope(context,
295 _hx509_lock_unlock_certs(lock),
297 data, length,
298 NULL,
300 &contentType,
301 &content);
302 if (ret) {
303 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
304 "PKCS12 failed to unenvelope");
305 return ret;
308 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
309 ret = parse_safe_content(context, c, flags,
310 content.data, content.length);
312 der_free_octet_string(&content);
313 der_free_oid(&contentType);
315 return ret;
319 struct type bagtypes[] = {
320 { &asn1_oid_id_pkcs12_keyBag, keyBag_parser },
321 { &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },
322 { &asn1_oid_id_pkcs12_certBag, certBag_parser },
323 { &asn1_oid_id_pkcs7_data, safeContent_parser },
324 { &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser },
325 { &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser }
328 static void
329 parse_pkcs12_type(hx509_context context,
330 struct hx509_collector *c,
331 int flags,
332 const heim_oid *oid,
333 const void *data, size_t length,
334 const PKCS12_Attributes *attrs)
336 size_t i;
338 for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
339 if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0)
340 (*bagtypes[i].func)(context, c, flags, data, length, attrs);
343 static int
344 p12_init(hx509_context context,
345 hx509_certs certs, void **data, int flags,
346 const char *residue, hx509_lock lock)
348 struct ks_pkcs12 *p12;
349 size_t len;
350 void *buf;
351 PKCS12_PFX pfx;
352 PKCS12_AuthenticatedSafe as;
353 int ret;
354 size_t i;
355 struct hx509_collector *c;
357 *data = NULL;
359 if (residue == NULL || residue[0] == '\0') {
360 hx509_set_error_string(context, 0, EINVAL,
361 "PKCS#12 file not specified");
362 return EINVAL;
365 if (lock == NULL)
366 lock = _hx509_empty_lock;
368 ret = _hx509_collector_alloc(context, lock, &c);
369 if (ret)
370 return ret;
372 p12 = calloc(1, sizeof(*p12));
373 if (p12 == NULL) {
374 ret = ENOMEM;
375 hx509_set_error_string(context, 0, ret, "out of memory");
376 goto out;
379 p12->fn = strdup(residue);
380 if (p12->fn == NULL) {
381 ret = ENOMEM;
382 hx509_set_error_string(context, 0, ret, "out of memory");
383 goto out;
386 if (flags & HX509_CERTS_CREATE) {
387 ret = hx509_certs_init(context, "MEMORY:ks-file-create",
388 0, lock, &p12->certs);
389 if (ret == 0)
390 *data = p12;
391 goto out;
394 ret = rk_undumpdata(residue, &buf, &len);
395 if (ret) {
396 hx509_clear_error_string(context);
397 goto out;
400 ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);
401 rk_xfree(buf);
402 if (ret) {
403 hx509_set_error_string(context, 0, ret,
404 "Failed to decode the PFX in %s", residue);
405 goto out;
408 if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) {
409 free_PKCS12_PFX(&pfx);
410 ret = EINVAL;
411 hx509_set_error_string(context, 0, ret,
412 "PKCS PFX isn't a pkcs7-data container");
413 goto out;
416 if (pfx.authSafe.content == NULL) {
417 free_PKCS12_PFX(&pfx);
418 ret = EINVAL;
419 hx509_set_error_string(context, 0, ret,
420 "PKCS PFX missing data");
421 goto out;
425 heim_octet_string asdata;
427 ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,
428 pfx.authSafe.content->length,
429 &asdata,
430 NULL);
431 free_PKCS12_PFX(&pfx);
432 if (ret) {
433 hx509_clear_error_string(context);
434 goto out;
436 ret = decode_PKCS12_AuthenticatedSafe(asdata.data,
437 asdata.length,
438 &as,
439 NULL);
440 der_free_octet_string(&asdata);
441 if (ret) {
442 hx509_clear_error_string(context);
443 goto out;
447 for (i = 0; i < as.len; i++)
448 parse_pkcs12_type(context,
450 flags,
451 &as.val[i].contentType,
452 as.val[i].content->data,
453 as.val[i].content->length,
454 NULL);
456 free_PKCS12_AuthenticatedSafe(&as);
458 ret = _hx509_collector_collect_certs(context, c, &p12->certs);
459 if (ret == 0)
460 *data = p12;
462 out:
463 _hx509_collector_free(c);
465 if (ret && p12) {
466 if (p12->fn)
467 free(p12->fn);
468 if (p12->certs)
469 hx509_certs_free(&p12->certs);
470 free(p12);
473 return ret;
476 static int
477 addBag(hx509_context context,
478 PKCS12_AuthenticatedSafe *as,
479 const heim_oid *oid,
480 void *data,
481 size_t length)
483 void *ptr;
484 int ret;
486 ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
487 if (ptr == NULL) {
488 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
489 return ENOMEM;
491 as->val = ptr;
493 ret = der_copy_oid(oid, &as->val[as->len].contentType);
494 if (ret) {
495 hx509_set_error_string(context, 0, ret, "out of memory");
496 return ret;
499 as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
500 if (as->val[as->len].content == NULL) {
501 der_free_oid(&as->val[as->len].contentType);
502 hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
503 return ENOMEM;
506 as->val[as->len].content->data = data;
507 as->val[as->len].content->length = length;
509 as->len++;
511 return 0;
514 struct store_func_ctx {
515 PKCS12_AuthenticatedSafe as;
516 int store_flags;
519 static int HX509_LIB_CALL
520 store_func(hx509_context context, void *d, hx509_cert c)
522 struct store_func_ctx *ctx = d;
523 PKCS12_OctetString os;
524 PKCS12_CertBag cb;
525 size_t size;
526 int ret;
528 if ((ctx->store_flags & HX509_CERTS_STORE_NO_ROOTS)) {
529 int is_root = 0;
531 ret = hx509_cert_is_root(context, c, &is_root);
532 if (ret || is_root)
533 return ret;
536 memset(&os, 0, sizeof(os));
537 memset(&cb, 0, sizeof(cb));
539 os.data = NULL;
540 os.length = 0;
542 ret = hx509_cert_binary(context, c, &os);
543 if (ret)
544 return ret;
546 ASN1_MALLOC_ENCODE(PKCS12_OctetString,
547 cb.certValue.data,cb.certValue.length,
548 &os, &size, ret);
549 free(os.data);
550 if (ret)
551 goto out;
552 ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType);
553 if (ret) {
554 free_PKCS12_CertBag(&cb);
555 goto out;
557 ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
558 &cb, &size, ret);
559 free_PKCS12_CertBag(&cb);
560 if (ret)
561 goto out;
563 ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_certBag, os.data,
564 os.length);
566 if (_hx509_cert_private_key_exportable(c) &&
567 !(ctx->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
568 hx509_private_key key = _hx509_cert_private_key(c);
569 PKCS8PrivateKeyInfo pki;
571 memset(&pki, 0, sizeof(pki));
573 ret = der_parse_hex_heim_integer("00", &pki.version);
574 if (ret)
575 return ret;
576 ret = _hx509_private_key_oid(context, key,
577 &pki.privateKeyAlgorithm.algorithm);
578 if (ret) {
579 free_PKCS8PrivateKeyInfo(&pki);
580 return ret;
582 ret = _hx509_private_key_export(context,
583 _hx509_cert_private_key(c),
584 HX509_KEY_FORMAT_DER,
585 &pki.privateKey);
586 if (ret) {
587 free_PKCS8PrivateKeyInfo(&pki);
588 return ret;
590 /* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */
592 ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
593 &pki, &size, ret);
594 free_PKCS8PrivateKeyInfo(&pki);
595 if (ret)
596 return ret;
598 ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_keyBag, os.data,
599 os.length);
600 if (ret)
601 return ret;
604 out:
605 return ret;
608 static int
609 p12_store(hx509_context context,
610 hx509_certs certs, void *data, int flags, hx509_lock lock)
612 struct ks_pkcs12 *p12 = data;
613 PKCS12_PFX pfx;
614 struct store_func_ctx ctx;
615 PKCS12_OctetString asdata;
616 size_t size;
617 int ret;
619 memset(&ctx, 0, sizeof(ctx));
620 memset(&pfx, 0, sizeof(pfx));
621 ctx.store_flags = flags;
623 ret = hx509_certs_iter_f(context, p12->certs, store_func, &ctx);
624 if (ret)
625 goto out;
627 ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
628 &ctx.as, &size, ret);
629 free_PKCS12_AuthenticatedSafe(&ctx.as);
630 if (ret)
631 return ret;
633 ret = der_parse_hex_heim_integer("03", &pfx.version);
634 if (ret) {
635 free(asdata.data);
636 goto out;
639 pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));
641 ASN1_MALLOC_ENCODE(PKCS12_OctetString,
642 pfx.authSafe.content->data,
643 pfx.authSafe.content->length,
644 &asdata, &size, ret);
645 free(asdata.data);
646 if (ret)
647 goto out;
649 ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType);
650 if (ret)
651 goto out;
653 ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
654 &pfx, &size, ret);
655 if (ret)
656 goto out;
658 #if 0
659 const struct _hx509_password *pw;
661 pw = _hx509_lock_get_passwords(lock);
662 if (pw != NULL) {
663 pfx.macData = calloc(1, sizeof(*pfx.macData));
664 if (pfx.macData == NULL) {
665 ret = ENOMEM;
666 hx509_set_error_string(context, 0, ret, "malloc out of memory");
667 return ret;
669 if (pfx.macData == NULL) {
670 free(asdata.data);
671 goto out;
674 ret = calculate_hash(&aspath, pw, pfx.macData);
675 #endif
677 rk_dumpdata(p12->fn, asdata.data, asdata.length);
678 free(asdata.data);
680 out:
681 free_PKCS12_AuthenticatedSafe(&ctx.as);
682 free_PKCS12_PFX(&pfx);
684 return ret;
688 static int
689 p12_free(hx509_certs certs, void *data)
691 struct ks_pkcs12 *p12 = data;
692 hx509_certs_free(&p12->certs);
693 free(p12->fn);
694 free(p12);
695 return 0;
698 static int
699 p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
701 struct ks_pkcs12 *p12 = data;
702 return hx509_certs_add(context, p12->certs, c);
705 static int
706 p12_iter_start(hx509_context context,
707 hx509_certs certs,
708 void *data,
709 void **cursor)
711 struct ks_pkcs12 *p12 = data;
712 return hx509_certs_start_seq(context, p12->certs, cursor);
715 static int
716 p12_iter(hx509_context context,
717 hx509_certs certs,
718 void *data,
719 void *cursor,
720 hx509_cert *cert)
722 struct ks_pkcs12 *p12 = data;
723 return hx509_certs_next_cert(context, p12->certs, cursor, cert);
726 static int
727 p12_iter_end(hx509_context context,
728 hx509_certs certs,
729 void *data,
730 void *cursor)
732 struct ks_pkcs12 *p12 = data;
733 return hx509_certs_end_seq(context, p12->certs, cursor);
736 static int
737 p12_destroy(hx509_context context, hx509_certs certs, void *data)
739 struct ks_pkcs12 *p12 = data;
740 return _hx509_erase_file(context, p12->fn);
743 static struct hx509_keyset_ops keyset_pkcs12 = {
744 "PKCS12",
746 p12_init,
747 p12_store,
748 p12_free,
749 p12_add,
750 NULL,
751 p12_iter_start,
752 p12_iter,
753 p12_iter_end,
754 NULL,
755 NULL,
756 NULL,
757 p12_destroy
760 HX509_LIB_FUNCTION void HX509_LIB_CALL
761 _hx509_ks_pkcs12_register(hx509_context context)
763 _hx509_ks_register(context, &keyset_pkcs12);