From d1ccd4eeebc94dac11140ae77b73392d0763d3a4 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Fri, 21 Mar 2014 00:16:29 +0100 Subject: Refactor pair record handling to use new usbmuxd pair record interface This refactoring is mandatory as libimobiledevice should not interact with the pair record configuration directory which is owned by the usbmuxd user. This change also adds compatibility for the native usbmuxd and thus pair records saved by iTunes. --- src/idevice.c | 31 ++-- src/lockdown.c | 530 ++++++++++++--------------------------------------------- src/lockdown.h | 5 - 3 files changed, 130 insertions(+), 436 deletions(-) (limited to 'src') diff --git a/src/idevice.c b/src/idevice.c index d01aa8f..c656517 100644 --- a/src/idevice.c +++ b/src/idevice.c @@ -511,7 +511,7 @@ static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, debug_info("pre-read client wants %zi bytes", length); - recv_buffer = (char *) malloc(sizeof(char) * this_len); + recv_buffer = (char *)malloc(sizeof(char) * this_len); /* repeat until we have the full data or an error occurs */ do { @@ -637,12 +637,12 @@ static const char *errorstring(int e) /** * Internally used gnutls callback function that gets called during handshake. */ -static int internal_cert_callback (gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st) +static int internal_cert_callback(gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st) { int res = -1; - gnutls_certificate_type_t type = gnutls_certificate_type_get (session); + gnutls_certificate_type_t type = gnutls_certificate_type_get(session); if (type == GNUTLS_CRT_X509) { - ssl_data_t ssl_data = (ssl_data_t)gnutls_session_get_ptr (session); + ssl_data_t ssl_data = (ssl_data_t)gnutls_session_get_ptr(session); if (ssl_data && ssl_data->host_privkey && ssl_data->host_cert) { debug_info("Passing certificate"); st->type = type; @@ -673,15 +673,20 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) idevice_error_t ret = IDEVICE_E_SSL_ERROR; uint32_t return_me = 0; + plist_t pair_record = NULL; + + userpref_read_pair_record(connection->udid, &pair_record); + if (!pair_record) { + debug_info("ERROR: Failed enabling SSL. Unable to read pair record for udid %s.", connection->udid); + return ret; + } #ifdef HAVE_OPENSSL key_data_t root_cert = { NULL, 0 }; key_data_t root_privkey = { NULL, 0 }; - userpref_error_t uerr = userpref_device_record_get_keys_and_certs(connection->udid, &root_privkey, &root_cert, NULL, NULL); - if (uerr != USERPREF_E_SUCCESS) { - debug_info("Error %d when loading keys and certificates! %d", uerr); - } + pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, &root_cert); + pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, &root_privkey); /* Set up OpenSSL */ if (openssl_init_done == 0) { @@ -756,7 +761,7 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) errno = 0; gnutls_global_init(); gnutls_certificate_allocate_credentials(&ssl_data_loc->certificate); - gnutls_certificate_client_set_retrieve_function (ssl_data_loc->certificate, internal_cert_callback); + gnutls_certificate_client_set_retrieve_function(ssl_data_loc->certificate, internal_cert_callback); gnutls_init(&ssl_data_loc->session, GNUTLS_CLIENT); gnutls_priority_set_direct(ssl_data_loc->session, "NONE:+VERS-SSL3.0:+ANON-DH:+RSA:+AES-128-CBC:+AES-256-CBC:+SHA1:+MD5:+COMP-NULL", NULL); gnutls_credentials_set(ssl_data_loc->session, GNUTLS_CRD_CERTIFICATE, ssl_data_loc->certificate); @@ -767,10 +772,10 @@ idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) gnutls_x509_privkey_init(&ssl_data_loc->root_privkey); gnutls_x509_privkey_init(&ssl_data_loc->host_privkey); - userpref_error_t uerr = userpref_device_record_get_keys_and_certs(connection->udid, ssl_data_loc->root_privkey, ssl_data_loc->root_cert, ssl_data_loc->host_privkey, ssl_data_loc->host_cert); - if (uerr != USERPREF_E_SUCCESS) { - debug_info("Error %d when loading keys and certificates! %d", uerr); - } + pair_record_import_key_with_name(pair_record, USERPREF_ROOT_CERTIFICATE_KEY, ssl_data_loc->root_cert); + pair_record_import_key_with_name(pair_record, USERPREF_HOST_CERTIFICATE_KEY, ssl_data_loc->host_cert); + pair_record_import_key_with_name(pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY, ssl_data_loc->root_privkey); + pair_record_import_key_with_name(pair_record, USERPREF_HOST_PRIVATE_KEY_KEY, ssl_data_loc->host_privkey); debug_info("GnuTLS step 1..."); gnutls_transport_set_ptr(ssl_data_loc->session, (gnutls_transport_ptr_t)connection); diff --git a/src/lockdown.c b/src/lockdown.c index e21db30..6ea747f 100644 --- a/src/lockdown.c +++ b/src/lockdown.c @@ -47,6 +47,7 @@ #include "idevice.h" #include "common/debug.h" #include "common/userpref.h" +#include "common/utils.h" #include "asprintf.h" #ifdef WIN32 @@ -57,17 +58,6 @@ #define RESULT_SUCCESS 0 #define RESULT_FAILURE 1 -#ifndef HAVE_OPENSSL -const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { - {"PKCS1", 536872976, 0}, - {0, 1073741836, 0}, - {"RSAPublicKey", 536870917, 0}, - {"modulus", 1073741827, 0}, - {"publicExponent", 3, 0}, - {0, 0, 0} -}; -#endif - /** * Internally used function for checking the result from lockdown's answer * plist to a previously sent request. @@ -618,7 +608,7 @@ lockdownd_error_t lockdownd_get_device_udid(lockdownd_client_t client, char **ud * * @return LOCKDOWN_E_SUCCESS on success */ -lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key) +static lockdownd_error_t lockdownd_get_device_public_key_as_key_data(lockdownd_client_t client, key_data_t *public_key) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t value = NULL; @@ -758,16 +748,27 @@ lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdown if (type) free(type); - userpref_device_record_get_host_id(client_loc->udid, &host_id); + debug_info("reading pair record"); + + plist_t pair_record = NULL; + userpref_read_pair_record(client_loc->udid, &pair_record); + + debug_info("reading HostID"); + + pair_record_get_host_id(pair_record, &host_id); if (LOCKDOWN_E_SUCCESS == ret && !host_id) { ret = LOCKDOWN_E_INVALID_CONF; } - if (LOCKDOWN_E_SUCCESS == ret && !userpref_has_device_record(client_loc->udid)) { + debug_info("HostID: %s", host_id); + + if (LOCKDOWN_E_SUCCESS == ret && !pair_record) { /* attempt pairing */ ret = lockdownd_pair(client_loc, NULL); } + plist_free(pair_record); + /* in any case, we need to validate pairing to receive trusted host status */ ret = lockdownd_validate_pair(client_loc, NULL); @@ -836,67 +837,69 @@ static plist_t lockdownd_pair_record_to_plist(lockdownd_pair_record_t pair_recor * * @return LOCKDOWN_E_SUCCESS on success */ -static lockdownd_error_t generate_pair_record_plist(lockdownd_client_t client, plist_t *pair_record_plist) +static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t *pair_record) { lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; + key_data_t public_key = { NULL, 0 }; char* host_id = NULL; char* system_buid = NULL; - key_data_t public_key = { NULL, 0 }; - key_data_t device_cert = { NULL, 0 }; - key_data_t host_cert = { NULL, 0 }; - key_data_t root_cert = { NULL, 0 }; - - /* load certificates if a pairing exists */ - userpref_error_t uret = userpref_device_record_get_certs_as_pem(client->udid, &root_cert, &host_cert, &device_cert); - if ((uret == USERPREF_E_SUCCESS) && (root_cert.size > 0) && (host_cert.size > 0) && (device_cert.size > 0)) { - ret = LOCKDOWN_E_SUCCESS; - } - - /* get systembuid and host id */ - userpref_get_system_buid(&system_buid); - userpref_device_record_get_host_id(client->udid, &host_id); - /* generate new certificates if needed */ + ret = lockdownd_get_device_public_key_as_key_data(client, &public_key); if (ret != LOCKDOWN_E_SUCCESS) { - ret = lockdownd_get_device_public_key(client, &public_key); - if (ret != LOCKDOWN_E_SUCCESS) { - debug_info("device refused to send public key."); - goto leave; - } - debug_info("device public key follows:\n%.*s", public_key.size, public_key.data); + debug_info("device refused to send public key."); + goto leave; + } + debug_info("device public key follows:\n%.*s", public_key.size, public_key.data); - userpref_device_record_set_value(client->udid, USERPREF_SYSTEM_BUID_KEY, plist_new_string(system_buid)); + host_id = generate_uuid(); - ret = lockdownd_gen_pair_cert_for_udid(client->udid, public_key, &device_cert, &host_cert, &root_cert); + *pair_record = plist_new_dict(); + + userpref_error_t uret = USERPREF_E_SUCCESS; + uret = pair_record_generate_keys_and_certs(pair_record); + switch(uret) { + case USERPREF_E_INVALID_ARG: + ret = LOCKDOWN_E_INVALID_ARG; + break; + case USERPREF_E_INVALID_CONF: + ret = LOCKDOWN_E_INVALID_CONF; + break; + case USERPREF_E_SSL_ERROR: + ret = LOCKDOWN_E_SSL_ERROR; + default: + break; + } + + uret = pair_record_generate_from_device_public_key(pair_record, public_key); + switch(uret) { + case USERPREF_E_INVALID_ARG: + ret = LOCKDOWN_E_INVALID_ARG; + break; + case USERPREF_E_INVALID_CONF: + ret = LOCKDOWN_E_INVALID_CONF; + break; + case USERPREF_E_SSL_ERROR: + ret = LOCKDOWN_E_SSL_ERROR; + default: + break; } + /* get systembuid and host id */ + userpref_read_system_buid(&system_buid); + + pair_record_set_host_id(pair_record, host_id); + if (ret != LOCKDOWN_E_SUCCESS) { goto leave; } - /* setup request plist */ - *pair_record_plist = plist_new_dict(); - plist_dict_set_item(*pair_record_plist, "DeviceCertificate", plist_new_data((const char*)device_cert.data, device_cert.size)); - plist_dict_set_item(*pair_record_plist, "HostCertificate", plist_new_data((const char*)host_cert.data, host_cert.size)); - plist_dict_set_item(*pair_record_plist, "HostID", plist_new_string(host_id)); - plist_dict_set_item(*pair_record_plist, "RootCertificate", plist_new_data((const char*)root_cert.data, root_cert.size)); - plist_dict_set_item(*pair_record_plist, "SystemBUID", plist_new_string(system_buid)); - leave: if (host_id) free(host_id); if (system_buid) free(system_buid); - if (public_key.data) - free(public_key.data); - if (device_cert.data) - free(device_cert.data); - if (host_cert.data) - free(host_cert.data); - if (root_cert.data) - free(root_cert.data); return ret; } @@ -923,7 +926,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; plist_t dict = NULL; - plist_t dict_record = NULL; + plist_t pair_record_plist = NULL; int pairing_mode = 0; /* 0 = libimobiledevice, 1 = external */ if (pair_record && pair_record->system_buid && pair_record->host_id) { @@ -933,36 +936,39 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ } /* use passed pair_record */ - dict_record = lockdownd_pair_record_to_plist(pair_record); + pair_record_plist = lockdownd_pair_record_to_plist(pair_record); pairing_mode = 1; } else { - ret = generate_pair_record_plist(client, &dict_record); - - if (ret != LOCKDOWN_E_SUCCESS) { - if (dict_record) - plist_free(dict_record); - return ret; + /* generate a new pair record if pairing */ + if (!strcmp("Pair", verb)) { + ret = pair_record_generate(client, &pair_record_plist); + + if (ret != LOCKDOWN_E_SUCCESS) { + if (pair_record_plist) + plist_free(pair_record_plist); + return ret; + } + } else { + /* use existing pair record */ + if (userpref_has_pair_record(client->udid)) { + userpref_read_pair_record(client->udid, &pair_record_plist); + } else { + return LOCKDOWN_E_PAIRING_FAILED; + } } } - if (!strcmp("Pair", verb)) { - /* get wifi mac */ - plist_t wifi_mac_node = NULL; - lockdownd_get_value(client, NULL, "WiFiAddress", &wifi_mac_node); + plist_t request_pair_record = plist_copy(pair_record_plist); - /* save wifi mac address in config */ - if (wifi_mac_node) { - userpref_device_record_set_value(client->udid, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(wifi_mac_node)); - plist_free(wifi_mac_node); - wifi_mac_node = NULL; - } - } + /* remove stuff that is private */ + plist_dict_remove_item(request_pair_record, USERPREF_ROOT_PRIVATE_KEY_KEY); + plist_dict_remove_item(request_pair_record, USERPREF_HOST_PRIVATE_KEY_KEY); /* setup pair request plist */ dict = plist_new_dict(); plist_dict_add_label(dict, client->label); - plist_dict_set_item(dict, "PairRecord", plist_copy(dict_record)); + plist_dict_set_item(dict, "PairRecord", request_pair_record); plist_dict_set_item(dict, "Request", plist_new_string(verb)); plist_dict_set_item(dict, "ProtocolVersion", plist_new_string(LOCKDOWN_PROTOCOL_VERSION)); @@ -976,7 +982,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ dict = NULL; if (ret != LOCKDOWN_E_SUCCESS) { - plist_free(dict_record); + plist_free(pair_record_plist); return ret; } @@ -984,7 +990,7 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ ret = lockdownd_receive(client, &dict); if (ret != LOCKDOWN_E_SUCCESS) { - plist_free(dict_record); + plist_free(pair_record_plist); return ret; } @@ -1007,24 +1013,32 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ debug_info("internal pairing mode"); if (!strcmp("Unpair", verb)) { /* remove public key from config */ - userpref_remove_device_record(client->udid); + userpref_delete_pair_record(client->udid); } else { if (!strcmp("Pair", verb)) { - debug_info("getting EscrowBag from response"); + debug_info("Saving EscrowBag from response in pair record"); /* add returned escrow bag if available */ - plist_t escrow_bag = plist_dict_get_item(dict, "EscrowBag"); - if (escrow_bag && plist_get_node_type(escrow_bag) == PLIST_DATA) { - userpref_device_record_set_value(client->udid, USERPREF_ESCROW_BAG_KEY, plist_copy(escrow_bag)); - plist_free(escrow_bag); - escrow_bag = NULL; + plist_t extra_node = plist_dict_get_item(dict, USERPREF_ESCROW_BAG_KEY); + if (extra_node && plist_get_node_type(extra_node) == PLIST_DATA) { + plist_dict_set_item(pair_record_plist, USERPREF_ESCROW_BAG_KEY, plist_copy(extra_node)); + plist_free(extra_node); + extra_node = NULL; } - /* store DeviceCertificate upon successful pairing */ - plist_t devcrt = plist_dict_get_item(dict_record, USERPREF_DEVICE_CERTIFICATE_KEY); - if (devcrt && plist_get_node_type(devcrt) == PLIST_DATA) { - userpref_device_record_set_value(client->udid, USERPREF_DEVICE_CERTIFICATE_KEY, plist_copy(devcrt)); + debug_info("Saving WiFiAddress from device in pair record"); + + /* get wifi mac */ + lockdownd_get_value(client, NULL, "WiFiAddress", &extra_node); + + /* save wifi mac address in config */ + if (extra_node) { + plist_dict_set_item(pair_record_plist, USERPREF_WIFI_MAC_ADDRESS_KEY, plist_copy(extra_node)); + plist_free(extra_node); + extra_node = NULL; } + + userpref_save_pair_record(client->udid, pair_record_plist); } } } else { @@ -1057,9 +1071,9 @@ static lockdownd_error_t lockdownd_do_pair(lockdownd_client_t client, lockdownd_ } } - if (dict_record) { - plist_free(dict_record); - dict_record = NULL; + if (pair_record_plist) { + plist_free(pair_record_plist); + pair_record_plist = NULL; } plist_free(dict); @@ -1205,332 +1219,6 @@ lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) return ret; } -/** - * Generates the device certificate from the public key as well as the host - * and root certificates. - * - * @param public_key The public key of the device to use for generation. - * @param odevice_cert Holds the generated device certificate. - * @param ohost_cert Holds the generated host certificate. - * @param oroot_cert Holds the generated root certificate. - * - * @return LOCKDOWN_E_SUCCESS on success, LOCKDOWN_E_INVALID_ARG when a - * parameter is NULL, LOCKDOWN_E_INVALID_CONF if the internal configuration - * system failed, LOCKDOWN_E_SSL_ERROR if the certificates could not be - * generated - */ -lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * odevice_cert, - key_data_t * ohost_cert, key_data_t * oroot_cert) -{ - if (!public_key.data || !odevice_cert || !ohost_cert || !oroot_cert) - return LOCKDOWN_E_INVALID_ARG; - - lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR; - userpref_error_t uret = USERPREF_E_UNKNOWN_ERROR; - -#ifdef HAVE_OPENSSL - BIO *membio = BIO_new_mem_buf(public_key.data, public_key.size); - RSA *pubkey = NULL; - if (!PEM_read_bio_RSAPublicKey(membio, &pubkey, NULL, NULL)) { - debug_info("Could not read public key"); - } - BIO_free(membio); - - /* now generate certificates */ - key_data_t root_privkey, host_privkey; - key_data_t root_cert, host_cert; - X509* dev_cert; - - root_cert.data = NULL; - root_cert.size = 0; - host_cert.data = NULL; - host_cert.size = 0; - - dev_cert = X509_new(); - - root_privkey.data = NULL; - root_privkey.size = 0; - host_privkey.data = NULL; - host_privkey.size = 0; - - uret = userpref_device_record_get_keys_and_certs(udid, &root_privkey, &root_cert, &host_privkey, &host_cert); - if (USERPREF_E_SUCCESS == uret) { - /* generate device certificate */ - ASN1_INTEGER* sn = ASN1_INTEGER_new(); - ASN1_INTEGER_set(sn, 0); - X509_set_serialNumber(dev_cert, sn); - ASN1_INTEGER_free(sn); - X509_set_version(dev_cert, 2); - - X509_EXTENSION* ext; - if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (char*)"critical,CA:FALSE"))) { - debug_info("ERROR: X509V3_EXT_conf_nid failedĀ for Basic Constraints"); - } - X509_add_ext(dev_cert, ext, -1); - X509_EXTENSION_free(ext); - - ASN1_TIME* asn1time = ASN1_TIME_new(); - ASN1_TIME_set(asn1time, time(NULL)); - X509_set_notBefore(dev_cert, asn1time); - ASN1_TIME_set(asn1time, time(NULL) + (60 * 60 * 24 * 365 * 10)); - X509_set_notAfter(dev_cert, asn1time); - ASN1_TIME_free(asn1time); - - BIO* membp; - - X509* rootCert = NULL; - membp = BIO_new_mem_buf(root_cert.data, root_cert.size); - PEM_read_bio_X509(membp, &rootCert, NULL, NULL); - BIO_free(membp); - if (!rootCert) { - debug_info("Could not read RootCertificate"); - } else { - debug_info("RootCertificate loaded"); - EVP_PKEY* pkey = EVP_PKEY_new(); - EVP_PKEY_assign_RSA(pkey, pubkey); - X509_set_pubkey(dev_cert, pkey); - EVP_PKEY_free(pkey); - X509_free(rootCert); - } - - X509V3_CTX ctx; - X509V3_set_ctx_nodb(&ctx); - X509V3_set_ctx(&ctx, NULL, dev_cert, NULL, NULL, 0); - - if (!(ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, (char*)"hash"))) { - debug_info("ERROR: X509V3_EXT_conf_nid failed for Subject Key identifier"); - } - X509_add_ext(dev_cert, ext, -1); - X509_EXTENSION_free(ext); - - if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment"))) { - debug_info("ERROR: X509V3_EXT_conf_nid failed for Key Usage"); - } - X509_add_ext(dev_cert, ext, -1); - X509_EXTENSION_free(ext); - - EVP_PKEY* rootPriv = NULL; - membp = BIO_new_mem_buf(root_privkey.data, root_privkey.size); - PEM_read_bio_PrivateKey(membp, &rootPriv, NULL, NULL); - BIO_free(membp); - if (!rootPriv) { - debug_info("Could not read RootPrivateKey"); - } else { - debug_info("RootPrivateKey loaded"); - if (X509_sign(dev_cert, rootPriv, EVP_sha1())) { - ret = LOCKDOWN_E_SUCCESS; - } else { - debug_info("signing failed"); - } - EVP_PKEY_free(rootPriv); - } - - if (LOCKDOWN_E_SUCCESS == ret) { - /* if everything went well, export in PEM format */ - key_data_t pem_root_cert = { NULL, 0 }; - key_data_t pem_host_cert = { NULL, 0 }; - - uret = userpref_device_record_get_certs_as_pem(udid, &pem_root_cert, &pem_host_cert, NULL); - if (USERPREF_E_SUCCESS == uret) { - /* copy buffer for output */ - membp = BIO_new(BIO_s_mem()); - if (membp && PEM_write_bio_X509(membp, dev_cert) > 0) { - void *datap; - odevice_cert->size = BIO_get_mem_data(membp, &datap); - odevice_cert->data = malloc(odevice_cert->size); - memcpy(odevice_cert->data, datap, odevice_cert->size); - } - if (membp) - BIO_free(membp); - - ohost_cert->data = malloc(pem_host_cert.size); - memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size); - ohost_cert->size = pem_host_cert.size; - - oroot_cert->data = malloc(pem_root_cert.size); - memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size); - oroot_cert->size = pem_root_cert.size; - - free(pem_root_cert.data); - free(pem_host_cert.data); - } - } - } - X509V3_EXT_cleanup(); - X509_free(dev_cert); - - switch(uret) { - case USERPREF_E_INVALID_ARG: - ret = LOCKDOWN_E_INVALID_ARG; - break; - case USERPREF_E_INVALID_CONF: - ret = LOCKDOWN_E_INVALID_CONF; - break; - case USERPREF_E_SSL_ERROR: - ret = LOCKDOWN_E_SSL_ERROR; - default: - break; - } - - if (root_cert.data) - free(root_cert.data); - if (host_cert.data) - free(host_cert.data); - if (root_privkey.data) - free(root_privkey.data); - if (host_privkey.data) - free(host_privkey.data); -#else - gnutls_datum_t modulus = { NULL, 0 }; - gnutls_datum_t exponent = { NULL, 0 }; - - /* now decode the PEM encoded key */ - gnutls_datum_t der_pub_key; - if (GNUTLS_E_SUCCESS == gnutls_pem_base64_decode_alloc("RSA PUBLIC KEY", &public_key, &der_pub_key)) { - - /* initalize asn.1 parser */ - ASN1_TYPE pkcs1 = ASN1_TYPE_EMPTY; - if (ASN1_SUCCESS == asn1_array2tree(pkcs1_asn1_tab, &pkcs1, NULL)) { - - ASN1_TYPE asn1_pub_key = ASN1_TYPE_EMPTY; - asn1_create_element(pkcs1, "PKCS1.RSAPublicKey", &asn1_pub_key); - - if (ASN1_SUCCESS == asn1_der_decoding(&asn1_pub_key, der_pub_key.data, der_pub_key.size, NULL)) { - - /* get size to read */ - int ret1 = asn1_read_value(asn1_pub_key, "modulus", NULL, (int*)&modulus.size); - int ret2 = asn1_read_value(asn1_pub_key, "publicExponent", NULL, (int*)&exponent.size); - - modulus.data = gnutls_malloc(modulus.size); - exponent.data = gnutls_malloc(exponent.size); - - ret1 = asn1_read_value(asn1_pub_key, "modulus", modulus.data, (int*)&modulus.size); - ret2 = asn1_read_value(asn1_pub_key, "publicExponent", exponent.data, (int*)&exponent.size); - if (ASN1_SUCCESS == ret1 && ASN1_SUCCESS == ret2) - ret = LOCKDOWN_E_SUCCESS; - } - if (asn1_pub_key) - asn1_delete_structure(&asn1_pub_key); - } - if (pkcs1) - asn1_delete_structure(&pkcs1); - } - - /* now generate certificates */ - if (LOCKDOWN_E_SUCCESS == ret && 0 != modulus.size && 0 != exponent.size) { - - gnutls_global_init(); - gnutls_datum_t essentially_null = { (unsigned char*)strdup("abababababababab"), strlen("abababababababab") }; - - gnutls_x509_privkey_t fake_privkey, root_privkey, host_privkey; - gnutls_x509_crt_t dev_cert, root_cert, host_cert; - - gnutls_x509_privkey_init(&fake_privkey); - gnutls_x509_privkey_init(&root_privkey); - gnutls_x509_privkey_init(&host_privkey); - - gnutls_x509_crt_init(&dev_cert); - gnutls_x509_crt_init(&root_cert); - gnutls_x509_crt_init(&host_cert); - - if (GNUTLS_E_SUCCESS == - gnutls_x509_privkey_import_rsa_raw(fake_privkey, &modulus, &exponent, &essentially_null, &essentially_null, - &essentially_null, &essentially_null)) { - - uret = userpref_device_record_get_keys_and_certs(udid, root_privkey, root_cert, host_privkey, host_cert); - - if (USERPREF_E_SUCCESS == uret) { - /* generate device certificate */ - gnutls_x509_crt_set_key(dev_cert, fake_privkey); - gnutls_x509_crt_set_serial(dev_cert, "\x00", 1); - gnutls_x509_crt_set_version(dev_cert, 3); - gnutls_x509_crt_set_ca_status(dev_cert, 0); - gnutls_x509_crt_set_activation_time(dev_cert, time(NULL)); - gnutls_x509_crt_set_expiration_time(dev_cert, time(NULL) + (60 * 60 * 24 * 365 * 10)); - - /* use custom hash generation for compatibility with the "Apple ecosystem" */ - const gnutls_digest_algorithm_t dig_sha1 = GNUTLS_DIG_SHA1; - size_t hash_size = gnutls_hash_get_len(dig_sha1); - unsigned char hash[hash_size]; - if (gnutls_hash_fast(dig_sha1, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) { - debug_info("ERROR: Failed to generate SHA1 for public key"); - } else { - gnutls_x509_crt_set_subject_key_id(dev_cert, hash, hash_size); - } - - gnutls_x509_crt_set_key_usage(dev_cert, GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT); - gnutls_x509_crt_sign(dev_cert, root_cert, root_privkey); - - if (LOCKDOWN_E_SUCCESS == ret) { - /* if everything went well, export in PEM format */ - size_t export_size = 0; - gnutls_datum_t dev_pem = { NULL, 0 }; - gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, NULL, &export_size); - dev_pem.data = gnutls_malloc(export_size); - gnutls_x509_crt_export(dev_cert, GNUTLS_X509_FMT_PEM, dev_pem.data, &export_size); - dev_pem.size = export_size; - - gnutls_datum_t pem_root_cert = { NULL, 0 }; - gnutls_datum_t pem_host_cert = { NULL, 0 }; - - uret = userpref_device_record_get_certs_as_pem(udid, &pem_root_cert, &pem_host_cert, NULL); - - if (USERPREF_E_SUCCESS == uret) { - /* copy buffer for output */ - odevice_cert->data = malloc(dev_pem.size); - memcpy(odevice_cert->data, dev_pem.data, dev_pem.size); - odevice_cert->size = dev_pem.size; - - ohost_cert->data = malloc(pem_host_cert.size); - memcpy(ohost_cert->data, pem_host_cert.data, pem_host_cert.size); - ohost_cert->size = pem_host_cert.size; - - oroot_cert->data = malloc(pem_root_cert.size); - memcpy(oroot_cert->data, pem_root_cert.data, pem_root_cert.size); - oroot_cert->size = pem_root_cert.size; - - gnutls_free(pem_root_cert.data); - gnutls_free(pem_host_cert.data); - - if (dev_pem.data) - gnutls_free(dev_pem.data); - } - } - } - - switch(uret) { - case USERPREF_E_INVALID_ARG: - ret = LOCKDOWN_E_INVALID_ARG; - break; - case USERPREF_E_INVALID_CONF: - ret = LOCKDOWN_E_INVALID_CONF; - break; - case USERPREF_E_SSL_ERROR: - ret = LOCKDOWN_E_SSL_ERROR; - default: - break; - } - } - - if (essentially_null.data) - free(essentially_null.data); - gnutls_x509_crt_deinit(dev_cert); - gnutls_x509_crt_deinit(root_cert); - gnutls_x509_crt_deinit(host_cert); - gnutls_x509_privkey_deinit(fake_privkey); - gnutls_x509_privkey_deinit(root_privkey); - gnutls_x509_privkey_deinit(host_privkey); - - } - - gnutls_free(modulus.data); - gnutls_free(exponent.data); - - gnutls_free(der_pub_key.data); -#endif - return ret; -} - /** * Opens a session with lockdownd and switches to SSL mode if device wants it. * @@ -1569,7 +1257,7 @@ lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, const char /* add system buid */ char *system_buid = NULL; - userpref_get_system_buid(&system_buid); + userpref_read_system_buid(&system_buid); if (system_buid) { plist_dict_set_item(dict, "SystemBUID", plist_new_string(system_buid)); if (system_buid) { @@ -1671,8 +1359,14 @@ lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, const char (*service)->ssl_enabled = 0; } + plist_t pair_record = NULL; + userpref_read_pair_record(client->udid, &pair_record); + char *host_id = NULL; - userpref_device_record_get_host_id(client->udid, &host_id); + pair_record_get_host_id(pair_record, &host_id); + + plist_free(pair_record); + if (!host_id) return LOCKDOWN_E_INVALID_CONF; diff --git a/src/lockdown.h b/src/lockdown.h index 9c2be44..a09e89b 100644 --- a/src/lockdown.h +++ b/src/lockdown.h @@ -22,8 +22,6 @@ #ifndef __LOCKDOWND_H #define __LOCKDOWND_H -#include "common/userpref.h" - #include "libimobiledevice/lockdown.h" #include "property_list_service.h" @@ -37,7 +35,4 @@ struct lockdownd_client_private { char *label; }; -lockdownd_error_t lockdownd_get_device_public_key(lockdownd_client_t client, key_data_t * public_key); -lockdownd_error_t lockdownd_gen_pair_cert_for_udid(const char *udid, key_data_t public_key, key_data_t * device_cert, key_data_t * host_cert, key_data_t * root_cert); - #endif -- cgit v1.1-32-gdbae