From: Josef Micka <micka@compelson.com>
Date: Mon, 4 Nov 2024 12:16:26 +0100
Subject: Use SHA256 signature, instead of SHA1
 for iOS 4 and newer when creating and signing pairing
 certificates

Bug: https://github.com/libimobiledevice/libimobiledevice/issues/1355
Bug-Debian: https://bugs.debian.org/1102053
Forwarded: https://github.com/libimobiledevice/libimobiledevice/pull/1616
---
 common/userpref.c | 29 +++++++++++++++--------------
 common/userpref.h |  2 +-
 src/lockdown-cu.c |  2 +-
 src/lockdown.c    |  2 +-
 4 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/common/userpref.c b/common/userpref.c
index 08ab7e2..5fd9732 100644
--- a/common/userpref.c
+++ b/common/userpref.c
@@ -81,6 +81,7 @@
 
 #include "userpref.h"
 #include "debug.h"
+#include "../src/idevice.h"
 
 #if defined(HAVE_GNUTLS)
 const ASN1_ARRAY_TYPE pkcs1_asn1_tab[] = {
@@ -419,7 +420,7 @@ static int _mbedtls_x509write_crt_set_basic_constraints_critical(mbedtls_x509wri
  *
  * @return 1 if keys were successfully generated, 0 otherwise
  */
-userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key)
+userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, int osversion)
 {
 	userpref_error_t ret = USERPREF_E_SSL_ERROR;
 
@@ -484,7 +485,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 		X509_set_pubkey(root_cert, root_pkey);
 
 		/* sign root cert with root private key */
-		X509_sign(root_cert, root_pkey, EVP_sha1());
+		X509_sign(root_cert, root_pkey, osversion < DEVICE_VERSION(4,0,0) ? EVP_sha1() : EVP_sha256());
 	}
 
 	/* create host certificate */
@@ -517,7 +518,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 		X509_set_pubkey(host_cert, host_pkey);
 
 		/* sign host cert with root private key */
