diff --git a/Cargo.lock b/Cargo.lock index 616d1f5..5f0b8d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1582,7 +1582,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn", ] [[package]] diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index b75ea91..8c18cad 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -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(), diff --git a/idevice/src/lib.rs b/idevice/src/lib.rs index 071d89c..e928bcb 100644 --- a/idevice/src/lib.rs +++ b/idevice/src/lib.rs @@ -76,6 +76,18 @@ pub trait IdeviceService: Sized { #[allow(async_fn_in_trait)] async fn connect(provider: &dyn IdeviceProvider) -> Result { 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::().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, diff --git a/idevice/src/pairing_file.rs b/idevice/src/pairing_file.rs index ee9c816..94299d3 100644 --- a/idevice/src/pairing_file.rs +++ b/idevice/src/pairing_file.rs @@ -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 for PairingFile { } } +#[cfg(feature = "rustls")] impl From 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 for RawPairingFile { } } +#[cfg(all(feature = "openssl", not(feature = "rustls")))] +impl TryFrom for RawPairingFile { + type Error = openssl::error::ErrorStack; + + fn try_from(value: PairingFile) -> Result { + 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 diff --git a/idevice/src/services/crashreportcopymobile.rs b/idevice/src/services/crashreportcopymobile.rs index 980d058..d5684fa 100644 --- a/idevice/src/services/crashreportcopymobile.rs +++ b/idevice/src/services/crashreportcopymobile.rs @@ -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::().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?; } diff --git a/idevice/src/services/dvt/mod.rs b/idevice/src/services/dvt/mod.rs index 71e9b1f..ffce75c 100644 --- a/idevice/src/services/dvt/mod.rs +++ b/idevice/src/services/dvt/mod.rs @@ -39,6 +39,18 @@ impl crate::IdeviceService for remote_server::RemoteServerClient Result { // 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::().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().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(()) }