From db894120dad6787ea35ba7045e436ed6e2a4c898 Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Sat, 15 Nov 2025 11:45:34 -0700 Subject: [PATCH] Add OpenSSL dependency --- Cargo.lock | 78 ++++++++++++++++++ idevice/Cargo.toml | 14 ++-- idevice/src/lib.rs | 133 ++++++++++++++++++++----------- idevice/src/pairing_file.rs | 57 +++++++++++++ idevice/src/services/lockdown.rs | 2 +- tools/Cargo.toml | 1 + 6 files changed, 233 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6be7358..9951ce5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -672,6 +672,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1064,6 +1079,7 @@ dependencies = [ "json", "ns-keyed-archive", "obfstr", + "openssl", "plist", "rand 0.9.2", "reqwest", @@ -1074,6 +1090,7 @@ dependencies = [ "sha2", "thiserror 2.0.17", "tokio", + "tokio-openssl", "tokio-rustls", "tracing", "tun-rs", @@ -1548,6 +1565,44 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "parking" version = "2.2.1" @@ -1662,6 +1717,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "plist" version = "1.8.0" @@ -2404,6 +2465,17 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "tokio-openssl" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59df6849caa43bb7567f9a36f863c447d95a11d5903c9cc334ba32576a27eadd" +dependencies = [ + "openssl", + "openssl-sys", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" @@ -2716,6 +2788,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" diff --git a/idevice/Cargo.toml b/idevice/Cargo.toml index 7096ef0..6fdfe36 100644 --- a/idevice/Cargo.toml +++ b/idevice/Cargo.toml @@ -12,16 +12,18 @@ keywords = ["lockdownd", "ios"] [dependencies] tokio = { version = "1", features = ["io-util"] } -tokio-rustls = { version = "0.26", default-features = false } +tokio-rustls = { version = "0.26", default-features = false, optional = true } rustls = { version = "0.23", default-features = false, features = [ "std", "tls12", -] } -crossfire = { version = "2.1", optional = true } +], optional = true } +tokio-openssl = { version = "0.6", optional = true } +openssl = { version = "0.10", optional = true } plist = { version = "1.8" } serde = { version = "1", features = ["derive"] } ns-keyed-archive = { version = "0.1.4", optional = true } +crossfire = { version = "2.1", optional = true } thiserror = { version = "2" } tracing = { version = "0.1.41" } @@ -64,8 +66,10 @@ bytes = "1.10.1" [features] default = ["aws-lc"] -aws-lc = ["rustls/aws-lc-rs", "tokio-rustls/aws-lc-rs"] -ring = ["rustls/ring", "tokio-rustls/ring"] +aws-lc = ["rustls", "rustls/aws-lc-rs", "tokio-rustls/aws-lc-rs"] +ring = ["rustls", "rustls/ring", "tokio-rustls/ring"] +rustls = ["dep:rustls", "dep:tokio-rustls"] +openssl = ["dep:openssl", "dep:tokio-openssl"] afc = ["dep:chrono"] amfi = [] diff --git a/idevice/src/lib.rs b/idevice/src/lib.rs index 3272104..7cbea9b 100644 --- a/idevice/src/lib.rs +++ b/idevice/src/lib.rs @@ -1,11 +1,12 @@ #![doc = include_str!("../README.md")] // Jackson Coxson -#[cfg(feature = "pair")] +#[cfg(all(feature = "pair", feature = "rustls"))] mod ca; pub mod pairing_file; pub mod plist_macro; pub mod provider; +#[cfg(feature = "rustls")] mod sni; #[cfg(feature = "tunnel_tcp_stack")] pub mod tcp; @@ -27,6 +28,7 @@ pub use services::*; pub use xpc::RemoteXpcClient; use provider::{IdeviceProvider, RsdProvider}; +#[cfg(feature = "rustls")] use rustls::{crypto::CryptoProvider, pki_types::ServerName}; use std::{ io::{self, BufWriter}, @@ -460,57 +462,84 @@ impl Idevice { &mut self, pairing_file: &pairing_file::PairingFile, ) -> Result<(), IdeviceError> { - if CryptoProvider::get_default().is_none() { - // rust-analyzer will choke on this block, don't worry about it - let crypto_provider: CryptoProvider = { - #[cfg(all(feature = "ring", not(feature = "aws-lc")))] - { - debug!("Using ring crypto backend"); - rustls::crypto::ring::default_provider() + #[cfg(feature = "rustls")] + { + if CryptoProvider::get_default().is_none() { + // rust-analyzer will choke on this block, don't worry about it + let crypto_provider: CryptoProvider = { + #[cfg(all(feature = "ring", not(feature = "aws-lc")))] + { + debug!("Using ring crypto backend"); + rustls::crypto::ring::default_provider() + } + + #[cfg(all(feature = "aws-lc", not(feature = "ring")))] + { + debug!("Using aws-lc crypto backend"); + rustls::crypto::aws_lc_rs::default_provider() + } + + #[cfg(not(any(feature = "ring", feature = "aws-lc")))] + { + compile_error!( + "No crypto backend was selected! Specify an idevice feature for a crypto backend" + ); + } + + #[cfg(all(feature = "ring", feature = "aws-lc"))] + { + // We can't throw a compile error because it breaks rust-analyzer. + // My sanity while debugging the workspace crates are more important. + + debug!("Using ring crypto backend, because both were passed"); + tracing::warn!( + "Both ring && aws-lc are selected as idevice crypto backends!" + ); + rustls::crypto::ring::default_provider() + } + }; + + if let Err(e) = CryptoProvider::install_default(crypto_provider) { + // For whatever reason, getting the default provider will return None on iOS at + // random. Installing the default provider a second time will return an error, so + // we will log it but not propogate it. An issue should be opened with rustls. + tracing::error!("Failed to set crypto provider: {e:?}"); } - - #[cfg(all(feature = "aws-lc", not(feature = "ring")))] - { - debug!("Using aws-lc crypto backend"); - rustls::crypto::aws_lc_rs::default_provider() - } - - #[cfg(not(any(feature = "ring", feature = "aws-lc")))] - { - compile_error!( - "No crypto backend was selected! Specify an idevice feature for a crypto backend" - ); - } - - #[cfg(all(feature = "ring", feature = "aws-lc"))] - { - // We can't throw a compile error because it breaks rust-analyzer. - // My sanity while debugging the workspace crates are more important. - - debug!("Using ring crypto backend, because both were passed"); - tracing::warn!("Both ring && aws-lc are selected as idevice crypto backends!"); - rustls::crypto::ring::default_provider() - } - }; - - if let Err(e) = CryptoProvider::install_default(crypto_provider) { - // For whatever reason, getting the default provider will return None on iOS at - // random. Installing the default provider a second time will return an error, so - // we will log it but not propogate it. An issue should be opened with rustls. - tracing::error!("Failed to set crypto provider: {e:?}"); } + let config = sni::create_client_config(pairing_file)?; + let connector = tokio_rustls::TlsConnector::from(Arc::new(config)); + + let socket = self.socket.take().unwrap(); + let socket = connector + .connect(ServerName::try_from("Device").unwrap(), socket) + .await?; + + self.socket = Some(Box::new(socket)); + + Ok(()) } - let config = sni::create_client_config(pairing_file)?; - let connector = tokio_rustls::TlsConnector::from(Arc::new(config)); + #[cfg(all(feature = "openssl", not(feature = "rustls")))] + { + let connector = + openssl::ssl::SslConnector::builder(openssl::ssl::SslMethod::tls()).unwrap(); - let socket = self.socket.take().unwrap(); - let socket = connector - .connect(ServerName::try_from("Device").unwrap(), socket) - .await?; + let mut connector = connector + .build() + .configure() + .unwrap() + .into_ssl("ur mom") + .unwrap(); - self.socket = Some(Box::new(socket)); + connector.set_certificate(&pairing_file.host_certificate)?; + connector.set_private_key(&pairing_file.host_private_key)?; + connector.set_verify(openssl::ssl::SslVerifyMode::empty()); + let socket = self.socket.take().unwrap(); + let mut ssl_stream = tokio_openssl::SslStream::new(connector, socket)?; + std::pin::Pin::new(&mut ssl_stream).connect().await?; + self.socket = Some(Box::new(ssl_stream)); - Ok(()) + Ok(()) + } } } @@ -521,12 +550,24 @@ impl Idevice { pub enum IdeviceError { #[error("device socket io failed")] Socket(#[from] io::Error) = -1, + #[cfg(all(feature = "rustls", not(feature = "openssl")))] #[error("PEM parse failed")] PemParseFailed(#[from] rustls::pki_types::pem::Error) = -2, + + #[cfg(all(feature = "rustls", not(feature = "openssl")))] #[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")))] #[error("TLS verifiction build failed")] TlsBuilderFailed(#[from] rustls::server::VerifierBuilderError) = -4, + #[cfg(all(feature = "openssl", not(feature = "rustls")))] + #[error("TLS verifiction build failed")] + TlsBuilderFailed(#[from] openssl::error::ErrorStack) = -4, + #[error("io on plist")] Plist(#[from] plist::Error) = -5, #[error("can't convert bytes to utf8")] diff --git a/idevice/src/pairing_file.rs b/idevice/src/pairing_file.rs index 6115af0..ee9c816 100644 --- a/idevice/src/pairing_file.rs +++ b/idevice/src/pairing_file.rs @@ -5,7 +5,13 @@ use std::path::Path; +#[cfg(feature = "openssl")] +use openssl::{ + pkey::{PKey, Private}, + x509::X509, +}; use plist::Data; +#[cfg(feature = "rustls")] use rustls::pki_types::{CertificateDer, pem::PemObject}; use serde::{Deserialize, Serialize}; use tracing::warn; @@ -14,6 +20,7 @@ use tracing::warn; /// /// Contains all cryptographic materials and identifiers needed for secure communication /// with an iOS device, including certificates, private keys, and device identifiers. +#[cfg(feature = "rustls")] #[derive(Clone, Debug)] pub struct PairingFile { /// Device's certificate in DER format @@ -38,6 +45,21 @@ pub struct PairingFile { pub udid: Option, } +#[cfg(all(feature = "openssl", not(feature = "rustls")))] +#[derive(Clone, Debug)] +pub struct PairingFile { + pub device_certificate: X509, + pub host_private_key: PKey, + pub host_certificate: X509, + pub root_private_key: PKey, + pub root_certificate: X509, + pub system_buid: String, + pub host_id: String, + pub escrow_bag: Vec, + pub wifi_mac_address: String, + pub udid: Option, +} + /// Internal representation of a pairing file for serialization/deserialization #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "PascalCase")] @@ -133,6 +155,7 @@ impl PairingFile { /// /// # Errors /// Returns `IdeviceError` if serialization fails + #[cfg(feature = "rustls")] pub fn serialize(self) -> Result, crate::IdeviceError> { let raw = RawPairingFile::from(self); @@ -140,8 +163,18 @@ impl PairingFile { plist::to_writer_xml(&mut buf, &raw)?; Ok(buf) } + + #[cfg(all(feature = "openssl", not(feature = "rustls")))] + pub fn serialize(self) -> Result, crate::IdeviceError> { + let raw = RawPairingFile::try_from(self)?; + + let mut buf = Vec::new(); + plist::to_writer_xml(&mut buf, &raw)?; + Ok(buf) + } } +#[cfg(feature = "rustls")] impl TryFrom for PairingFile { type Error = rustls::pki_types::pem::Error; @@ -180,6 +213,30 @@ impl TryFrom for PairingFile { } } +#[cfg(all(feature = "openssl", not(feature = "rustls")))] +impl TryFrom for PairingFile { + type Error = openssl::error::ErrorStack; + + fn try_from(value: RawPairingFile) -> Result { + Ok(Self { + device_certificate: X509::from_pem(&Into::>::into(value.device_certificate))?, + host_private_key: PKey::private_key_from_pem(&Into::>::into( + value.host_private_key, + ))?, + host_certificate: X509::from_pem(&Into::>::into(value.host_certificate))?, + root_private_key: PKey::private_key_from_pem(&Into::>::into( + value.root_private_key, + ))?, + root_certificate: X509::from_pem(&Into::>::into(value.root_certificate))?, + system_buid: value.system_buid, + host_id: value.host_id, + escrow_bag: value.escrow_bag.into(), + wifi_mac_address: value.wifi_mac_address, + udid: value.udid, + }) + } +} + impl From for RawPairingFile { /// Converts a structured pairing file into a raw pairing file for serialization fn from(value: PairingFile) -> Self { diff --git a/idevice/src/services/lockdown.rs b/idevice/src/services/lockdown.rs index 5d16e23..0218723 100644 --- a/idevice/src/services/lockdown.rs +++ b/idevice/src/services/lockdown.rs @@ -243,7 +243,7 @@ impl LockdownClient { /// /// # Errors /// Returns `IdeviceError` - #[cfg(feature = "pair")] + #[cfg(all(feature = "pair", feature = "rustls"))] pub async fn pair( &mut self, host_id: impl Into, diff --git a/tools/Cargo.toml b/tools/Cargo.toml index b88a6c8..90713e9 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -161,3 +161,4 @@ futures-util = { version = "0.3" } default = ["aws-lc"] aws-lc = ["idevice/aws-lc"] ring = ["idevice/ring"] +openssl = ["idevice/openssl"]