diff options
| author | 2014-03-21 18:14:15 +0100 | |
|---|---|---|
| committer | 2014-03-21 18:14:15 +0100 | |
| commit | 03ad1dc56830bd6e921e58ecce2b8b0fd3aea675 (patch) | |
| tree | e8d806acde618ba817a165b14943dd1ffec47256 | |
| parent | 1a0ce00184f560556d5e823dc8b1258a79ed5aaa (diff) | |
| download | libimobiledevice-03ad1dc56830bd6e921e58ecce2b8b0fd3aea675.tar.gz libimobiledevice-03ad1dc56830bd6e921e58ecce2b8b0fd3aea675.tar.bz2 | |
userpref: merge pair_record_generate_from_device_public_key() into pair_record_generate_keys_and_certs()
| -rw-r--r-- | common/userpref.c | 387 | ||||
| -rw-r--r-- | common/userpref.h | 3 | ||||
| -rw-r--r-- | src/lockdown.c | 16 |
3 files changed, 140 insertions, 266 deletions
diff --git a/common/userpref.c b/common/userpref.c index 5a00d28..cb74945 100644 --- a/common/userpref.c +++ b/common/userpref.c | |||
| @@ -43,8 +43,10 @@ | |||
| 43 | #include <openssl/x509v3.h> | 43 | #include <openssl/x509v3.h> |
| 44 | #else | 44 | #else |
| 45 | #include <gnutls/gnutls.h> | 45 | #include <gnutls/gnutls.h> |
| 46 | #include <gnutls/crypto.h> | ||
| 46 | #include <gnutls/x509.h> | 47 | #include <gnutls/x509.h> |
| 47 | #include <gcrypt.h> | 48 | #include <gcrypt.h> |
| 49 | #include <libtasn1.h> | ||
| 48 | #endif | 50 | #endif |
| 49 | 51 | ||
| 50 | #include <dirent.h> | 52 | #include <dirent.h> |
| @@ -389,19 +391,27 @@ static int X509_add_ext_helper(X509 *cert, int nid, char *value) | |||
| 389 | #endif | 391 | #endif |
| 390 | 392 | ||
| 391 | /** | 393 | /** |
| 392 | * Private function which generate private keys and certificates. | 394 | * Private function to generate required private keys and certificates. |
| 395 | * | ||
| 396 | * @param pair_record a #PLIST_DICT that will be filled with the keys | ||
| 397 | * and certificates | ||
| 398 | * @param public_key the public key to use (device public key) | ||
| 393 | * | 399 | * |
| 394 | * @return 1 if keys were successfully generated, 0 otherwise | 400 | * @return 1 if keys were successfully generated, 0 otherwise |
| 395 | */ | 401 | */ |
| 396 | userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record) | 402 | userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key) |
| 397 | { | 403 | { |
| 398 | userpref_error_t ret = USERPREF_E_SSL_ERROR; | 404 | userpref_error_t ret = USERPREF_E_SSL_ERROR; |
| 399 | 405 | ||
| 406 | key_data_t dev_cert_pem = { NULL, 0 }; | ||
| 400 | key_data_t root_key_pem = { NULL, 0 }; | 407 | key_data_t root_key_pem = { NULL, 0 }; |
| 401 | key_data_t root_cert_pem = { NULL, 0 }; | 408 | key_data_t root_cert_pem = { NULL, 0 }; |
| 402 | key_data_t host_key_pem = { NULL, 0 }; | 409 | key_data_t host_key_pem = { NULL, 0 }; |
| 403 | key_data_t host_cert_pem = { NULL, 0 }; | 410 | key_data_t host_cert_pem = { NULL, 0 }; |
| 404 | 411 | ||
| 412 | if (!pair_record || !public_key.data) | ||
| 413 | return USERPREF_E_INVALID_ARG; | ||
| 414 | |||
| 405 | debug_info("Generating keys and certificates..."); | 415 | debug_info("Generating keys and certificates..."); |
| 406 | 416 | ||
| 407 | #ifdef HAVE_OPENSSL | 417 | #ifdef HAVE_OPENSSL |
| @@ -531,6 +541,63 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record) | |||
| 531 | } | 541 | } |
| 532 | } | 542 | } |
| 533 | 543 | ||
| 544 | RSA *pubkey = NULL; | ||
| 545 | { | ||
| 546 | BIO *membp = BIO_new_mem_buf(public_key.data, public_key.size); | ||
| 547 | if (!PEM_read_bio_RSAPublicKey(membp, &pubkey, NULL, NULL)) { | ||
| 548 | debug_info("Could not read public key"); | ||
| 549 | } | ||
| 550 | BIO_free(membp); | ||
| 551 | } | ||
| 552 | |||
| 553 | X509* dev_cert = X509_new(); | ||
| 554 | if (pubkey && dev_cert) { | ||
| 555 | /* generate device certificate */ | ||
| 556 | ASN1_INTEGER* sn = ASN1_INTEGER_new(); | ||
| 557 | ASN1_INTEGER_set(sn, 0); | ||
| 558 | X509_set_serialNumber(dev_cert, sn); | ||
| 559 | ASN1_INTEGER_free(sn); | ||
| 560 | X509_set_version(dev_cert, 2); | ||
| 561 | |||
| 562 | X509_add_ext_helper(dev_cert, NID_basic_constraints, (char*)"critical,CA:FALSE"); | ||
| 563 | |||
| 564 | ASN1_TIME* asn1time = ASN1_TIME_new(); | ||
| 565 | ASN1_TIME_set(asn1time, time(NULL)); | ||
| 566 | X509_set_notBefore(dev_cert, asn1time); | ||
| 567 | ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10)); | ||
| 568 | X509_set_notAfter(dev_cert, asn1time); | ||
| 569 | ASN1_TIME_free(asn1time); | ||
| 570 | |||
| 571 | EVP_PKEY* pkey = EVP_PKEY_new(); | ||
| 572 | EVP_PKEY_assign_RSA(pkey, pubkey); | ||
| 573 | X509_set_pubkey(dev_cert, pkey); | ||
| 574 | EVP_PKEY_free(pkey); | ||
| 575 | |||
| 576 | X509_add_ext_helper(dev_cert, NID_subject_key_identifier, (char*)"hash"); | ||
| 577 | X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment"); | ||
| 578 | |||
| 579 | /* sign device certificate with root private key */ | ||
| 580 | if (X509_sign(dev_cert, root_pkey, EVP_sha1())) { | ||
| 581 | /* if signing succeeded, export in PEM format */ | ||
| 582 | BIO* membp = BIO_new(BIO_s_mem()); | ||
| 583 | if (PEM_write_bio_X509(membp, dev_cert) > 0) { | ||
| 584 | char *bdata = NULL; | ||
| 585 | dev_cert_pem.size = BIO_get_mem_data(membp, &bdata); | ||
| 586 | dev_cert_pem.data = (unsigned char*)malloc(dev_cert_pem.size); | ||
| 587 | if (dev_cert_pem.data) { | ||
| 588 | memcpy(dev_cert_pem.data, bdata, dev_cert_pem.size); | ||
| 589 | } | ||
| 590 | BIO_free(membp); | ||
| 591 | membp = NULL; | ||
| 592 | } | ||
| 593 | } else { | ||
| 594 | debug_info("ERROR: Signing device certificate with root private key failed!"); | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | X509V3_EXT_cleanup(); | ||
| 599 | X509_free(dev_cert); | ||
| 600 | |||
| 534 | EVP_PKEY_free(root_pkey); | 601 | EVP_PKEY_free(root_pkey); |
| 535 | EVP_PKEY_free(host_pkey); | 602 | EVP_PKEY_free(host_pkey); |
| 536 | 603 | ||
| @@ -605,175 +672,8 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record) | |||
| 605 | gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_export_size); | 672 | gnutls_x509_crt_export(host_cert, GNUTLS_X509_FMT_PEM, host_cert_pem.data, &host_cert_export_size); |
| 606 | host_cert_pem.size = host_cert_export_size; | 673 | host_cert_pem.size = host_cert_export_size; |
| 607 | 674 | ||
| 608 | /* restore gnutls env */ | 675 | ret = USERPREF_E_UNKNOWN_ERROR; |
| 609 | gnutls_global_deinit(); | ||
| 610 | gnutls_global_init(); | ||
| 611 | #endif | ||
| 612 | if (NULL != root_cert_pem.data && 0 != root_cert_pem.size && | ||
| 613 | NULL != host_cert_pem.data && 0 != host_cert_pem.size) | ||
| 614 | ret = USERPREF_E_SUCCESS; | ||
| 615 | |||
| 616 | /* now set keys and certificates */ | ||
| 617 | pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, &host_key_pem); | ||
| 618 | pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &host_cert_pem); | ||
| 619 | pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_key_pem); | ||
| 620 | pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert_pem); | ||
| 621 | |||
| 622 | if (root_key_pem.data) | ||
| 623 | free(root_key_pem.data); | ||
| 624 | if (root_cert_pem.data) | ||
| 625 | free(root_cert_pem.data); | ||
| 626 | if (host_key_pem.data) | ||
| 627 | free(host_key_pem.data); | ||
| 628 | if (host_cert_pem.data) | ||
| 629 | free(host_cert_pem.data); | ||
| 630 | |||
| 631 | return ret; | ||
| 632 | } | ||
| 633 | |||
| 634 | /** | ||
| 635 | * Generates the device certificate from the public key as well as the host | ||
| 636 | * and root certificates. | ||
| 637 | * | ||
| 638 | * @param pair_record The pair record to use for lookup of key pairs | ||
| 639 | * @param public_key The public key of the device to use for generation. | ||
| 640 | * | ||
| 641 | * @return USERPREF_E_SUCCESS on success, USERPREF_E_INVALID_ARG when a | ||
| 642 | * parameter is NULL, USERPREF_E_INVALID_CONF if the internal configuration | ||
| 643 | * system failed, USERPREF_E_SSL_ERROR if the certificates could not be | ||
| 644 | * generated | ||
| 645 | */ | ||
| 646 | userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record, key_data_t public_key) | ||
| 647 | { | ||
| 648 | if (!pair_record || !public_key.data) | ||
| 649 | return USERPREF_E_INVALID_ARG; | ||
| 650 | |||
| 651 | userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR; | ||
| 652 | |||
| 653 | #ifdef HAVE_OPENSSL | ||
| 654 | BIO *membio = BIO_new_mem_buf(public_key.data, public_key.size); | ||
| 655 | RSA *pubkey = NULL; | ||
| 656 | if (!PEM_read_bio_RSAPublicKey(membio, &pubkey, NULL, NULL)) { | ||
| 657 | debug_info("Could not read public key"); | ||
| 658 | } | ||
| 659 | BIO_free(membio); | ||
| 660 | |||
| 661 | /* now generate certificates */ | ||
| 662 | key_data_t root_privkey, host_privkey; | ||
| 663 | key_data_t root_cert, host_cert; | ||
| 664 | |||
| 665 | X509* dev_cert = X509_new(); | ||
| 666 | |||
| 667 | root_cert.data = NULL; | ||
| 668 | root_cert.size = 0; | ||
| 669 | host_cert.data = NULL; | ||
| 670 | host_cert.size = 0; | ||
| 671 | |||
| 672 | root_privkey.data = NULL; | ||
| 673 | root_privkey.size = 0; | ||
| 674 | host_privkey.data = NULL; | ||
| 675 | host_privkey.size = 0; | ||
| 676 | |||
| 677 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert); | ||
| 678 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &host_cert); | ||
| 679 | uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey); | ||
| 680 | uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, &host_privkey); | ||
| 681 | |||
| 682 | if (USERPREF_E_SUCCESS == uret) { | ||
| 683 | /* generate device certificate */ | ||
| 684 | ASN1_INTEGER* sn = ASN1_INTEGER_new(); | ||
| 685 | ASN1_INTEGER_set(sn, 0); | ||
| 686 | X509_set_serialNumber(dev_cert, sn); | ||
| 687 | ASN1_INTEGER_free(sn); | ||
| 688 | X509_set_version(dev_cert, 2); | ||
| 689 | |||
| 690 | X509_add_ext_helper(dev_cert, NID_basic_constraints, (char*)"critical,CA:FALSE"); | ||
| 691 | |||
| 692 | ASN1_TIME* asn1time = ASN1_TIME_new(); | ||
| 693 | ASN1_TIME_set(asn1time, time(NULL)); | ||
| 694 | X509_set_notBefore(dev_cert, asn1time); | ||
| 695 | ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10)); | ||
| 696 | X509_set_notAfter(dev_cert, asn1time); | ||
| 697 | ASN1_TIME_free(asn1time); | ||
| 698 | |||
| 699 | /* read root certificate */ | ||
| 700 | BIO* membp; | ||
| 701 | X509* rootCert = NULL; | ||
| 702 | membp = BIO_new_mem_buf(root_cert.data, root_cert.size); | ||
| 703 | PEM_read_bio_X509(membp, &rootCert, NULL, NULL); | ||
| 704 | BIO_free(membp); | ||
| 705 | if (!rootCert) { | ||
| 706 | debug_info("Could not read RootCertificate"); | ||
| 707 | } else { | ||
| 708 | debug_info("RootCertificate loaded"); | ||
| 709 | EVP_PKEY* pkey = EVP_PKEY_new(); | ||
| 710 | EVP_PKEY_assign_RSA(pkey, pubkey); | ||
| 711 | X509_set_pubkey(dev_cert, pkey); | ||
| 712 | EVP_PKEY_free(pkey); | ||
| 713 | X509_free(rootCert); | ||
| 714 | } | ||
| 715 | |||
| 716 | X509_add_ext_helper(dev_cert, NID_subject_key_identifier, (char*)"hash"); | ||
| 717 | X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment"); | ||
| 718 | 676 | ||
| 719 | /* read root private key */ | ||
| 720 | EVP_PKEY* rootPriv = NULL; | ||
| 721 | membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size); | ||
| 722 | PEM_read_bio_PrivateKey(membp, &rootPriv, NULL, NULL); | ||
| 723 | BIO_free(membp); | ||
| 724 | if (!rootPriv) { | ||
| 725 | debug_info("Could not read RootPrivateKey"); | ||
| 726 | } else { | ||
| 727 | debug_info("RootPrivateKey loaded"); | ||
| 728 | if (X509_sign(dev_cert, rootPriv, EVP_sha1())) { | ||
| 729 | uret = USERPREF_E_SUCCESS; | ||
| 730 | } else { | ||
| 731 | debug_info("signing failed"); | ||
| 732 | } | ||
| 733 | EVP_PKEY_free(rootPriv); | ||
| 734 | } | ||
| 735 | |||
| 736 | if (USERPREF_E_SUCCESS == uret) { | ||
| 737 | /* if everything went well, export in PEM format */ | ||
| 738 | key_data_t pem_root_cert = { NULL, 0 }; | ||
| 739 | key_data_t pem_host_cert = { NULL, 0 }; | ||
| 740 | |||
| 741 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &pem_root_cert); | ||
| 742 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &pem_host_cert); | ||
| 743 | |||
| 744 | if (USERPREF_E_SUCCESS == uret) { | ||
| 745 | /* set new keys and certs in pair record */ | ||
| 746 | membp = BIO_new(BIO_s_mem()); | ||
| 747 | if (membp && PEM_write_bio_X509(membp, dev_cert) > 0) { | ||
| 748 | void *datap; | ||
| 749 | int size = BIO_get_mem_data(membp, &datap); | ||
| 750 | plist_dict_set_item(pair_record, USERPREF_DEVICE_CERTIFICATE_KEY, plist_new_data(datap, size)); | ||
| 751 | } | ||
| 752 | if (membp) | ||
| 753 | BIO_free(membp); | ||
| 754 | |||
| 755 | plist_dict_set_item(pair_record, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data((char*)pem_host_cert.data, pem_host_cert.size)); | ||
| 756 | plist_dict_set_item(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data((char*)pem_root_cert.data, pem_root_cert.size)); | ||
| 757 | plist_dict_set_item(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data((char*)root_privkey.data, root_privkey.size)); | ||
| 758 | plist_dict_set_item(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data((char*)host_privkey.data, host_privkey.size)); | ||
| 759 | |||
| 760 | free(pem_root_cert.data); | ||
| 761 | free(pem_host_cert.data); | ||
| 762 | } | ||
| 763 | } | ||
| 764 | } | ||
| 765 | X509V3_EXT_cleanup(); | ||
| 766 | X509_free(dev_cert); | ||
| 767 | |||
| 768 | if (root_cert.data) | ||
| 769 | free(root_cert.data); | ||
| 770 | if (host_cert.data) | ||
| 771 | free(host_cert.data); | ||
| 772 | if (root_privkey.data) | ||
| 773 | free(root_privkey.data); | ||
| 774 | if (host_privkey.data) | ||
| 775 | free(host_privkey.data); | ||
| 776 | #else | ||
| 777 | gnutls_datum_t modulus = { NULL, 0 }; | 677 | gnutls_datum_t modulus = { NULL, 0 }; |
| 778 | gnutls_datum_t exponent = { NULL, 0 }; | 678 | gnutls_datum_t exponent = { NULL, 0 }; |
| 779 | 679 | ||
| @@ -800,7 +700,7 @@ userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record | |||
| 800 | ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, (int*)&modulus.size); | 700 | ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, (int*)&modulus.size); |
| 801 | ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, (int*)&exponent.size); | 701 | ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, (int*)&exponent.size); |
| 802 | if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2) | 702 | if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2) |
| 803 | uret = USERPREF_E_SUCCESS; | 703 | ret = USERPREF_E_SUCCESS; |
| 804 | } | 704 | } |
| 805 | if (asn1_pub_key) | 705 | if (asn1_pub_key) |
| 806 | asn1_delete_structure(&asn1_pub_key); | 706 | asn1_delete_structure(&asn1_pub_key); |
| @@ -810,83 +710,45 @@ userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record | |||
| 810 | } | 710 | } |
| 811 | 711 | ||
| 812 | /* now generate certificates */ | 712 | /* now generate certificates */ |
| 813 | if (USERPREF_E_SUCCESS == uret && 0 != modulus.size && 0 != exponent.size) { | 713 | if (USERPREF_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { |
| 814 | |||
| 815 | gnutls_global_init(); | ||
| 816 | gnutls_datum_t essentially_null = { (unsigned char*)strdup("abababababababab"), strlen("abababababababab") }; | 714 | gnutls_datum_t essentially_null = { (unsigned char*)strdup("abababababababab"), strlen("abababababababab") }; |
| 817 | 715 | ||
| 818 | gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey; | 716 | gnutls_x509_privkey_t fake_privkey; |
| 819 | gnutls_x509_crt_t dev_cert, root_cert, host_cert; | 717 | gnutls_x509_crt_t dev_cert; |
| 820 | 718 | ||
| 821 | gnutls_x509_privkey_init(&fake_privkey); | 719 | gnutls_x509_privkey_init(&fake_privkey); |
| 822 | gnutls_x509_privkey_init(&root_privkey); | ||
| 823 | gnutls_x509_privkey_init(&host_privkey); | ||
| 824 | |||
| 825 | gnutls_x509_crt_init(&dev_cert); | 720 | gnutls_x509_crt_init(&dev_cert); |
| 826 | gnutls_x509_crt_init(&root_cert); | ||
| 827 | gnutls_x509_crt_init(&host_cert); | ||
| 828 | |||
| 829 | if (GNUTLS_E_SUCCESS == | ||
| 830 | gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null, | ||
| 831 | &essentially_null, &essentially_null)) { | ||
| 832 | |||
| 833 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, root_cert); | ||
| 834 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, host_cert); | ||
| 835 | uret = pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, root_privkey); | ||
| 836 | uret = pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, host_privkey); | ||
| 837 | |||
| 838 | if (USERPREF_E_SUCCESS == uret) { | ||
| 839 | /* generate device certificate */ | ||
| 840 | gnutls_x509_crt_set_key(dev_cert, fake_privkey); | ||
| 841 | gnutls_x509_crt_set_serial(dev_cert, "\x00", 1); | ||
| 842 | gnutls_x509_crt_set_version(dev_cert, 3); | ||
| 843 | gnutls_x509_crt_set_ca_status(dev_cert, 0); | ||
| 844 | gnutls_x509_crt_set_activation_time(dev_cert, time(NULL)); | ||
| 845 | gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); | ||
| 846 | |||
| 847 | /* use custom hash generation for compatibility with the "Apple ecosystem" */ | ||
| 848 | const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1; | ||
| 849 | size_t hash_size = gnutls_hash_get_len(dig_sha1); | ||
| 850 | unsigned char hash[hash_size]; | ||
| 851 | if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { | ||
| 852 | debug_info("ERROR: Failed to generate SHA1 for public key"); | ||
| 853 | } else { | ||
| 854 | gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size); | ||
| 855 | } | ||
| 856 | 721 | ||
| 857 | gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT); | 722 | if (GNUTLS_E_SUCCESS == gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null, &essentially_null, &essentially_null)) { |
| 858 | gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey); | 723 | /* generate device certificate */ |
| 859 | 724 | gnutls_x509_crt_set_key(dev_cert, fake_privkey); | |
| 860 | if (LOCKDOWN_E_SUCCESS == ret) { | 725 | gnutls_x509_crt_set_serial(dev_cert, "\x00", 1); |
| 861 | /* if everything went well, export in PEM format */ | 726 | gnutls_x509_crt_set_version(dev_cert, 3); |
| 862 | size_t export_size = 0; | 727 | gnutls_x509_crt_set_ca_status(dev_cert, 0); |
| 863 | gnutls_datum_t dev_pem = { NULL, 0 }; | 728 | gnutls_x509_crt_set_activation_time(dev_cert, time(NULL)); |
| 864 | gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &export_size); | 729 | gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); |
| 865 | dev_pem.data = gnutls_malloc(export_size); | 730 | |
| 866 | gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &export_size); | 731 | /* use custom hash generation for compatibility with the "Apple ecosystem" */ |
| 867 | dev_pem.size = export_size; | 732 | const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1; |
| 868 | 733 | size_t hash_size = gnutls_hash_get_len(dig_sha1); | |
| 869 | gnutls_datum_t pem_root_cert = { NULL, 0 }; | 734 | unsigned char hash[hash_size]; |
| 870 | gnutls_datum_t pem_host_cert = { NULL, 0 }; | 735 | if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { |
| 871 | 736 | debug_info("ERROR: Failed to generate SHA1 for public key"); | |
| 872 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &pem_root_cert); | 737 | } else { |
| 873 | uret = pair_record_import_crt_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &pem_host_cert); | 738 | gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size); |
| 874 | 739 | } | |
| 875 | if (USERPREF_E_SUCCESS == uret) { | 740 | |
| 876 | /* set new keys and certs in pair record */ | 741 | gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT); |
| 877 | plist_dict_set_item(pair_record, USERPREF_DEVICE_CERTIFICATE_KEY, plist_new_data(dev_pem.data, dev_pem.size)); | 742 | gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey); |
| 878 | plist_dict_set_item(pair_record, USERPREF_HOST_CERTIFICATE_KEY, plist_new_data(pem_host_cert.data, pem_host_cert.size)); | 743 | |
| 879 | plist_dict_set_item(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, plist_new_data(pem_root_cert.data, pem_root_cert.size)); | 744 | if (USERPREF_E_SUCCESS == ret) { |
| 880 | plist_dict_set_item(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, plist_new_data(root_privkey.data, root_privkey.size)); | 745 | /* if everything went well, export in PEM format */ |
| 881 | plist_dict_set_item(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, plist_new_data(host_privkey.data, host_privkey.size)); | 746 | size_t export_size = 0; |
| 882 | 747 | gnutls_datum_t dev_pem = { NULL, 0 }; | |
| 883 | gnutls_free(pem_root_cert.data); | 748 | gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &export_size); |
| 884 | gnutls_free(pem_host_cert.data); | 749 | dev_pem.data = gnutls_malloc(export_size); |
| 885 | 750 | gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &export_size); | |
| 886 | if (dev_pem.data) | 751 | dev_pem.size = export_size; |
| 887 | gnutls_free(dev_pem.data); | ||
| 888 | } | ||
| 889 | } | ||
| 890 | } | 752 | } |
| 891 | } | 753 | } |
| 892 | 754 | ||
| @@ -894,19 +756,46 @@ userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record | |||
| 894 | free(essentially_null.data); | 756 | free(essentially_null.data); |
| 895 | 757 | ||
| 896 | gnutls_x509_crt_deinit(dev_cert); | 758 | gnutls_x509_crt_deinit(dev_cert); |
| 897 | gnutls_x509_crt_deinit(root_cert); | ||
| 898 | gnutls_x509_crt_deinit(host_cert); | ||
| 899 | gnutls_x509_privkey_deinit(fake_privkey); | 759 | gnutls_x509_privkey_deinit(fake_privkey); |
| 900 | gnutls_x509_privkey_deinit(root_privkey); | ||
| 901 | gnutls_x509_privkey_deinit(host_privkey); | ||
| 902 | } | 760 | } |
| 903 | 761 | ||
| 762 | gnutls_x509_crt_deinit(root_cert); | ||
| 763 | gnutls_x509_crt_deinit(host_cert); | ||
| 764 | gnutls_x509_privkey_deinit(root_privkey); | ||
| 765 | gnutls_x509_privkey_deinit(host_privkey); | ||
| 766 | |||
| 904 | gnutls_free(modulus.data); | 767 | gnutls_free(modulus.data); |
| 905 | gnutls_free(exponent.data); | 768 | gnutls_free(exponent.data); |
| 906 | 769 | ||
| 907 | gnutls_free(der_pub_key.data); | 770 | gnutls_free(der_pub_key.data); |
| 771 | |||
| 772 | /* restore gnutls env */ | ||
| 773 | gnutls_global_deinit(); | ||
| 774 | gnutls_global_init(); | ||
| 908 | #endif | 775 | #endif |
| 909 | return uret; | 776 | if (NULL != root_cert_pem.data && 0 != root_cert_pem.size && |
| 777 | NULL != host_cert_pem.data && 0 != host_cert_pem.size) | ||
| 778 | ret = USERPREF_E_SUCCESS; | ||
| 779 | |||
| 780 | /* now set keys and certificates */ | ||
| 781 | pair_record_set_item_from_key_data(pair_record, USERPREF_DEVICE_CERTIFICATE_KEY, &dev_cert_pem); | ||
| 782 | pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, &host_key_pem); | ||
| 783 | pair_record_set_item_from_key_data(pair_record, USERPREF_HOST_CERTIFICATE_KEY, &host_cert_pem); | ||
| 784 | pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_key_pem); | ||
| 785 | pair_record_set_item_from_key_data(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert_pem); | ||
| 786 | |||
| 787 | if (dev_cert_pem.data) | ||
| 788 | free(dev_cert_pem.data); | ||
| 789 | if (root_key_pem.data) | ||
| 790 | free(root_key_pem.data); | ||
| 791 | if (root_cert_pem.data) | ||
| 792 | free(root_cert_pem.data); | ||
| 793 | if (host_key_pem.data) | ||
| 794 | free(host_key_pem.data); | ||
| 795 | if (host_cert_pem.data) | ||
| 796 | free(host_cert_pem.data); | ||
| 797 | |||
| 798 | return ret; | ||
| 910 | } | 799 | } |
| 911 | 800 | ||
| 912 | /** | 801 | /** |
| @@ -933,7 +822,7 @@ userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const cha | |||
| 933 | ret = pair_record_get_item_as_key_data(pair_record, name, key); | 822 | ret = pair_record_get_item_as_key_data(pair_record, name, key); |
| 934 | #else | 823 | #else |
| 935 | key_data_t pem = { NULL, 0 }; | 824 | key_data_t pem = { NULL, 0 }; |
| 936 | ret = pair_record_get_item_as_key_data(pair_record, name, pem); | 825 | ret = pair_record_get_item_as_key_data(pair_record, name, &pem); |
| 937 | if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) | 826 | if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) |
| 938 | ret = USERPREF_E_SUCCESS; | 827 | ret = USERPREF_E_SUCCESS; |
| 939 | else | 828 | else |
| @@ -970,7 +859,7 @@ userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const cha | |||
| 970 | ret = pair_record_get_item_as_key_data(pair_record, name, cert); | 859 | ret = pair_record_get_item_as_key_data(pair_record, name, cert); |
| 971 | #else | 860 | #else |
| 972 | key_data_t pem = { NULL, 0 }; | 861 | key_data_t pem = { NULL, 0 }; |
| 973 | ret = pair_record_get_item_as_key_data(pair_record, name, pem); | 862 | ret = pair_record_get_item_as_key_data(pair_record, name, &pem); |
| 974 | if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) | 863 | if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) |
| 975 | ret = USERPREF_E_SUCCESS; | 864 | ret = USERPREF_E_SUCCESS; |
| 976 | else | 865 | else |
diff --git a/common/userpref.h b/common/userpref.h index a39417a..d9ce015 100644 --- a/common/userpref.h +++ b/common/userpref.h | |||
| @@ -75,8 +75,7 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor | |||
| 75 | userpref_error_t userpref_save_pair_record(const char *udid, plist_t pair_record); | 75 | userpref_error_t userpref_save_pair_record(const char *udid, plist_t pair_record); |
| 76 | userpref_error_t userpref_delete_pair_record(const char *udid); | 76 | userpref_error_t userpref_delete_pair_record(const char *udid); |
| 77 | 77 | ||
| 78 | LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record); | 78 | LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key); |
| 79 | LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_generate_from_device_public_key(plist_t pair_record, key_data_t public_key); | ||
| 80 | #ifdef HAVE_OPENSSL | 79 | #ifdef HAVE_OPENSSL |
| 81 | LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key); | 80 | LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key); |
| 82 | LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert); | 81 | LIBIMOBILEDEVICE_INTERNAL userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert); |
diff --git a/src/lockdown.c b/src/lockdown.c index aff682a..0efe30e 100644 --- a/src/lockdown.c +++ b/src/lockdown.c | |||
| @@ -852,21 +852,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t | |||
| 852 | *pair_record = plist_new_dict(); | 852 | *pair_record = plist_new_dict(); |
| 853 | 853 | ||
| 854 | userpref_error_t uret = USERPREF_E_SUCCESS; | 854 | userpref_error_t uret = USERPREF_E_SUCCESS; |
| 855 | uret = pair_record_generate_keys_and_certs(*pair_record); | 855 | uret = pair_record_generate_keys_and_certs(*pair_record, public_key); |
| 856 | switch(uret) { | ||
| 857 | case USERPREF_E_INVALID_ARG: | ||
| 858 | ret = LOCKDOWN_E_INVALID_ARG; | ||
| 859 | break; | ||
| 860 | case USERPREF_E_INVALID_CONF: | ||
| 861 | ret = LOCKDOWN_E_INVALID_CONF; | ||
| 862 | break; | ||
| 863 | case USERPREF_E_SSL_ERROR: | ||
| 864 | ret = LOCKDOWN_E_SSL_ERROR; | ||
| 865 | default: | ||
| 866 | break; | ||
| 867 | } | ||
| 868 | |||
| 869 | uret = pair_record_generate_from_device_public_key(*pair_record, public_key); | ||
| 870 | switch(uret) { | 856 | switch(uret) { |
| 871 | case USERPREF_E_INVALID_ARG: | 857 | case USERPREF_E_INVALID_ARG: |
| 872 | ret = LOCKDOWN_E_INVALID_ARG; | 858 | ret = LOCKDOWN_E_INVALID_ARG; |
