diff options
-rw-r--r-- | README.md | 17 | ||||
-rw-r--r-- | common/userpref.c | 316 | ||||
-rw-r--r-- | common/userpref.h | 4 | ||||
-rw-r--r-- | configure.ac | 113 | ||||
-rw-r--r-- | src/Makefile.am | 11 | ||||
-rw-r--r-- | src/idevice.c | 195 | ||||
-rw-r--r-- | src/idevice.h | 19 | ||||
-rw-r--r-- | tools/Makefile.am | 16 | ||||
-rw-r--r-- | tools/idevicebackup.c | 137 |
9 files changed, 626 insertions, 202 deletions
@@ -94,10 +94,19 @@ make sudo make install ``` -By default, OpenSSL will be used. If you prefer GnuTLS, configure with -`--disable-openssl` like this: +By default, OpenSSL will be used as TLS/SSL library. If you prefer GnuTLS, +configure with `--with-gnutls` like this: ```bash -./autogen.sh --disable-openssl +./autogen.sh --with-gnutls +``` + +MbedTLS is also supported and can be enabled by passing `--with-mbedtls` to +configure. If mbedTLS is not installed in a default location, you need to set +the environment variables `mbedtls_INCLUDES` to the path that contains the +MbedTLS headers and `mbedtls_LIBDIR` to set the library path. Optionally, +`mbedtls_LIBS` can be used to set the library names directly. Example: +```bash +./autogen.sh --with-mbedtls mbedtls_INCLUDES=/opt/local/include mbedtls_LIBDIR=/opt/local/lib ``` ## Usage @@ -179,4 +188,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. This project is an independent software and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2020-06-12 +README Updated on: 2021-07-27 diff --git a/common/userpref.c b/common/userpref.c index a5aa7cb..0c6050f 100644 --- a/common/userpref.c +++ b/common/userpref.c @@ -2,6 +2,7 @@ * userpref.c * contains methods to access user specific certificates IDs and more. * + * Copyright (c) 2013-2021 Nikias Bassen, All Rights Reserved. * Copyright (c) 2013-2014 Martin Szulecki All Rights Reserved. * Copyright (c) 2008 Jonathan Beck All Rights Reserved. * @@ -36,7 +37,7 @@ #endif #include <unistd.h> #include <usbmuxd.h> -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) #include <openssl/bn.h> #include <openssl/pem.h> #include <openssl/rsa.h> @@ -47,12 +48,20 @@ #define X509_set1_notBefore X509_set_notBefore #define X509_set1_notAfter X509_set_notAfter #endif -#else +#elif defined(HAVE_GNUTLS) #include <gnutls/gnutls.h> #include <gnutls/crypto.h> #include <gnutls/x509.h> #include <gcrypt.h> #include <libtasn1.h> +#elif defined(HAVE_MBEDTLS) +#include <mbedtls/ssl.h> +#include <mbedtls/entropy.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/asn1write.h> +#include <mbedtls/oid.h> +#else +#error No supported TLS/SSL library enabled #endif #include <dirent.h> @@ -68,7 +77,7 @@ #include "debug.h" #include "utils.h" -#ifndef HAVE_OPENSSL +#if defined(HAVE_GNUTLS) const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = { {"PKCS1", 536872976, 0}, {0, 1073741836, 0}, @@ -343,7 +352,7 @@ userpref_error_t userpref_delete_pair_record(const char *udid) return res == 0 ? USERPREF_E_SUCCESS: USERPREF_E_UNKNOWN_ERROR; } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) static int X509_add_ext_helper(X509 *cert, int nid, char *value) { X509_EXTENSION *ex; @@ -364,6 +373,31 @@ static int X509_add_ext_helper(X509 *cert, int nid, char *value) return 1; } +#elif defined(HAVE_MBEDTLS) +static int _mbedtls_x509write_crt_set_basic_constraints_critical(mbedtls_x509write_cert *ctx, int is_ca, int max_pathlen) +{ + int ret; + unsigned char buf[9]; + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + + if (is_ca && max_pathlen > 127) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if (is_ca) { + if (max_pathlen >= 0) { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) ); + } + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), 1, buf + sizeof(buf) - len, len ); +} #endif /** @@ -390,7 +424,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da debug_info("Generating keys and certificates..."); -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) BIGNUM *e = BN_new(); RSA* root_keypair = RSA_new(); RSA* host_keypair = RSA_new(); @@ -579,7 +613,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da X509_free(host_cert); X509_free(root_cert); -#else +#elif defined(HAVE_GNUTLS) gnutls_x509_privkey_t root_privkey; gnutls_x509_crt_t root_cert; gnutls_x509_privkey_t host_privkey; @@ -749,6 +783,211 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da gnutls_free(exponent.data); gnutls_free(der_pub_key.data); +#elif defined(HAVE_MBEDTLS) + time_t now = time(NULL); + struct tm* timestamp = gmtime(&now); + char notbefore[16]; + strftime(notbefore, sizeof(notbefore), "%Y%m%d%H%M%S", timestamp); + time_t then = now + 60 * 60 * 24 * 365 * 10; + char notafter[16]; + timestamp = gmtime(&then); + strftime(notafter, sizeof(notafter), "%Y%m%d%H%M%S", timestamp); + + mbedtls_mpi sn; + mbedtls_mpi_init(&sn); + mbedtls_mpi_lset(&sn, 1); /* 0 doesn't work, so we have to use 1 (like GnuTLS) */ + + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ctr_drbg_init(&ctr_drbg); + + mbedtls_pk_context root_pkey; + mbedtls_pk_init(&root_pkey); + + mbedtls_pk_context host_pkey; + mbedtls_pk_init(&host_pkey); + + mbedtls_pk_context dev_public_key; + mbedtls_pk_init(&dev_public_key); + + mbedtls_entropy_context entropy; + mbedtls_entropy_init(&entropy); + + mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)"limd", 4); + + /* ----- root key & cert ----- */ + ret = mbedtls_pk_setup(&root_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + if (ret != 0) { + debug_info("mbedtls_pk_setup returned -0x%04x", -ret); + goto cleanup; + } + + ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(root_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537); + if (ret != 0) { + debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret); + goto cleanup; + } + + mbedtls_x509write_cert cert; + mbedtls_x509write_crt_init(&cert); + + /* set serial number */ + mbedtls_x509write_crt_set_serial(&cert, &sn); + + /* set version */ + mbedtls_x509write_crt_set_version(&cert, 2); + + /* set x509v3 basic constraints */ + _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 1, -1); + + /* use root public key for root cert */ + mbedtls_x509write_crt_set_subject_key(&cert, &root_pkey); + + /* set x509v3 subject key identifier */ + mbedtls_x509write_crt_set_subject_key_identifier(&cert); + + /* set key validity */ + mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter); + + /* sign root cert with root private key */ + mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); + mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); + + unsigned char outbuf[16384]; + + /* write root private key */ + mbedtls_pk_write_key_pem(&root_pkey, outbuf, sizeof(outbuf)); + root_key_pem.size = strlen((const char*)outbuf); + root_key_pem.data = malloc(root_key_pem.size+1); + memcpy(root_key_pem.data, outbuf, root_key_pem.size); + root_key_pem.data[root_key_pem.size] = '\0'; + + /* write root certificate */ + mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); + root_cert_pem.size = strlen((const char*)outbuf); + root_cert_pem.data = malloc(root_cert_pem.size+1); + memcpy(root_cert_pem.data, outbuf, root_cert_pem.size); + root_cert_pem.data[root_cert_pem.size] = '\0'; + + mbedtls_x509write_crt_free(&cert); + + + /* ----- host key & cert ----- */ + ret = mbedtls_pk_setup(&host_pkey, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + if (ret != 0) { + debug_info("mbedtls_pk_setup returned -0x%04x", -ret); + goto cleanup; + } + + ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(host_pkey), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537); + if (ret != 0) { + debug_info("mbedtls_rsa_gen_key returned -0x%04x", -ret); + goto cleanup; + } + + mbedtls_x509write_crt_init(&cert); + + /* set serial number */ + mbedtls_x509write_crt_set_serial(&cert, &sn); + + /* set version */ + mbedtls_x509write_crt_set_version(&cert, 2); + + /* set x509v3 basic constraints */ + _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1); + + /* use host public key for host cert */ + mbedtls_x509write_crt_set_subject_key(&cert, &host_pkey); + + /* set x509v3 subject key identifier */ + mbedtls_x509write_crt_set_subject_key_identifier(&cert); + + /* set x509v3 key usage */ + mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT); + + /* set key validity */ + mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter); + + /* sign host cert with root private key */ + mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); + mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); + + /* write host private key */ + mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf)); + host_key_pem.size = strlen((const char*)outbuf); + host_key_pem.data = malloc(host_key_pem.size+1); + memcpy(host_key_pem.data, outbuf, host_key_pem.size); + host_key_pem.data[host_key_pem.size] = '\0'; + + /* write host certificate */ + mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); + host_cert_pem.size = strlen((const char*)outbuf); + host_cert_pem.data = malloc(host_cert_pem.size+1); + memcpy(host_cert_pem.data, outbuf, host_cert_pem.size); + host_cert_pem.data[host_cert_pem.size] = '\0'; + + mbedtls_x509write_crt_free(&cert); + + + /* ----- device certificate ----- */ + unsigned char* pubkey_data = malloc(public_key.size+1); + if (!pubkey_data) { + debug_info("malloc() failed\n"); + goto cleanup; + } + memcpy(pubkey_data, public_key.data, public_key.size); + pubkey_data[public_key.size] = '\0'; + + int pr = mbedtls_pk_parse_public_key(&dev_public_key, pubkey_data, public_key.size+1); + free(pubkey_data); + if (pr != 0) { + debug_info("Failed to read device public key: -0x%x\n", -pr); + goto cleanup; + } + + mbedtls_x509write_crt_init(&cert); + + /* set serial number */ + mbedtls_x509write_crt_set_serial(&cert, &sn); + + /* set version */ + mbedtls_x509write_crt_set_version(&cert, 2); + + /* set x509v3 basic constraints */ + _mbedtls_x509write_crt_set_basic_constraints_critical(&cert, 0, -1); + + /* use root public key for dev cert subject key */ + mbedtls_x509write_crt_set_subject_key(&cert, &dev_public_key); + + /* set x509v3 subject key identifier */ + mbedtls_x509write_crt_set_subject_key_identifier(&cert); + + /* set x509v3 key usage */ + mbedtls_x509write_crt_set_key_usage(&cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_ENCIPHERMENT); + + /* set key validity */ + mbedtls_x509write_crt_set_validity(&cert, notbefore, notafter); + + /* sign device certificate with root private key */ + mbedtls_x509write_crt_set_issuer_key(&cert, &root_pkey); + mbedtls_x509write_crt_set_md_alg(&cert, MBEDTLS_MD_SHA1); + + /* write device certificate */ + mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg); + dev_cert_pem.size = strlen((const char*)outbuf); + dev_cert_pem.data = malloc(dev_cert_pem.size+1); + memcpy(dev_cert_pem.data, outbuf, dev_cert_pem.size); + dev_cert_pem.data[dev_cert_pem.size] = '\0'; + + mbedtls_x509write_crt_free(&cert); + + /* cleanup */ +cleanup: + mbedtls_mpi_free(&sn); + mbedtls_pk_free(&dev_public_key); + mbedtls_entropy_free(&entropy); + mbedtls_pk_free(&host_pkey); + mbedtls_pk_free(&root_pkey); + mbedtls_ctr_drbg_free(&ctr_drbg); #endif /* make sure that we have all we need */ @@ -783,32 +1022,31 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da * * @return 1 if the key was successfully imported. */ -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key) -#else +#elif defined(HAVE_GNUTLS) userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, gnutls_x509_privkey_t key) #endif { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) if (!key) return USERPREF_E_SUCCESS; #endif userpref_error_t ret = USERPREF_E_INVALID_CONF; -#ifdef HAVE_OPENSSL - ret = pair_record_get_item_as_key_data(pair_record, name, key); -#else - key_data_t pem = { NULL, 0 }; - ret = pair_record_get_item_as_key_data(pair_record, name, &pem); - if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) - ret = USERPREF_E_SUCCESS; - else - ret = USERPREF_E_SSL_ERROR; - - if (pem.data) - free(pem.data); -#endif +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) + ret = pair_record_get_item_as_key_data(pair_record, name, key); +#elif defined(HAVE_GNUTLS) + key_data_t pem = { NULL, 0 }; + ret = pair_record_get_item_as_key_data(pair_record, name, &pem); + if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_privkey_import(key, &pem, GNUTLS_X509_FMT_PEM)) + ret = USERPREF_E_SUCCESS; + else + ret = USERPREF_E_SSL_ERROR; + if (pem.data) + free(pem.data); +#endif return ret; } @@ -820,32 +1058,31 @@ userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const cha * * @return IDEVICE_E_SUCCESS if the certificate was successfully imported. */ -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert) #else userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, gnutls_x509_crt_t cert) #endif { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) if (!cert) return USERPREF_E_SUCCESS; #endif userpref_error_t ret = USERPREF_E_INVALID_CONF; -#ifdef HAVE_OPENSSL - ret = pair_record_get_item_as_key_data(pair_record, name, cert); -#else - key_data_t pem = { NULL, 0 }; - ret = pair_record_get_item_as_key_data(pair_record, name, &pem); - if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) - ret = USERPREF_E_SUCCESS; - else - ret = USERPREF_E_SSL_ERROR; - - if (pem.data) - free(pem.data); -#endif +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) + ret = pair_record_get_item_as_key_data(pair_record, name, cert); +#elif defined(HAVE_GNUTLS) + key_data_t pem = { NULL, 0 }; + ret = pair_record_get_item_as_key_data(pair_record, name, &pem); + if (ret == USERPREF_E_SUCCESS && GNUTLS_E_SUCCESS == gnutls_x509_crt_import(cert, &pem, GNUTLS_X509_FMT_PEM)) + ret = USERPREF_E_SUCCESS; + else + ret = USERPREF_E_SSL_ERROR; + if (pem.data) + free(pem.data); +#endif return ret; } @@ -880,9 +1117,10 @@ userpref_error_t pair_record_get_item_as_key_data(plist_t pair_record, const cha if (node && plist_get_node_type(node) == PLIST_DATA) { plist_get_data_val(node, &buffer, &length); - value->data = (unsigned char*)malloc(length); + value->data = (unsigned char*)malloc(length+1); memcpy(value->data, buffer, length); - value->size = length; + value->data[length] = '\0'; + value->size = length+1; free(buffer); buffer = NULL; } else { diff --git a/common/userpref.h b/common/userpref.h index 4ea630f..072721a 100644 --- a/common/userpref.h +++ b/common/userpref.h @@ -27,7 +27,7 @@ #include <config.h> #endif -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) typedef struct { unsigned char *data; unsigned int size; @@ -68,7 +68,7 @@ userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id, userpref_error_t userpref_delete_pair_record(const char *udid); userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key); -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) || defined(HAVE_MBEDTLS) userpref_error_t pair_record_import_key_with_name(plist_t pair_record, const char* name, key_data_t* key); userpref_error_t pair_record_import_crt_with_name(plist_t pair_record, const char* name, key_data_t* cert); #else diff --git a/configure.ac b/configure.ac index 82038e1..bd061fc 100644 --- a/configure.ac +++ b/configure.ac @@ -128,43 +128,92 @@ fi AM_CONDITIONAL([HAVE_CYTHON],[test "x$CYTHON_SUB" = "xcython"]) AC_SUBST([CYTHON_SUB]) -AC_ARG_ENABLE([openssl], - [AS_HELP_STRING([--disable-openssl], +default_openssl=yes + +AC_ARG_WITH([mbedtls], + [AS_HELP_STRING([--without-mbedtls], + [Do not look for mbedtls])], + [use_mbedtls=$withval], + [use_mbedtls=no]) +if test "x$use_mbedtls" == "xyes"; then + default_openssl=no +fi +AC_ARG_WITH([gnutls], + [AS_HELP_STRING([--without-gnutls], + [Do not look for GnuTLS])], + [use_gnutls=$withval], + [use_gnutls=no]) +if test "x$use_gnutls" == "xyes"; then + default_openssl=no +fi +AC_ARG_WITH([openssl], + [AS_HELP_STRING([--without-openssl], [Do not look for OpenSSL])], - [use_openssl=$enableval], - [use_openssl=yes]) - -pkg_req_openssl="openssl >= 0.9.8" -PKG_CHECK_MODULES(openssl, $pkg_req_openssl, have_openssl=yes, have_openssl=no) -if test "x$have_openssl" = "xyes"; then - if test "x$use_openssl" != "xyes"; then - enable_openssl=no - echo "*** Note: OpenSSL support explicitly disabled ***" - else - enable_openssl=yes + [use_openssl=$withval], + [use_openssl=$default_openssl]) + +if test "x$use_mbedtls" == "xyes"; then + CACHED_CFLAGS="$CFLAGS" + conf_mbedtls_CFLAGS="" + if test -n "$mbedtls_INCLUDES"; then + CFLAGS=" -I$mbedtls_INCLUDES" + conf_mbedtls_CFLAGS="-I$mbedtls_INCLUDES" fi -else - if test "x$use_openssl" == "xyes" -a "x$have_openssl" != "xyes"; then - AC_MSG_ERROR([OpenSSL support explicitly requested but OpenSSL could not be found]) + conf_mbedtls_LIBS="" + if test -n "$mbedtls_LIBDIR"; then + conf_mbedtls_LIBS+=" -L$mbedtls_LIBDIR" fi -fi - -if test "x$enable_openssl" = "xyes"; then - AC_DEFINE(HAVE_OPENSSL, 1, [Define if you have OpenSSL support]) - AC_SUBST(openssl_CFLAGS) - AC_SUBST(openssl_LIBS) - ssl_provider="OpenSSL"; - ssl_requires="$pkg_req_openssl" + if test -n "$mbedtls_LIBS"; then + conf_mbedtls_LIBS+=" $mbedtls_LIBS" + else + conf_mbedtls_LIBS+=" -lmbedtls -lmbedx509 -lmbedcrypto" + fi + AC_CHECK_HEADER(mbedtls/ssl.h, [break], [AC_MSG_ERROR([MbedTLS support explicitly requested, but includes could not be found. Try setting mbedtls_INCLUDES=/path/to/mbedtls/include])]) + CFLAGS="$CACHED_CFLAGS" + AC_DEFINE(HAVE_MBEDTLS, 1, [Define if you have MbedTLS support]) + ssl_lib_CFLAGS="$conf_mbedtls_CFLAGS" + ssl_lib_LIBS="$conf_mbedtls_LIBS" + AC_SUBST(ssl_lib_CFLAGS) + AC_SUBST(ssl_lib_LIBS) + ssl_provider="MbedTLS"; + ssl_requires="" AC_SUBST(ssl_requires) else - pkg_req_gnutls="gnutls >= 2.2.0" - pkg_req_libtasn1="libtasn1 >= 1.1" - PKG_CHECK_MODULES(libgnutls, $pkg_req_gnutls) - AC_CHECK_LIB(gcrypt, gcry_control, [AC_SUBST(libgcrypt_LIBS,[-lgcrypt])], [AC_MSG_ERROR([libgcrypt is required to build libimobiledevice with GnuTLS])]) - PKG_CHECK_MODULES(libtasn1, $pkg_req_libtasn1) - ssl_provider="GnuTLS" - ssl_requires="$pkg_req_gnutls $pkg_req_libtasn1" - AC_SUBST(ssl_requires) + if test "x$use_openssl" == "xyes"; then + pkg_req_openssl="openssl >= 0.9.8" + PKG_CHECK_MODULES(openssl, $pkg_req_openssl, have_openssl=yes, have_openssl=no) + if test "x$have_openssl" != "xyes"; then + AC_MSG_ERROR([OpenSSL support explicitly requested but OpenSSL could not be found]) + else + AC_DEFINE(HAVE_OPENSSL, 1, [Define if you have OpenSSL support]) + ssl_lib_CFLAGS="$openssl_CFLAGS" + ssl_lib_LIBS="$openssl_LIBS" + AC_SUBST(ssl_lib_CFLAGS) + AC_SUBST(ssl_lib_LIBS) + ssl_provider="OpenSSL"; + ssl_requires="$pkg_req_openssl" + AC_SUBST(ssl_requires) + fi + else + if test "x$use_gnutls" == "xyes"; then + pkg_req_gnutls="gnutls >= 2.2.0" + pkg_req_libtasn1="libtasn1 >= 1.1" + PKG_CHECK_MODULES(libgnutls, $pkg_req_gnutls) + AC_CHECK_LIB(gcrypt, gcry_control, [AC_SUBST(libgcrypt_LIBS,[-lgcrypt])], [AC_MSG_ERROR([libgcrypt is required to build libimobiledevice with GnuTLS])]) + PKG_CHECK_MODULES(libtasn1, $pkg_req_libtasn1) + + AC_DEFINE(HAVE_GNUTLS, 1, [Define if you have GnuTLS support]) + ssl_lib_CFLAGS="$libgnutls_CFLAGS $libtasn1_CFLAGS $libgcrypt_CFLAGS" + ssl_lib_LIBS="$libgnutls_LIBS $libtasn1_LIBS $libgcrypt_LIBS" + AC_SUBST(ssl_lib_CFLAGS) + AC_SUBST(ssl_lib_LIBS) + ssl_provider="GnuTLS" + ssl_requires="$pkg_req_gnutls $pkg_req_libtasn1" + AC_SUBST(ssl_requires) + else + AC_MSG_ERROR([No SSL library configured. $PACKAGE cannot be built without a supported SSL library.]) + fi + fi fi AC_ARG_ENABLE([debug], diff --git a/src/Makefile.am b/src/Makefile.am index 1ef47fc..96fe963 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,20 +5,15 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ $(libusbmuxd_CFLAGS) \ - $(libgnutls_CFLAGS) \ - $(libtasn1_CFLAGS) \ $(libplist_CFLAGS) \ + $(ssl_lib_CFLAGS) \ $(LFS_CFLAGS) \ - $(openssl_CFLAGS) \ $(PTHREAD_CFLAGS) AM_LDFLAGS = \ - $(libgnutls_LIBS) \ - $(libtasn1_LIBS) \ - $(libplist_LIBS) \ $(libusbmuxd_LIBS) \ - $(libgcrypt_LIBS) \ - $(openssl_LIBS) \ + $(libplist_LIBS) \ + $(ssl_lib_LIBS) \ $(PTHREAD_LIBS) lib_LTLIBRARIES = libimobiledevice-1.0.la diff --git a/src/idevice.c b/src/idevice.c index e67a649..5b9c1ac 100644 --- a/src/idevice.c +++ b/src/idevice.c @@ -2,7 +2,7 @@ * idevice.c * Device discovery and communication interface. * - * Copyright (c) 2009-2019 Nikias Bassen. All Rights Reserved. + * Copyright (c) 2009-2021 Nikias Bassen. All Rights Reserved. * Copyright (c) 2014 Martin Szulecki All Rights Reserved. * Copyright (c) 2008 Zach C. All Rights Reserved. * @@ -31,12 +31,21 @@ #include <time.h> #include <usbmuxd.h> -#ifdef HAVE_OPENSSL + +#if defined(HAVE_OPENSSL) #include <openssl/err.h> #include <openssl/rsa.h> #include <openssl/ssl.h> -#else +#elif defined(HAVE_GNUTLS) #include <gnutls/gnutls.h> +#elif defined(HAVE_MBEDTLS) +#include <mbedtls/rsa.h> +#include <mbedtls/ssl.h> +#include <mbedtls/entropy.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/debug.h> +#else +#error No supported TLS/SSL library enabled #endif #include "idevice.h" @@ -106,7 +115,7 @@ static void id_function(CRYPTO_THREADID *thread) static void internal_idevice_init(void) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) int i; SSL_library_init(); @@ -124,14 +133,16 @@ static void internal_idevice_init(void) #endif CRYPTO_set_locking_callback(locking_function); #endif -#else +#elif defined(HAVE_GNUTLS) gnutls_global_init(); +#elif defined(HAVE_MBEDTLS) + // NO-OP #endif } static void internal_idevice_deinit(void) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) int i; if (mutex_buf) { @@ -152,8 +163,10 @@ static void internal_idevice_deinit(void) SSL_COMP_free_compression_methods(); openssl_remove_thread_state(); #endif -#else +#elif defined(HAVE_GNUTLS) gnutls_global_deinit(); +#elif defined(HAVE_MBEDTLS) + // NO-OP #endif } @@ -556,7 +569,11 @@ static idevice_error_t internal_connection_send(idevice_connection_t connection, LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_t connection, const char *data, uint32_t len, uint32_t *sent_bytes) { - if (!connection || !data || (connection->ssl_data && !connection->ssl_data->session)) { + if (!connection || !data +#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) + || (connection->ssl_data && !connection->ssl_data->session) +#endif + ) { return IDEVICE_E_INVALID_ARG; } @@ -564,7 +581,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_ connection->status = IDEVICE_E_SUCCESS; uint32_t sent = 0; while (sent < len) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) int s = SSL_write(connection->ssl_data->session, (const void*)(data+sent), (int)(len-sent)); if (s <= 0) { int sslerr = SSL_get_error(connection->ssl_data->session, s); @@ -573,8 +590,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_ } break; } -#else +#elif defined(HAVE_GNUTLS) ssize_t s = gnutls_record_send(connection->ssl_data->session, (void*)(data+sent), (size_t)(len-sent)); +#elif defined(HAVE_MBEDTLS) + int s = mbedtls_ssl_write(&connection->ssl_data->ctx, (const unsigned char*)(data+sent), (size_t)(len-sent)); #endif if (s < 0) { break; @@ -662,7 +681,12 @@ static idevice_error_t internal_connection_receive_timeout(idevice_connection_t LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) { - if (!connection || (connection->ssl_data && !connection->ssl_data->session) || len == 0) { + if (!connection +#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) + || (connection->ssl_data && !connection->ssl_data->session) +#endif + || len == 0 + ) { return IDEVICE_E_INVALID_ARG; } @@ -678,7 +702,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_ connection->ssl_recv_timeout = timeout; connection->status = IDEVICE_E_SUCCESS; while (received < len) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received); if (r > 0) { received += r; @@ -689,13 +713,20 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_ } break; } -#else +#elif defined(HAVE_GNUTLS) ssize_t r = gnutls_record_recv(connection->ssl_data->session, (void*)(data+received), (size_t)len-received); if (r > 0) { received += r; } else { break; } +#elif defined(HAVE_MBEDTLS) + int r = mbedtls_ssl_read(&connection->ssl_data->ctx, (void*)(data+received), (size_t)len-received); + if (r > 0) { + received += r; + } else { + break; + } #endif } connection->ssl_recv_timeout = (unsigned int)-1; @@ -744,7 +775,11 @@ static idevice_error_t internal_connection_receive(idevice_connection_t connecti LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) { - if (!connection || (connection->ssl_data && !connection->ssl_data->session)) { + if (!connection +#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) + || (connection->ssl_data && !connection->ssl_data->session) +#endif + ) { return IDEVICE_E_INVALID_ARG; } @@ -753,11 +788,13 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connecti debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout"); connection->ssl_recv_timeout = (unsigned int)-1; } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len); debug_info("SSL_read %d, received %d", len, received); -#else +#elif defined(HAVE_GNUTLS) ssize_t received = gnutls_record_recv(connection->ssl_data->session, (void*)data, (size_t)len); +#elif defined(HAVE_MBEDTLS) + int received = mbedtls_ssl_read(&connection->ssl_data->ctx, (unsigned char*)data, (size_t)len); #endif if (received > 0) { *recv_bytes = received; @@ -806,10 +843,16 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **u return IDEVICE_E_SUCCESS; } +#if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS) +typedef ssize_t ssl_cb_ret_type_t; +#elif defined(HAVE_MBEDTLS) +typedef int ssl_cb_ret_type_t; +#endif + /** * Internally used SSL callback function for receiving encrypted data. */ -static ssize_t internal_ssl_read(idevice_connection_t connection, char *buffer, size_t length) +static ssl_cb_ret_type_t internal_ssl_read(idevice_connection_t connection, char *buffer, size_t length) { uint32_t bytes = 0; uint32_t pos = 0; @@ -849,7 +892,7 @@ static ssize_t internal_ssl_read(idevice_connection_t connection, char *buffer, /** * Internally used SSL callback function for sending encrypted data. */ -static ssize_t internal_ssl_write(idevice_connection_t connection, const char *buffer, size_t length) +static ssl_cb_ret_type_t internal_ssl_write(idevice_connection_t connection, const char *buffer, size_t length) { uint32_t bytes = 0; idevice_error_t res; @@ -871,14 +914,14 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data) if (!ssl_data) return; -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) if (ssl_data->session) { SSL_free(ssl_data->session); } if (ssl_data->ctx) { SSL_CTX_free(ssl_data->ctx); } -#else +#elif defined(HAVE_GNUTLS) if (ssl_data->session) { gnutls_deinit(ssl_data->session); } @@ -897,6 +940,13 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data) if (ssl_data->host_privkey) { gnutls_x509_privkey_deinit(ssl_data->host_privkey); } +#elif defined(HAVE_MBEDTLS) + mbedtls_pk_free(&ssl_data->root_privkey); + mbedtls_x509_crt_free(&ssl_data->certificate); + mbedtls_entropy_free(&ssl_data->entropy); + mbedtls_ctr_drbg_free(&ssl_data->ctr_drbg); + mbedtls_ssl_config_free(&ssl_data->config); + mbedtls_ssl_free(&ssl_data->ctx); #endif } @@ -961,7 +1011,7 @@ static const char *ssl_error_to_string(int e) #endif #endif -#ifndef HAVE_OPENSSL +#if defined(HAVE_GNUTLS) /** * Internally used gnutls callback function that gets called during handshake. */ @@ -992,6 +1042,23 @@ static int internal_cert_callback(gnutls_session_t session, const gnutls_datum_t } return res; } +#elif defined(HAVE_MBEDTLS) +static void _mbedtls_log_cb(void* ctx, int level, const char* filename, int line, const char* message) +{ + fprintf(stderr, "[mbedtls][%d] %s:%d => %s", level, filename, line, message); +} + +static int cert_verify_cb(void* ctx, mbedtls_x509_crt* cert, int depth, uint32_t *flags) +{ + *flags = 0; + return 0; +} + +static int _mbedtls_f_rng(void* p_rng, unsigned char* buf, size_t len) +{ + memset(buf, 4, len); + return 0; +} #endif LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_connection_t connection) @@ -1008,7 +1075,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne return ret; } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) key_data_t root_cert = { NULL, 0 }; key_data_t root_privkey = { NULL, 0 }; @@ -1118,7 +1185,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne } /* required for proper multi-thread clean up to prevent leaks */ openssl_remove_thread_state(); -#else +#elif defined(HAVE_GNUTLS) ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private)); /* Set up GnuTLS... */ @@ -1176,6 +1243,82 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne ret = IDEVICE_E_SUCCESS; debug_info("SSL mode enabled"); } +#elif defined(HAVE_MBEDTLS) + key_data_t root_cert = { NULL, 0 }; + key_data_t root_privkey = { NULL, 0 }; + + pair_record_import_crt_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); + + plist_free(pair_record); + + ssl_data_t ssl_data_loc = (ssl_data_t)malloc(sizeof(struct ssl_data_private)); + + mbedtls_ssl_init(&ssl_data_loc->ctx); + mbedtls_ssl_config_init(&ssl_data_loc->config); + mbedtls_entropy_init(&ssl_data_loc->entropy); + mbedtls_ctr_drbg_init(&ssl_data_loc->ctr_drbg); + + int r = mbedtls_ctr_drbg_seed(&ssl_data_loc->ctr_drbg, mbedtls_entropy_func, &ssl_data_loc->entropy, NULL, 0); + if (r != 0) { + debug_info("ERROR: [mbedtls] mbedtls_ctr_drbg_seed failed: %d", r); + return ret; + } + + if (mbedtls_ssl_config_defaults(&ssl_data_loc->config, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) { + debug_info("ERROR: [mbedtls] Failed to set config defaults"); + return ret; + } + + mbedtls_ssl_conf_rng(&ssl_data_loc->config, mbedtls_ctr_drbg_random, &ssl_data_loc->ctr_drbg); + + mbedtls_ssl_conf_dbg(&ssl_data_loc->config, _mbedtls_log_cb, NULL); + + mbedtls_ssl_conf_verify(&ssl_data_loc->config, cert_verify_cb, NULL); + + mbedtls_ssl_setup(&ssl_data_loc->ctx, &ssl_data_loc->config); + + mbedtls_ssl_set_bio(&ssl_data_loc->ctx, connection, (mbedtls_ssl_send_t*)&internal_ssl_write, (mbedtls_ssl_recv_t*)&internal_ssl_read, NULL); + + mbedtls_x509_crt_init(&ssl_data_loc->certificate); + + int crterr = mbedtls_x509_crt_parse(&ssl_data_loc->certificate, root_cert.data, root_cert.size); + if (crterr < 0) { + debug_info("ERROR: [mbedtls] parsing root cert failed: %d", crterr); + return ret; + } + + mbedtls_ssl_conf_ca_chain(&ssl_data_loc->config, &ssl_data_loc->certificate, NULL); + + mbedtls_pk_init(&ssl_data_loc->root_privkey); + +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + int pkerr = mbedtls_pk_parse_key(&ssl_data_loc->root_privkey, root_privkey.data, root_privkey.size, NULL, 0, &_mbedtls_f_rng, NULL); +#else + int pkerr = mbedtls_pk_parse_key(&ssl_data_loc->root_privkey, root_privkey.data, root_privkey.size, NULL, 0); +#endif + if (pkerr < 0) { + debug_info("ERROR: [mbedtls] parsing private key failed: %d (size=%d)", pkerr, root_privkey.size); + return ret; + } + + mbedtls_ssl_conf_own_cert(&ssl_data_loc->config, &ssl_data_loc->certificate, &ssl_data_loc->root_privkey); + + int return_me = 0; + do { + return_me = mbedtls_ssl_handshake(&ssl_data_loc->ctx); + } while (return_me == MBEDTLS_ERR_SSL_WANT_READ || return_me == MBEDTLS_ERR_SSL_WANT_WRITE); + + if (return_me != 0) { + debug_info("ERROR during SSL handshake: %d", return_me); + internal_ssl_cleanup(ssl_data_loc); + free(ssl_data_loc); + } else { + connection->ssl_data = ssl_data_loc; + ret = IDEVICE_E_SUCCESS; + debug_info("SSL mode enabled, %s, cipher: %s", mbedtls_ssl_get_version(&ssl_data_loc->ctx), mbedtls_ssl_get_ciphersuite(&ssl_data_loc->ctx)); + debug_info("SSL mode enabled"); + } #endif return ret; } @@ -1197,7 +1340,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevi // some services require plain text communication after SSL handshake // sending out SSL_shutdown will cause bytes if (!sslBypass) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) if (connection->ssl_data->session) { /* see: https://www.openssl.org/docs/ssl/SSL_shutdown.html#RETURN_VALUES */ if (SSL_shutdown(connection->ssl_data->session) == 0) { @@ -1210,10 +1353,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_disable_bypass_ssl(idevi } } } -#else +#elif defined(HAVE_GNUTLS) if (connection->ssl_data->session) { gnutls_bye(connection->ssl_data->session, GNUTLS_SHUT_RDWR); } +#elif defined(HAVE_MBEDTLS) + mbedtls_ssl_close_notify(&connection->ssl_data->ctx); #endif } diff --git a/src/idevice.h b/src/idevice.h index 4e53a7f..7a8f4ce 100644 --- a/src/idevice.h +++ b/src/idevice.h @@ -26,11 +26,15 @@ #include <config.h> #endif -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) #include <openssl/ssl.h> -#else +#elif defined(HAVE_GNUTLS) #include <gnutls/gnutls.h> #include <gnutls/x509.h> +#elif defined(HAVE_MBEDTLS) +#include <mbedtls/ssl.h> +#include <mbedtls/entropy.h> +#include <mbedtls/ctr_drbg.h> #endif #ifdef WIN32 @@ -49,16 +53,23 @@ #define DEVICE_VERSION(maj, min, patch) (((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (patch & 0xFF)) struct ssl_data_private { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) SSL *session; SSL_CTX *ctx; -#else +#elif defined(HAVE_GNUTLS) gnutls_certificate_credentials_t certificate; gnutls_session_t session; gnutls_x509_privkey_t root_privkey; gnutls_x509_crt_t root_cert; gnutls_x509_privkey_t host_privkey; gnutls_x509_crt_t host_cert; +#elif defined(HAVE_MBEDTLS) + mbedtls_ssl_context ctx; + mbedtls_ssl_config config; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_x509_crt certificate; + mbedtls_pk_context root_privkey; #endif }; typedef struct ssl_data_private *ssl_data_t; diff --git a/tools/Makefile.am b/tools/Makefile.am index 04a5faa..b78f3f2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -4,18 +4,10 @@ AM_CPPFLAGS = \ AM_CFLAGS = \ $(GLOBAL_CFLAGS) \ - $(libgnutls_CFLAGS) \ - $(libtasn1_CFLAGS) \ - $(libgcrypt_CFLAGS) \ - $(openssl_CFLAGS) \ $(libplist_CFLAGS) \ $(LFS_CFLAGS) AM_LDFLAGS = \ - $(libgnutls_LIBS) \ - $(libtasn1_LIBS) \ - $(libgcrypt_LIBS) \ - $(openssl_LIBS) \ $(libplist_LIBS) bin_PROGRAMS = \ @@ -49,8 +41,8 @@ idevicename_LDFLAGS = $(AM_LDFLAGS) idevicename_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicepair_SOURCES = idevicepair.c -idevicepair_CFLAGS = -I$(top_srcdir) $(AM_CFLAGS) -idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS) +idevicepair_CFLAGS = -I$(top_srcdir) $(AM_CFLAGS) $(ssl_lib_CFLAGS) +idevicepair_LDFLAGS = $(AM_LDFLAGS) $(libusbmuxd_LIBS) $(ssl_lib_LIBS) idevicepair_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la idevicesyslog_SOURCES = idevicesyslog.c @@ -64,8 +56,8 @@ idevice_id_LDFLAGS = $(AM_LDFLAGS) idevice_id_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la idevicebackup_SOURCES = idevicebackup.c -idevicebackup_CFLAGS = $(AM_CFLAGS) -idevicebackup_LDFLAGS = $(AM_LDFLAGS) +idevicebackup_CFLAGS = $(AM_CFLAGS) $(ssl_lib_CFLAGS) +idevicebackup_LDFLAGS = $(AM_LDFLAGS) $(ssl_lib_LIBS) idevicebackup_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la $(top_builddir)/common/libinternalcommon.la idevicebackup2_SOURCES = idevicebackup2.c diff --git a/tools/idevicebackup.c b/tools/idevicebackup.c index dfd7b8b..8d0f74b 100644 --- a/tools/idevicebackup.c +++ b/tools/idevicebackup.c @@ -31,10 +31,20 @@ #include <errno.h> #include <stdlib.h> #include <signal.h> -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) #include <openssl/sha.h> -#else +#elif defined(HAVE_GNUTLS) #include <gcrypt.h> +#elif defined(HAVE_MBEDTLS) +#include <mbedtls/sha1.h> +#if MBEDTLS_VERSION_NUMBER < 0x03000000 +#define mbedtls_sha1 mbedtls_sha1_ret +#define mbedtls_sha1_starts mbedtls_sha1_starts_ret +#define mbedtls_sha1_update mbedtls_sha1_update_ret +#define mbedtls_sha1_finish mbedtls_sha1_finish_ret +#endif +#else +#error No supported crypto library enabled #endif #include <unistd.h> #include <ctype.h> @@ -78,10 +88,12 @@ enum device_link_file_status_t { static void sha1_of_data(const char *input, uint32_t size, unsigned char *hash_out) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) SHA1((const unsigned char*)input, size, hash_out); -#else +#elif defined(HAVE_GNUTLS) gcry_md_hash_buffer(GCRY_MD_SHA1, hash_out, input, size); +#elif defined(HAVE_MBEDTLS) + mbedtls_sha1((unsigned char*)input, size, hash_out); #endif } @@ -96,12 +108,24 @@ static int compare_hash(const unsigned char *hash1, const unsigned char *hash2, return 1; } +static void _sha1_update(void* context, const char* data, size_t len) +{ +#if defined(HAVE_OPENSSL) + SHA1_Update(context, data, len); +#elif defined(HAVE_GNUTLS) + gcry_md_write(context, data, len); +#elif defined(HAVE_MBEDTLS) + mbedtls_sha1_update(context, (const unsigned char*)data, len); +#endif +} + static void compute_datahash(const char *path, const char *destpath, uint8_t greylist, const char *domain, const char *appid, const char *version, unsigned char *hash_out) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) SHA_CTX sha1; SHA1_Init(&sha1); -#else + void* psha1 = &sha1; +#elif defined(HAVE_GNUTLS) gcry_md_hd_t hd = NULL; gcry_md_open(&hd, GCRY_MD_SHA1, 0); if (!hd) { @@ -109,102 +133,63 @@ static void compute_datahash(const char *path, const char *destpath, uint8_t gre return; } gcry_md_reset(hd); + void* psha1 = hd; +#elif defined(HAVE_MBEDTLS) + mbedtls_sha1_context sha1; + mbedtls_sha1_init(&sha1); + mbedtls_sha1_starts(&sha1); + void* psha1 = &sha1; #endif FILE *f = fopen(path, "rb"); if (f) { unsigned char buf[16384]; size_t len; while ((len = fread(buf, 1, 16384, f)) > 0) { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, buf, len); -#else - gcry_md_write(hd, buf, len); -#endif + _sha1_update(psha1, (const char*)buf, len); } fclose(f); -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, destpath, strlen(destpath)); - SHA1_Update(&sha1, ";", 1); -#else - gcry_md_write(hd, destpath, strlen(destpath)); - gcry_md_write(hd, ";", 1); -#endif + _sha1_update(psha1, destpath, strlen(destpath)); + _sha1_update(psha1, ";", 1); + if (greylist == 1) { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, "true", 4); -#else - gcry_md_write(hd, "true", 4); -#endif + _sha1_update(psha1, "true", 4); } else { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, "false", 5); -#else - gcry_md_write(hd, "false", 5); -#endif + _sha1_update(psha1, "false", 5); } -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, ";", 1); -#else - gcry_md_write(hd, ";", 1); -#endif + _sha1_update(psha1, ";", 1); + if (domain) { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, domain, strlen(domain)); -#else - gcry_md_write(hd, domain, strlen(domain)); -#endif + _sha1_update(psha1, domain, strlen(domain)); } else { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, "(null)", 6); -#else - gcry_md_write(hd, "(null)", 6); -#endif + _sha1_update(psha1, "(null)", 6); } -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, ";", 1); -#else - gcry_md_write(hd, ";", 1); -#endif + _sha1_update(psha1, ";", 1); + if (appid) { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, appid, strlen(appid)); -#else - gcry_md_write(hd, appid, strlen(appid)); -#endif + _sha1_update(psha1, appid, strlen(appid)); } else { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, "(null)", 6); -#else - gcry_md_write(hd, "(null)", 6); -#endif + _sha1_update(psha1, "(null)", 6); } -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, ";", 1); -#else - gcry_md_write(hd, ";", 1); -#endif + _sha1_update(psha1, ";", 1); + if (version) { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, version, strlen(version)); -#else - gcry_md_write(hd, version, strlen(version)); -#endif + _sha1_update(psha1, version, strlen(version)); } else { -#ifdef HAVE_OPENSSL - SHA1_Update(&sha1, "(null)", 6); -#else - gcry_md_write(hd, "(null)", 6); -#endif + _sha1_update(psha1, "(null)", 6); } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) SHA1_Final(hash_out, &sha1); -#else +#elif defined(HAVE_GNUTLS) unsigned char *newhash = gcry_md_read(hd, GCRY_MD_SHA1); memcpy(hash_out, newhash, 20); +#elif defined(HAVE_MBEDTLS) + mbedtls_sha1_finish(&sha1, hash_out); #endif } -#ifndef HAVE_OPENSSL +#if defined(HAVE_GNUTLS) gcry_md_close(hd); +#elif defined(HAVE_MBEDTLS) + mbedtls_sha1_free(&sha1); #endif } |