1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "hx_locl.h" 37 38struct ks_pkcs12 { 39 hx509_certs certs; 40 char *fn; 41}; 42 43typedef int (*collector_func)(hx509_context, 44 struct hx509_collector *, 45 const void *, size_t, 46 const PKCS12_Attributes *); 47 48struct type { 49 const heim_oid *oid; 50 collector_func func; 51}; 52 53static void 54parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *, 55 const void *, size_t, const PKCS12_Attributes *); 56 57 58static const PKCS12_Attribute * 59find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid) 60{ 61 int i; 62 if (attrs == NULL) 63 return NULL; 64 for (i = 0; i < attrs->len; i++) 65 if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0) 66 return &attrs->val[i]; 67 return NULL; 68} 69 70static int 71keyBag_parser(hx509_context context, 72 struct hx509_collector *c, 73 const void *data, size_t length, 74 const PKCS12_Attributes *attrs) 75{ 76 const PKCS12_Attribute *attr; 77 PKCS8PrivateKeyInfo ki; 78 const heim_octet_string *os = NULL; 79 int ret; 80 81 attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId); 82 if (attr) 83 os = &attr->attrValues; 84 85 ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL); 86 if (ret) 87 return ret; 88 89 _hx509_collector_private_key_add(context, 90 c, 91 &ki.privateKeyAlgorithm, 92 NULL, 93 &ki.privateKey, 94 os); 95 free_PKCS8PrivateKeyInfo(&ki); 96 return 0; 97} 98 99static int 100ShroudedKeyBag_parser(hx509_context context, 101 struct hx509_collector *c, 102 const void *data, size_t length, 103 const PKCS12_Attributes *attrs) 104{ 105 PKCS8EncryptedPrivateKeyInfo pk; 106 heim_octet_string content; 107 int ret; 108 109 memset(&pk, 0, sizeof(pk)); 110 111 ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL); 112 if (ret) 113 return ret; 114 115 ret = _hx509_pbe_decrypt(context, 116 _hx509_collector_get_lock(c), 117 &pk.encryptionAlgorithm, 118 &pk.encryptedData, 119 &content); 120 free_PKCS8EncryptedPrivateKeyInfo(&pk); 121 if (ret) 122 return ret; 123 124 ret = keyBag_parser(context, c, content.data, content.length, attrs); 125 der_free_octet_string(&content); 126 return ret; 127} 128 129static int 130certBag_parser(hx509_context context, 131 struct hx509_collector *c, 132 const void *data, size_t length, 133 const PKCS12_Attributes *attrs) 134{ 135 heim_octet_string os; 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(&asn1_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 = hx509_cert_init_data(context, os.data, os.length, &cert); 158 der_free_octet_string(&os); 159 if (ret) 160 return ret; 161 162 ret = _hx509_collector_certs_add(context, c, cert); 163 if (ret) { 164 hx509_cert_free(cert); 165 return ret; 166 } 167 168 { 169 const PKCS12_Attribute *attr; 170 const heim_oid *oids[] = { 171 &asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName 172 }; 173 int i; 174 175 for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) { 176 const heim_oid *oid = oids[i]; 177 attr = find_attribute(attrs, oid); 178 if (attr) 179 _hx509_set_cert_attribute(context, cert, oid, 180 &attr->attrValues); 181 } 182 } 183 184 hx509_cert_free(cert); 185 186 return 0; 187} 188 189static int 190parse_safe_content(hx509_context context, 191 struct hx509_collector *c, 192 const unsigned char *p, size_t len) 193{ 194 PKCS12_SafeContents sc; 195 int ret, i; 196 197 memset(&sc, 0, sizeof(sc)); 198 199 ret = decode_PKCS12_SafeContents(p, len, &sc, NULL); 200 if (ret) 201 return ret; 202 203 for (i = 0; i < sc.len ; i++) 204 parse_pkcs12_type(context, 205 c, 206 &sc.val[i].bagId, 207 sc.val[i].bagValue.data, 208 sc.val[i].bagValue.length, 209 sc.val[i].bagAttributes); 210 211 free_PKCS12_SafeContents(&sc); 212 return 0; 213} 214 215static int 216safeContent_parser(hx509_context context, 217 struct hx509_collector *c, 218 const void *data, size_t length, 219 const PKCS12_Attributes *attrs) 220{ 221 heim_octet_string os; 222 int ret; 223 224 ret = decode_PKCS12_OctetString(data, length, &os, NULL); 225 if (ret) 226 return ret; 227 ret = parse_safe_content(context, c, os.data, os.length); 228 der_free_octet_string(&os); 229 return ret; 230} 231 232static int 233encryptedData_parser(hx509_context context, 234 struct hx509_collector *c, 235 const void *data, size_t length, 236 const PKCS12_Attributes *attrs) 237{ 238 heim_octet_string content; 239 heim_oid contentType; 240 int ret; 241 242 memset(&contentType, 0, sizeof(contentType)); 243 244 ret = hx509_cms_decrypt_encrypted(context, 245 _hx509_collector_get_lock(c), 246 data, length, 247 &contentType, 248 &content); 249 if (ret) 250 return ret; 251 252 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) 253 ret = parse_safe_content(context, c, content.data, content.length); 254 255 der_free_octet_string(&content); 256 der_free_oid(&contentType); 257 return ret; 258} 259 260static int 261envelopedData_parser(hx509_context context, 262 struct hx509_collector *c, 263 const void *data, size_t length, 264 const PKCS12_Attributes *attrs) 265{ 266 heim_octet_string content; 267 heim_oid contentType; 268 hx509_lock lock; 269 int ret; 270 271 memset(&contentType, 0, sizeof(contentType)); 272 273 lock = _hx509_collector_get_lock(c); 274 275 ret = hx509_cms_unenvelope(context, 276 _hx509_lock_unlock_certs(lock), 277 0, 278 data, length, 279 NULL, 280 0, 281 &contentType, 282 &content); 283 if (ret) { 284 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 285 "PKCS12 failed to unenvelope"); 286 return ret; 287 } 288 289 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) 290 ret = parse_safe_content(context, c, content.data, content.length); 291 292 der_free_octet_string(&content); 293 der_free_oid(&contentType); 294 295 return ret; 296} 297 298 299struct type bagtypes[] = { 300 { &asn1_oid_id_pkcs12_keyBag, keyBag_parser }, 301 { &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser }, 302 { &asn1_oid_id_pkcs12_certBag, certBag_parser }, 303 { &asn1_oid_id_pkcs7_data, safeContent_parser }, 304 { &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser }, 305 { &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser } 306}; 307 308static void 309parse_pkcs12_type(hx509_context context, 310 struct hx509_collector *c, 311 const heim_oid *oid, 312 const void *data, size_t length, 313 const PKCS12_Attributes *attrs) 314{ 315 int i; 316 317 for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++) 318 if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0) 319 (*bagtypes[i].func)(context, c, data, length, attrs); 320} 321 322static int 323p12_init(hx509_context context, 324 hx509_certs certs, void **data, int flags, 325 const char *residue, hx509_lock lock) 326{ 327 struct ks_pkcs12 *p12; 328 size_t len; 329 void *buf; 330 PKCS12_PFX pfx; 331 PKCS12_AuthenticatedSafe as; 332 int ret, i; 333 struct hx509_collector *c; 334 335 *data = NULL; 336 337 if (lock == NULL) 338 lock = _hx509_empty_lock; 339 340 ret = _hx509_collector_alloc(context, lock, &c); 341 if (ret) 342 return ret; 343 344 p12 = calloc(1, sizeof(*p12)); 345 if (p12 == NULL) { 346 ret = ENOMEM; 347 hx509_set_error_string(context, 0, ret, "out of memory"); 348 goto out; 349 } 350 351 p12->fn = strdup(residue); 352 if (p12->fn == NULL) { 353 ret = ENOMEM; 354 hx509_set_error_string(context, 0, ret, "out of memory"); 355 goto out; 356 } 357 358 if (flags & HX509_CERTS_CREATE) { 359 ret = hx509_certs_init(context, "MEMORY:ks-file-create", 360 0, lock, &p12->certs); 361 if (ret == 0) 362 *data = p12; 363 goto out; 364 } 365 366 ret = rk_undumpdata(residue, &buf, &len); 367 if (ret) { 368 hx509_clear_error_string(context); 369 goto out; 370 } 371 372 ret = decode_PKCS12_PFX(buf, len, &pfx, NULL); 373 rk_xfree(buf); 374 if (ret) { 375 hx509_set_error_string(context, 0, ret, 376 "Failed to decode the PFX in %s", residue); 377 goto out; 378 } 379 380 if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) { 381 free_PKCS12_PFX(&pfx); 382 ret = EINVAL; 383 hx509_set_error_string(context, 0, ret, 384 "PKCS PFX isn't a pkcs7-data container"); 385 goto out; 386 } 387 388 if (pfx.authSafe.content == NULL) { 389 free_PKCS12_PFX(&pfx); 390 ret = EINVAL; 391 hx509_set_error_string(context, 0, ret, 392 "PKCS PFX missing data"); 393 goto out; 394 } 395 396 { 397 heim_octet_string asdata; 398 399 ret = decode_PKCS12_OctetString(pfx.authSafe.content->data, 400 pfx.authSafe.content->length, 401 &asdata, 402 NULL); 403 free_PKCS12_PFX(&pfx); 404 if (ret) { 405 hx509_clear_error_string(context); 406 goto out; 407 } 408 ret = decode_PKCS12_AuthenticatedSafe(asdata.data, 409 asdata.length, 410 &as, 411 NULL); 412 der_free_octet_string(&asdata); 413 if (ret) { 414 hx509_clear_error_string(context); 415 goto out; 416 } 417 } 418 419 for (i = 0; i < as.len; i++) 420 parse_pkcs12_type(context, 421 c, 422 &as.val[i].contentType, 423 as.val[i].content->data, 424 as.val[i].content->length, 425 NULL); 426 427 free_PKCS12_AuthenticatedSafe(&as); 428 429 ret = _hx509_collector_collect_certs(context, c, &p12->certs); 430 if (ret == 0) 431 *data = p12; 432 433out: 434 _hx509_collector_free(c); 435 436 if (ret && p12) { 437 if (p12->fn) 438 free(p12->fn); 439 if (p12->certs) 440 hx509_certs_free(&p12->certs); 441 free(p12); 442 } 443 444 return ret; 445} 446 447static int 448addBag(hx509_context context, 449 PKCS12_AuthenticatedSafe *as, 450 const heim_oid *oid, 451 void *data, 452 size_t length) 453{ 454 void *ptr; 455 int ret; 456 457 ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1)); 458 if (ptr == NULL) { 459 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 460 return ENOMEM; 461 } 462 as->val = ptr; 463 464 ret = der_copy_oid(oid, &as->val[as->len].contentType); 465 if (ret) { 466 hx509_set_error_string(context, 0, ret, "out of memory"); 467 return ret; 468 } 469 470 as->val[as->len].content = calloc(1, sizeof(*as->val[0].content)); 471 if (as->val[as->len].content == NULL) { 472 der_free_oid(&as->val[as->len].contentType); 473 hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory"); 474 return ENOMEM; 475 } 476 477 as->val[as->len].content->data = data; 478 as->val[as->len].content->length = length; 479 480 as->len++; 481 482 return 0; 483} 484 485static int 486store_func(hx509_context context, void *ctx, hx509_cert c) 487{ 488 PKCS12_AuthenticatedSafe *as = ctx; 489 PKCS12_OctetString os; 490 PKCS12_CertBag cb; 491 size_t size; 492 int ret; 493 494 memset(&os, 0, sizeof(os)); 495 memset(&cb, 0, sizeof(cb)); 496 497 os.data = NULL; 498 os.length = 0; 499 500 ret = hx509_cert_binary(context, c, &os); 501 if (ret) 502 return ret; 503 504 ASN1_MALLOC_ENCODE(PKCS12_OctetString, 505 cb.certValue.data,cb.certValue.length, 506 &os, &size, ret); 507 free(os.data); 508 if (ret) 509 goto out; 510 ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType); 511 if (ret) { 512 free_PKCS12_CertBag(&cb); 513 goto out; 514 } 515 ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length, 516 &cb, &size, ret); 517 free_PKCS12_CertBag(&cb); 518 if (ret) 519 goto out; 520 521 ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length); 522 523 if (_hx509_cert_private_key_exportable(c)) { 524 hx509_private_key key = _hx509_cert_private_key(c); 525 PKCS8PrivateKeyInfo pki; 526 527 memset(&pki, 0, sizeof(pki)); 528 529 ret = der_parse_hex_heim_integer("00", &pki.version); 530 if (ret) 531 return ret; 532 ret = _hx509_private_key_oid(context, key, 533 &pki.privateKeyAlgorithm.algorithm); 534 if (ret) { 535 free_PKCS8PrivateKeyInfo(&pki); 536 return ret; 537 } 538 ret = _hx509_private_key_export(context, 539 _hx509_cert_private_key(c), 540 HX509_KEY_FORMAT_DER, 541 &pki.privateKey); 542 if (ret) { 543 free_PKCS8PrivateKeyInfo(&pki); 544 return ret; 545 } 546 /* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */ 547 548 ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length, 549 &pki, &size, ret); 550 free_PKCS8PrivateKeyInfo(&pki); 551 if (ret) 552 return ret; 553 554 ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length); 555 if (ret) 556 return ret; 557 } 558 559out: 560 return ret; 561} 562 563static int 564p12_store(hx509_context context, 565 hx509_certs certs, void *data, int flags, hx509_lock lock) 566{ 567 struct ks_pkcs12 *p12 = data; 568 PKCS12_PFX pfx; 569 PKCS12_AuthenticatedSafe as; 570 PKCS12_OctetString asdata; 571 size_t size; 572 int ret; 573 574 memset(&as, 0, sizeof(as)); 575 memset(&pfx, 0, sizeof(pfx)); 576 577 ret = hx509_certs_iter_f(context, p12->certs, store_func, &as); 578 if (ret) 579 goto out; 580 581 ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length, 582 &as, &size, ret); 583 free_PKCS12_AuthenticatedSafe(&as); 584 if (ret) 585 return ret; 586 587 ret = der_parse_hex_heim_integer("03", &pfx.version); 588 if (ret) { 589 free(asdata.data); 590 goto out; 591 } 592 593 pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content)); 594 595 ASN1_MALLOC_ENCODE(PKCS12_OctetString, 596 pfx.authSafe.content->data, 597 pfx.authSafe.content->length, 598 &asdata, &size, ret); 599 free(asdata.data); 600 if (ret) 601 goto out; 602 603 ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType); 604 if (ret) 605 goto out; 606 607 ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length, 608 &pfx, &size, ret); 609 if (ret) 610 goto out; 611 612#if 0 613 const struct _hx509_password *pw; 614 615 pw = _hx509_lock_get_passwords(lock); 616 if (pw != NULL) { 617 pfx.macData = calloc(1, sizeof(*pfx.macData)); 618 if (pfx.macData == NULL) { 619 ret = ENOMEM; 620 hx509_set_error_string(context, 0, ret, "malloc out of memory"); 621 return ret; 622 } 623 if (pfx.macData == NULL) { 624 free(asdata.data); 625 goto out; 626 } 627 } 628 ret = calculate_hash(&aspath, pw, pfx.macData); 629#endif 630 631 rk_dumpdata(p12->fn, asdata.data, asdata.length); 632 free(asdata.data); 633 634out: 635 free_PKCS12_AuthenticatedSafe(&as); 636 free_PKCS12_PFX(&pfx); 637 638 return ret; 639} 640 641 642static int 643p12_free(hx509_certs certs, void *data) 644{ 645 struct ks_pkcs12 *p12 = data; 646 hx509_certs_free(&p12->certs); 647 free(p12->fn); 648 free(p12); 649 return 0; 650} 651 652static int 653p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c) 654{ 655 struct ks_pkcs12 *p12 = data; 656 return hx509_certs_add(context, p12->certs, c); 657} 658 659static int 660p12_iter_start(hx509_context context, 661 hx509_certs certs, 662 void *data, 663 void **cursor) 664{ 665 struct ks_pkcs12 *p12 = data; 666 return hx509_certs_start_seq(context, p12->certs, cursor); 667} 668 669static int 670p12_iter(hx509_context context, 671 hx509_certs certs, 672 void *data, 673 void *cursor, 674 hx509_cert *cert) 675{ 676 struct ks_pkcs12 *p12 = data; 677 return hx509_certs_next_cert(context, p12->certs, cursor, cert); 678} 679 680static int 681p12_iter_end(hx509_context context, 682 hx509_certs certs, 683 void *data, 684 void *cursor) 685{ 686 struct ks_pkcs12 *p12 = data; 687 return hx509_certs_end_seq(context, p12->certs, cursor); 688} 689 690static struct hx509_keyset_ops keyset_pkcs12 = { 691 "PKCS12", 692 0, 693 p12_init, 694 p12_store, 695 p12_free, 696 p12_add, 697 NULL, 698 p12_iter_start, 699 p12_iter, 700 p12_iter_end 701}; 702 703void 704_hx509_ks_pkcs12_register(hx509_context context) 705{ 706 _hx509_ks_register(context, &keyset_pkcs12); 707} 708