Enable SSL on iOS < 5

This commit is contained in:
Jackson Coxson
2025-11-17 12:27:45 -07:00
parent c9ca113239
commit f11a1bafff
7 changed files with 90 additions and 18 deletions

2
Cargo.lock generated
View File

@@ -1582,7 +1582,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
"syn",
]
[[package]]

View File

@@ -338,6 +338,7 @@ pub unsafe extern "C" fn idevice_rsd_checkin(idevice: *mut IdeviceHandle) -> *mu
pub unsafe extern "C" fn idevice_start_session(
idevice: *mut IdeviceHandle,
pairing_file: *const IdevicePairingFile,
legacy: bool,
) -> *mut IdeviceFfiError {
if idevice.is_null() || pairing_file.is_null() {
return ffi_err!(IdeviceError::FfiInvalidArg);
@@ -350,7 +351,7 @@ pub unsafe extern "C" fn idevice_start_session(
let pf = unsafe { &(*pairing_file).0 };
// Run the start_session method in the runtime
let result = run_sync(async { dev.start_session(pf).await });
let result = run_sync(async move { dev.start_session(pf, legacy).await });
match result {
Ok(_) => null_mut(),

View File

@@ -76,6 +76,18 @@ pub trait IdeviceService: Sized {
#[allow(async_fn_in_trait)]
async fn connect(provider: &dyn IdeviceProvider) -> Result<Self, IdeviceError> {
let mut lockdown = LockdownClient::connect(provider).await?;
let legacy = lockdown
.get_value(Some("ProductVersion"), None)
.await
.ok()
.as_ref()
.and_then(|x| x.as_string())
.and_then(|x| x.split(".").next())
.and_then(|x| x.parse::<u8>().ok())
.map(|x| x < 5)
.unwrap_or(false);
lockdown
.start_session(&provider.get_pairing_file().await?)
.await?;
@@ -90,7 +102,7 @@ pub trait IdeviceService: Sized {
let mut idevice = provider.connect(port).await?;
if ssl {
idevice
.start_session(&provider.get_pairing_file().await?)
.start_session(&provider.get_pairing_file().await?, legacy)
.await?;
}
@@ -464,6 +476,7 @@ impl Idevice {
pub async fn start_session(
&mut self,
pairing_file: &pairing_file::PairingFile,
legacy: bool,
) -> Result<(), IdeviceError> {
#[cfg(feature = "rustls")]
{
@@ -523,15 +536,16 @@ impl Idevice {
}
#[cfg(all(feature = "openssl", not(feature = "rustls")))]
{
let connector =
openssl::ssl::SslConnector::builder(openssl::ssl::SslMethod::tls()).unwrap();
let mut connector =
openssl::ssl::SslConnector::builder(openssl::ssl::SslMethod::tls())?;
if legacy {
connector.set_min_proto_version(Some(openssl::ssl::SslVersion::SSL3))?;
connector.set_max_proto_version(Some(openssl::ssl::SslVersion::TLS1))?;
connector.set_cipher_list("ALL:!aNULL:!eNULL:@SECLEVEL=0")?;
connector.set_options(openssl::ssl::SslOptions::ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
}
let mut connector = connector
.build()
.configure()
.unwrap()
.into_ssl("ur mom")
.unwrap();
let mut connector = connector.build().configure()?.into_ssl("ur mom")?;
connector.set_certificate(&pairing_file.host_certificate)?;
connector.set_private_key(&pairing_file.host_private_key)?;
@@ -553,18 +567,18 @@ impl Idevice {
pub enum IdeviceError {
#[error("device socket io failed")]
Socket(#[from] io::Error) = -1,
#[cfg(all(feature = "rustls", not(feature = "openssl")))]
#[cfg(feature = "rustls")]
#[error("PEM parse failed")]
PemParseFailed(#[from] rustls::pki_types::pem::Error) = -2,
#[cfg(all(feature = "rustls", not(feature = "openssl")))]
#[cfg(feature = "rustls")]
#[error("TLS error")]
Rustls(#[from] rustls::Error) = -3,
#[cfg(all(feature = "openssl", not(feature = "rustls")))]
#[error("TLS error")]
Rustls(#[from] openssl::ssl::Error) = -3,
#[cfg(all(feature = "rustls", not(feature = "openssl")))]
#[cfg(feature = "rustls")]
#[error("TLS verifiction build failed")]
TlsBuilderFailed(#[from] rustls::server::VerifierBuilderError) = -4,
#[cfg(all(feature = "openssl", not(feature = "rustls")))]
@@ -817,6 +831,7 @@ impl IdeviceError {
pub fn code(&self) -> i32 {
match self {
IdeviceError::Socket(_) => -1,
#[cfg(feature = "rustls")]
IdeviceError::PemParseFailed(_) => -2,
IdeviceError::Rustls(_) => -3,
IdeviceError::TlsBuilderFailed(_) => -4,

View File

@@ -5,7 +5,7 @@
use std::path::Path;
#[cfg(feature = "openssl")]
#[cfg(all(feature = "openssl", not(feature = "rustls")))]
use openssl::{
pkey::{PKey, Private},
x509::X509,
@@ -237,6 +237,7 @@ impl TryFrom<RawPairingFile> for PairingFile {
}
}
#[cfg(feature = "rustls")]
impl From<PairingFile> for RawPairingFile {
/// Converts a structured pairing file into a raw pairing file for serialization
fn from(value: PairingFile) -> Self {
@@ -264,6 +265,26 @@ impl From<PairingFile> for RawPairingFile {
}
}
#[cfg(all(feature = "openssl", not(feature = "rustls")))]
impl TryFrom<PairingFile> for RawPairingFile {
type Error = openssl::error::ErrorStack;
fn try_from(value: PairingFile) -> Result<Self, Self::Error> {
Ok(Self {
device_certificate: Data::new(value.device_certificate.to_pem()?),
host_private_key: Data::new(value.host_private_key.private_key_to_pem_pkcs8()?),
host_certificate: Data::new(value.host_certificate.to_pem()?),
root_private_key: Data::new(value.root_private_key.private_key_to_pem_pkcs8()?),
root_certificate: Data::new(value.root_certificate.to_pem()?),
system_buid: value.system_buid,
host_id: value.host_id.clone(),
escrow_bag: Data::new(value.escrow_bag),
wifi_mac_address: value.wifi_mac_address,
udid: value.udid,
})
}
}
/// Helper function to ensure data has proper PEM headers
/// If the data already has headers, it returns it as is
/// If not, it adds the appropriate BEGIN and END headers

View File

@@ -124,6 +124,18 @@ pub async fn flush_reports(
provider: &dyn crate::provider::IdeviceProvider,
) -> Result<(), IdeviceError> {
let mut lockdown = LockdownClient::connect(provider).await?;
let legacy = lockdown
.get_value(Some("ProductVersion"), None)
.await
.ok()
.as_ref()
.and_then(|x| x.as_string())
.and_then(|x| x.split(".").next())
.and_then(|x| x.parse::<u8>().ok())
.map(|x| x < 5)
.unwrap_or(false);
lockdown
.start_session(&provider.get_pairing_file().await?)
.await?;
@@ -135,7 +147,7 @@ pub async fn flush_reports(
let mut idevice = provider.connect(port).await?;
if ssl {
idevice
.start_session(&provider.get_pairing_file().await?)
.start_session(&provider.get_pairing_file().await?, legacy)
.await?;
}

View File

@@ -39,6 +39,18 @@ impl crate::IdeviceService for remote_server::RemoteServerClient<Box<dyn ReadWri
async fn connect(provider: &dyn IdeviceProvider) -> Result<Self, IdeviceError> {
// Establish Lockdown session
let mut lockdown = LockdownClient::connect(provider).await?;
let legacy = lockdown
.get_value(Some("ProductVersion"), None)
.await
.ok()
.as_ref()
.and_then(|x| x.as_string())
.and_then(|x| x.split(".").next())
.and_then(|x| x.parse::<u8>().ok())
.map(|x| x < 5)
.unwrap_or(false);
lockdown
.start_session(&provider.get_pairing_file().await?)
.await?;
@@ -56,7 +68,7 @@ impl crate::IdeviceService for remote_server::RemoteServerClient<Box<dyn ReadWri
let mut idevice = provider.connect(port).await?;
if ssl {
idevice
.start_session(&provider.get_pairing_file().await?)
.start_session(&provider.get_pairing_file().await?, legacy)
.await?;
}
// Convert to transport and build client

View File

@@ -157,6 +157,17 @@ impl LockdownClient {
return Err(IdeviceError::NoEstablishedConnection);
}
let legacy = self
.get_value(Some("ProductVersion"), None)
.await
.ok()
.as_ref()
.and_then(|x| x.as_string())
.and_then(|x| x.split(".").next())
.and_then(|x| x.parse::<u8>().ok())
.map(|x| x < 5)
.unwrap_or(false);
let request = crate::plist!({
"Label": self.idevice.label.clone(),
"Request": "StartSession",
@@ -178,7 +189,7 @@ impl LockdownClient {
}
}
self.idevice.start_session(pairing_file).await?;
self.idevice.start_session(pairing_file, legacy).await?;
Ok(())
}