Add support for MbedTLS
diff --git a/README.md b/README.md
index 71d7754..2f561aa 100644
--- a/README.md
+++ b/README.md
@@ -94,10 +94,19 @@
 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 @@
 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 @@
 	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 @@
 
 	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 @@
 
 	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 @@
 
 	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 @@
 	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 @@
  *
  * @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 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);
+	if (pem.data)
+		free(pem.data);
 #endif
-
 	return ret;
 }
 
@@ -820,32 +1058,31 @@
  *
  * @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 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);
+	if (pem.data)
+		free(pem.data);
 #endif
-
 	return ret;
 }
 
@@ -880,9 +1117,10 @@
 
 	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_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 @@
 AM_CONDITIONAL([HAVE_CYTHON],[test "x$CYTHON_SUB" = "xcython"])
 AC_SUBST([CYTHON_SUB])
 
-AC_ARG_ENABLE([openssl],
-            [AS_HELP_STRING([--disable-openssl],
-            [Do not look for OpenSSL])],
-            [use_openssl=$enableval],
-            [use_openssl=yes])
+default_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
-  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])
-  fi
+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=$withval],
+            [use_openssl=$default_openssl])
 
-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 "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
+  conf_mbedtls_LIBS=""
+  if test -n "$mbedtls_LIBDIR"; then
+    conf_mbedtls_LIBS+=" -L$mbedtls_LIBDIR"
+  fi
+  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_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 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 @@
 #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 @@
 	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 @@
 
 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 @@
 		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 @@
 				}
 				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 @@
 
 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 @@
 		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 @@
 				}
 				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 @@
 
 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 @@
 			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 @@
 	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 @@
 /**
  * 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 @@
 	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 @@
 	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 @@
 #endif
 #endif
 
-#ifndef HAVE_OPENSSL
+#if defined(HAVE_GNUTLS)
 /**
  * Internally used gnutls callback function that gets called during handshake.
  */
@@ -992,6 +1042,23 @@
 	}
 	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 @@
 		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 @@
 	}
 	/* 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 @@
 		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 @@
 	// 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 @@
 				}
 			}
 		}
-#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_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_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_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 @@
 
 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 @@
 	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 @@
 		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
 }