From 5e014055d1c9e83fca85e58f29d4227075f383c7 Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Wed, 8 Jan 2025 16:21:41 -0700 Subject: [PATCH] Initial rewrite commit --- .gitignore | 1 + Cargo.lock | 521 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 + src/lib.rs | 203 +++++++++++++++++ src/pairing_file.rs | 103 +++++++++ 5 files changed, 840 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/pairing_file.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..2bbafc7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,521 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cc" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[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 = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "idevice" +version = "0.1.0" +dependencies = [ + "env_logger", + "log", + "openssl", + "plist", + "serde", + "thiserror", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +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", +] + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "plist" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +dependencies = [ + "base64", + "indexmap", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..123a3e9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "idevice" +version = "0.1.0" +edition = "2021" + +[dependencies] +plist = { version = "1.7" } +serde = { version = "1", features = ["derive"] } +thiserror = { version = "2" } +log = { version = "0.4" } +env_logger = { version = "0.11" } +openssl = { version = "0.10" } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d4b015a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,203 @@ +// Jackson Coxson + +const LOCKDOWND_PORT: u16 = 62078; + +mod pairing_file; + +use log::debug; +use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; +use serde::{Deserialize, Serialize}; +use std::io::{self, BufWriter, Read, Write}; +use thiserror::Error; + +trait ReadWrite: Read + Write + std::fmt::Debug {} +impl ReadWrite for T {} + +pub struct LockdowndClient { + socket: Option>, // in a box for now to use the ReadWrite trait for further uses + label: String, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "PascalCase")] +struct LockdowndRequest { + label: String, + key: Option, + request: String, +} + +impl LockdowndClient { + pub fn get_type(&mut self) -> Result { + let req = LockdowndRequest { + label: self.label.clone(), + key: None, + request: "QueryType".to_string(), + }; + let message = plist::to_value(&req)?; + self.send_plist(message)?; + let message: plist::Dictionary = self.read_plist()?; + match message.get("Type") { + Some(m) => Ok(plist::from_value(m)?), + None => Err(IdeviceError::UnexpectedResponse), + } + } + + pub fn get_value(&mut self, value: impl Into) -> Result { + let req = LockdowndRequest { + label: self.label.clone(), + key: Some(value.into()), + request: "GetValue".to_string(), + }; + let message = plist::to_value(&req)?; + self.send_plist(message)?; + let message: plist::Dictionary = self.read_plist()?; + match message.get("Value") { + Some(m) => Ok(plist::from_value(m)?), + None => Err(IdeviceError::UnexpectedResponse), + } + } + + pub fn get_all_values(&mut self) -> Result { + let req = LockdowndRequest { + label: self.label.clone(), + key: None, + request: "GetValue".to_string(), + }; + let message = plist::to_value(&req)?; + self.send_plist(message)?; + let message: plist::Dictionary = self.read_plist()?; + match message.get("Value") { + Some(m) => Ok(plist::from_value(m)?), + None => Err(IdeviceError::UnexpectedResponse), + } + } + + /// Sends a plist to the socket + fn send_plist(&mut self, message: plist::Value) -> Result<(), IdeviceError> { + if let Some(socket) = &mut self.socket { + let buf = Vec::new(); + let mut writer = BufWriter::new(buf); + message.to_writer_xml(&mut writer)?; + let message = writer.into_inner().unwrap(); + let message = String::from_utf8(message)?; + let len = message.len() as u32; + socket.write_all(&len.to_be_bytes())?; + socket.write_all(message.as_bytes())?; + Ok(()) + } else { + Err(IdeviceError::NoEstablishedConnection) + } + } + + /// Read a plist from the socket + fn read_plist(&mut self) -> Result { + if let Some(socket) = &mut self.socket { + debug!("Reading response size"); + let mut buf = [0u8; 4]; + socket.read_exact(&mut buf)?; + let len = u32::from_be_bytes(buf); + let mut buf = vec![0; len as usize]; + socket.read_exact(&mut buf)?; + let res: plist::Dictionary = plist::from_bytes(&buf)?; + debug!("Received plist: {res:#?}"); + + if let Some(e) = res.get("Error") { + let e: String = plist::from_value(e)?; + if let Some(e) = IdeviceError::from_device_error_type(e.as_str()) { + return Err(e); + } else { + return Err(IdeviceError::UnknownErrorType(e)); + } + } + Ok(res) + } else { + Err(IdeviceError::NoEstablishedConnection) + } + } + + /// Starts a TLS session with the client + pub fn start_session( + &mut self, + pairing_file: pairing_file::PairingFile, + ) -> Result<(), IdeviceError> { + if self.socket.is_none() { + return Err(IdeviceError::NoEstablishedConnection); + } + + let mut request = plist::Dictionary::new(); + request.insert( + "Label".to_string(), + plist::Value::String(self.label.clone()), + ); + + request.insert( + "Request".to_string(), + plist::Value::String("StartSession".to_string()), + ); + request.insert( + "HostID".to_string(), + plist::Value::String(pairing_file.host_id.clone()), + ); + request.insert( + "SystemBUID".to_string(), + plist::Value::String(pairing_file.system_buid.clone()), + ); + + self.send_plist(plist::Value::Dictionary(request))?; + + let response = self.read_plist()?; + match response.get("EnableSessionSSL") { + Some(plist::Value::Boolean(enable)) => { + if !enable { + return Err(IdeviceError::UnexpectedResponse); + } + } + _ => { + return Err(IdeviceError::UnexpectedResponse); + } + } + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector + .set_certificate(&pairing_file.host_certificate) + .unwrap(); + connector + .set_private_key(&pairing_file.host_private_key) + .unwrap(); + connector.set_verify(SslVerifyMode::empty()); + + let connector = connector.build(); + let socket = self.socket.take().unwrap(); + let ssl_stream = connector.connect("ur mom", socket).unwrap(); + self.socket = Some(Box::new(ssl_stream)); + + Ok(()) + } +} + +#[derive(Error, Debug)] +pub enum IdeviceError { + #[error("device socket io failed")] + Socket(#[from] io::Error), + #[error("io on plist")] + Plist(#[from] plist::Error), + #[error("can't convert bytes to utf8")] + Utf8(#[from] std::string::FromUtf8Error), + #[error("unexpected response from device")] + UnexpectedResponse, + #[error("this request was prohibited")] + GetProhibited, + #[error("no established connection")] + NoEstablishedConnection, + #[error("unknown error `{0}` returned from device")] + UnknownErrorType(String), +} + +impl IdeviceError { + fn from_device_error_type(e: &str) -> Option { + match e { + "GetProhibited" => Some(Self::GetProhibited), + _ => None, + } + } +} diff --git a/src/pairing_file.rs b/src/pairing_file.rs new file mode 100644 index 0000000..743fecd --- /dev/null +++ b/src/pairing_file.rs @@ -0,0 +1,103 @@ +// Jackson Coxson + +use std::path::Path; + +use log::warn; +use openssl::{ + pkey::{PKey, Private}, + x509::X509, +}; +use plist::Data; +use serde::{Deserialize, Serialize}; + +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: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "PascalCase")] +struct RawPairingFile { + device_certificate: Data, + host_private_key: Data, + host_certificate: Data, + root_private_key: Data, + root_certificate: Data, + #[serde(rename = "SystemBUID")] + system_buid: String, + #[serde(rename = "HostID")] + host_id: String, + escrow_bag: Data, + #[serde(rename = "WiFiMACAddress")] + wifi_mac_address: String, + #[serde(rename = "UDID")] + udid: String, +} + +impl PairingFile { + pub fn read_from_file(path: impl AsRef) -> Result { + let f = std::fs::read_to_string(path)?; + let r = match plist::from_bytes::(f.as_bytes()) { + Ok(r) => r, + Err(e) => { + warn!("Unable to read raw pairing file to memory: {e:?}"); + return Err(crate::IdeviceError::UnexpectedResponse); + } + }; + match r.try_into() { + Ok(r) => Ok(r), + Err(e) => { + warn!("Unable to convert raw pairing file into pairing file: {e:?}"); + Err(crate::IdeviceError::UnexpectedResponse) + } + } + } +} + +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, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn f1() { + let f = std::fs::read_to_string( + "/Users/jacksoncoxson/Documents/00008140-0016243626F3001C.mobiledevicepairing", + ) + .unwrap(); + let p: plist::Dictionary = plist::from_bytes(f.as_bytes()).unwrap(); + println!("{p:#?}"); + let p: RawPairingFile = plist::from_bytes(f.as_bytes()).unwrap(); + println!("{p:#?}"); + } +}