-		X509_sign(host_cert, root_pkey, EVP_sha1());
+		X509_sign(host_cert, root_pkey, osversion < DEVICE_VERSION(4, 0, 0) ? EVP_sha1() : EVP_sha256());
 	}
 
 	if (root_cert && root_pkey && host_cert && host_pkey) {
@@ -609,7 +610,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 		X509_add_ext_helper(dev_cert, NID_key_usage, (char*)"critical,digitalSignature,keyEncipherment");
 
 		/* sign device certificate with root private key */
-		if (X509_sign(dev_cert, root_pkey, EVP_sha1())) {
+		if (X509_sign(dev_cert, root_pkey, osversion < DEVICE_VERSION(4, 0, 0) ? EVP_sha1() : EVP_sha256())) {
 			/* if signing succeeded, export in PEM format */
 			BIO* membp = BIO_new(BIO_s_mem());
 			if (PEM_write_bio_X509(membp, dev_cert) > 0) {
@@ -661,7 +662,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 	gnutls_x509_crt_set_ca_status(root_cert, 1);
 	gnutls_x509_crt_set_activation_time(root_cert, time(NULL));
 	gnutls_x509_crt_set_expiration_time(root_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
-	gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0);
+	gnutls_x509_crt_sign2(root_cert, root_cert, root_privkey, osversion < DEVICE_VERSION(4, 0, 0) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);
 
 	gnutls_x509_crt_set_key(host_cert, host_privkey);
 	gnutls_x509_crt_set_serial(host_cert, "\x01", 1);
@@ -670,7 +671,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 	gnutls_x509_crt_set_key_usage(host_cert, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE);
 	gnutls_x509_crt_set_activation_time(host_cert, time(NULL));
 	gnutls_x509_crt_set_expiration_time(host_cert, time(NULL) + (60 * 60 * 24 * 365 * 10));
-	gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0);
+	gnutls_x509_crt_sign2(host_cert, root_cert, root_privkey, osversion < DEVICE_VERSION(4, 0, 0) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);
 
 	/* export to PEM format */
 	size_t root_key_export_size = 0;
@@ -768,17 +769,17 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 			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);
+			const gnutls_digest_algorithm_t dig_sha = osversion < DEVICE_VERSION(4, 0, 0) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256;
+			size_t hash_size = gnutls_hash_get_len(dig_sha);
 			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");
+			if (gnutls_hash_fast(dig_sha, der_pub_key.data, der_pub_key.size, (unsigned char*)&hash) < 0) {
+				debug_info("ERROR: Failed to generate SHA 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_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, GNUTLS_DIG_SHA1, 0);
+			gnutls_error = gnutls_x509_crt_sign2(dev_cert, root_cert, root_privkey, osversion < DEVICE_VERSION(4, 0, 0) ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256, 0);
 			if (GNUTLS_E_SUCCESS == gnutls_error) {
 				/* if everything went well, export in PEM format */
 				size_t export_size = 0;
@@ -872,7 +873,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 
 	/* 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);
+	mbedtls_x509write_crt_set_md_alg(&cert, osversion < DEVICE_VERSION(4, 0, 0) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256);
 
 	unsigned char outbuf[16384];
 
@@ -931,7 +932,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 
 	/* 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);
+	mbedtls_x509write_crt_set_md_alg(&cert, osversion < DEVICE_VERSION(4, 0, 0) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256);
 
 	/* write host private key */
 	mbedtls_pk_write_key_pem(&host_pkey, outbuf, sizeof(outbuf));
@@ -991,7 +992,7 @@ userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_da
 
 	/* 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);
+	mbedtls_x509write_crt_set_md_alg(&cert, osversion < DEVICE_VERSION(4, 0, 0) ? MBEDTLS_MD_SHA1 : MBEDTLS_MD_SHA256);
 
 	/* write device certificate */
 	mbedtls_x509write_crt_pem(&cert, outbuf, sizeof(outbuf), mbedtls_ctr_drbg_random, &ctr_drbg);
diff --git a/common/userpref.h b/common/userpref.h
index 75bb8b7..5233bb9 100644
--- a/common/userpref.h
+++ b/common/userpref.h
@@ -68,7 +68,7 @@ userpref_error_t userpref_read_pair_record(const char *udid, plist_t *pair_recor
 userpref_error_t userpref_save_pair_record(const char *udid, uint32_t device_id, plist_t pair_record);
 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);
+userpref_error_t pair_record_generate_keys_and_certs(plist_t pair_record, key_data_t public_key, int osversion);
 #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);
diff --git a/src/lockdown-cu.c b/src/lockdown-cu.c
index 9fbd2c8..b78f0d0 100644
--- a/src/lockdown-cu.c
+++ b/src/lockdown-cu.c
@@ -1132,7 +1132,7 @@ lockdownd_error_t lockdownd_pair_cu(lockdownd_client_t client)
 	plist_free(pubkey);	
 
 	plist_t pair_record_plist = plist_new_dict();
-	pair_record_generate_keys_and_certs(pair_record_plist, public_key);
+	pair_record_generate_keys_and_certs(pair_record_plist, public_key, client->device->version);
 
 	char* host_id = NULL;
 	char* system_buid = NULL;
diff --git a/src/lockdown.c b/src/lockdown.c
index 3679fee..e77a755 100644
--- a/src/lockdown.c
+++ b/src/lockdown.c
@@ -840,7 +840,7 @@ static lockdownd_error_t pair_record_generate(lockdownd_client_t client, plist_t
 
 	/* generate keys and certificates into pair record */
 	userpref_error_t uret = USERPREF_E_SUCCESS;
-	uret = pair_record_generate_keys_and_certs(*pair_record, public_key);
+	uret = pair_record_generate_keys_and_certs(*pair_record, public_key, client->device->version);
 	switch(uret) {
 		case USERPREF_E_INVALID_ARG:
 			ret = LOCKDOWN_E_INVALID_ARG;
