mirror of
https://github.com/nab138/isideload.git
synced 2026-03-02 06:26:16 +01:00
Retrieve certificates
This commit is contained in:
219
Cargo.lock
generated
219
Cargo.lock
generated
@@ -26,7 +26,7 @@ checksum = "04097e08a47d9ad181c2e1f4a5fabc9ae06ce8839a333ba9a949bcb0d31fd2a3"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
"cpubits",
|
||||
"cpufeatures",
|
||||
"cpufeatures 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -43,6 +43,15 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
@@ -164,6 +173,16 @@ version = "1.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||
|
||||
[[package]]
|
||||
name = "bcder"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f7c42c9913f68cf9390a225e81ad56a5c515347287eb98baa710090ca1de86d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
@@ -254,6 +273,28 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.3.0",
|
||||
"rand_core 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.5.0"
|
||||
@@ -307,6 +348,12 @@ version = "0.4.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d"
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.10.2"
|
||||
@@ -354,6 +401,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
@@ -455,13 +511,23 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||
dependencies = [
|
||||
"const-oid 0.9.6",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.8.0-rc.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02c1d73e9668ea6b6a28172aa55f3ebec38507131ce179051c8033b5c6037653"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"const-oid 0.10.2",
|
||||
"pem-rfc7468",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -506,7 +572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b42f1d9edf5207c137646b568a0168ca0ec25b7f9eaf7f9961da51a3d91cea"
|
||||
dependencies = [
|
||||
"block-buffer 0.11.0",
|
||||
"const-oid",
|
||||
"const-oid 0.10.2",
|
||||
"crypto-common 0.2.0",
|
||||
"subtle",
|
||||
]
|
||||
@@ -901,6 +967,30 @@ dependencies = [
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.1.1"
|
||||
@@ -1082,7 +1172,7 @@ dependencies = [
|
||||
"pbkdf2",
|
||||
"plist",
|
||||
"plist-macro",
|
||||
"rand",
|
||||
"rand 0.10.0",
|
||||
"rcgen",
|
||||
"reqwest",
|
||||
"rootcause",
|
||||
@@ -1096,7 +1186,7 @@ dependencies = [
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"x509-parser",
|
||||
"x509-certificate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1403,8 +1493,8 @@ version = "0.8.0-rc.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
"der 0.8.0-rc.10",
|
||||
"spki 0.8.0-rc.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1413,8 +1503,8 @@ version = "0.11.0-rc.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b226d2cc389763951db8869584fd800cbbe2962bf454e2edeb5172b31ee99774"
|
||||
dependencies = [
|
||||
"der",
|
||||
"spki",
|
||||
"der 0.8.0-rc.10",
|
||||
"spki 0.8.0-rc.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1451,7 +1541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63641a86fddf4b5274f31c43734458ec7acd3133016dbaa37e4e247e1e9acd46"
|
||||
dependencies = [
|
||||
"cpubits",
|
||||
"cpufeatures",
|
||||
"cpufeatures 0.2.17",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
@@ -1537,7 +1627,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.4",
|
||||
"lru-slab",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
@@ -1588,6 +1678,17 @@ dependencies = [
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8"
|
||||
dependencies = [
|
||||
"chacha20",
|
||||
"getrandom 0.4.1",
|
||||
"rand_core 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
@@ -1598,6 +1699,15 @@ dependencies = [
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.5"
|
||||
@@ -1709,15 +1819,15 @@ version = "0.10.0-rc.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b342b99544549f37509ed7fd42b0cea04bfd9ce07c16ca56094cf0fbeefbbcd"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"const-oid 0.10.2",
|
||||
"crypto-bigint",
|
||||
"crypto-primes",
|
||||
"digest 0.11.0-rc.11",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core 0.10.0",
|
||||
"signature",
|
||||
"spki",
|
||||
"signature 3.0.0-rc.10",
|
||||
"spki 0.8.0-rc.4",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -1935,7 +2045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"cpufeatures 0.2.17",
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
@@ -1946,7 +2056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"cpufeatures 0.2.17",
|
||||
"digest 0.11.0-rc.11",
|
||||
]
|
||||
|
||||
@@ -1965,6 +2075,15 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "3.0.0-rc.10"
|
||||
@@ -2003,6 +2122,16 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der 0.7.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.8.0-rc.4"
|
||||
@@ -2010,7 +2139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"der",
|
||||
"der 0.8.0-rc.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2389,7 +2518,7 @@ dependencies = [
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
@@ -2676,6 +2805,41 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
@@ -3036,6 +3200,25 @@ version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
|
||||
|
||||
[[package]]
|
||||
name = "x509-certificate"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca9eb9a0c822c67129d5b8fcc2806c6bc4f50496b420825069a440669bcfbf7f"
|
||||
dependencies = [
|
||||
"bcder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"der 0.7.10",
|
||||
"hex",
|
||||
"pem",
|
||||
"ring",
|
||||
"signature 2.2.0",
|
||||
"spki 0.7.3",
|
||||
"thiserror 2.0.18",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x509-parser"
|
||||
version = "0.18.1"
|
||||
|
||||
@@ -6,6 +6,12 @@ A Rust library for sideloading iOS applications using an Apple ID. Used in [Cros
|
||||
|
||||
This branch is home to isideload-next, the next major version of isideload. It features a redesigned API, improved error handling, better entitlement handling, and more. It is not ready!
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Signing apps
|
||||
- [ ] Installing apps
|
||||
- [ ] Remove dependency on ring
|
||||
|
||||
## Licensing
|
||||
|
||||
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
@@ -10,4 +10,4 @@ plist-macro = "0.1.3"
|
||||
tokio = { version = "1.49.0", features = ["rt-multi-thread", "macros"] }
|
||||
tracing = "0.1.44"
|
||||
tracing-subscriber = "0.3.22"
|
||||
idevice = { version = "0.1.52", features = ["usbmuxd"]}
|
||||
idevice = { version = "0.1.52", features = ["usbmuxd"] }
|
||||
@@ -42,10 +42,10 @@ async fn main() {
|
||||
.login(apple_password, get_2fa_code)
|
||||
.await;
|
||||
|
||||
match &account {
|
||||
Ok(a) => println!("Logged in. {}", a),
|
||||
Err(e) => panic!("Failed to log in to Apple ID: {:?}", e),
|
||||
}
|
||||
// match &account {
|
||||
// Ok(a) => println!("Logged in. {}", a),
|
||||
// Err(e) => panic!("Failed to log in to Apple ID: {:?}", e),
|
||||
// }
|
||||
|
||||
let mut account = account.unwrap();
|
||||
|
||||
@@ -70,7 +70,7 @@ async fn main() {
|
||||
.unwrap()
|
||||
.to_provider(UsbmuxdAddr::from_env_var().unwrap(), "isideload-demo");
|
||||
|
||||
let mut sideloader = SideloaderBuilder::new(dev_session)
|
||||
let mut sideloader = SideloaderBuilder::new(dev_session, apple_id.to_string())
|
||||
.team_selection(TeamSelection::Prompt(|teams| {
|
||||
println!("Please select a team:");
|
||||
for (index, team) in teams.iter().enumerate() {
|
||||
|
||||
@@ -23,7 +23,7 @@ reqwest = { version = "0.13.1", features = ["json", "gzip"] }
|
||||
thiserror = "2.0.17"
|
||||
async-trait = "0.1.89"
|
||||
serde = "1.0.228"
|
||||
rand = "0.9.2"
|
||||
rand = "0.10.0"
|
||||
uuid = {version = "1.20.0", features = ["v4"] }
|
||||
tracing = "0.1.44"
|
||||
tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-webpki-roots"] }
|
||||
@@ -42,5 +42,5 @@ aes-gcm = "0.11.0-rc.3"
|
||||
rsa = { version = "0.10.0-rc.15" }
|
||||
tokio = "1.49.0"
|
||||
keyring = { version = "3.6.3", features = ["apple-native", "linux-native-sync-persistent", "windows-native"], optional = true }
|
||||
x509-parser = "0.18.1"
|
||||
x509-certificate = "0.25"
|
||||
rcgen = { version = "0.14.7", default-features = false, features = ["aws_lc_rs", "pem"] }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Serialization/Desieralization borrowed from https://github.com/SideStore/apple-private-apis/blob/master/omnisette/src/remote_anisette_v3.rs
|
||||
|
||||
use plist::Data;
|
||||
use rand::Rng;
|
||||
use rand::RngExt;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use sha2::{Digest, Sha256};
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -26,32 +26,58 @@ impl Display for TeamSelection {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MaxCertsBehavior {
|
||||
/// If the maximum number of certificates is reached, delete all existing certificates and create a new one
|
||||
Revoke,
|
||||
/// If the maximum number of certificates is reached, return an error instead of creating a new certificate
|
||||
Error,
|
||||
}
|
||||
|
||||
pub struct SideloaderBuilder {
|
||||
team_selection: TeamSelection,
|
||||
storage: Box<dyn SideloadingStorage>,
|
||||
developer_session: DeveloperSession,
|
||||
apple_email: String,
|
||||
team_selection: Option<TeamSelection>,
|
||||
max_certs_behavior: Option<MaxCertsBehavior>,
|
||||
storage: Option<Box<dyn SideloadingStorage>>,
|
||||
machine_name: Option<String>,
|
||||
}
|
||||
|
||||
impl SideloaderBuilder {
|
||||
pub fn new(developer_session: DeveloperSession) -> Self {
|
||||
pub fn new(developer_session: DeveloperSession, apple_email: String) -> Self {
|
||||
SideloaderBuilder {
|
||||
team_selection: TeamSelection::First,
|
||||
storage: Box::new(crate::util::storage::new_storage()),
|
||||
team_selection: None,
|
||||
storage: None,
|
||||
developer_session,
|
||||
machine_name: None,
|
||||
apple_email,
|
||||
max_certs_behavior: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn team_selection(mut self, selection: TeamSelection) -> Self {
|
||||
self.team_selection = selection;
|
||||
self.team_selection = Some(selection);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn storage(mut self, storage: Box<dyn SideloadingStorage>) -> Self {
|
||||
self.storage = storage;
|
||||
self.storage = Some(storage);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn machine_name(mut self, machine_name: String) -> Self {
|
||||
self.machine_name = Some(machine_name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Sideloader {
|
||||
Sideloader::new(self.team_selection, self.storage, self.developer_session)
|
||||
Sideloader::new(
|
||||
self.developer_session,
|
||||
self.apple_email,
|
||||
self.team_selection.unwrap_or(TeamSelection::First),
|
||||
self.max_certs_behavior.unwrap_or(MaxCertsBehavior::Revoke),
|
||||
self.machine_name.unwrap_or_else(|| "isideload".to_string()),
|
||||
self.storage
|
||||
.unwrap_or_else(|| Box::new(crate::util::storage::new_storage())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
use rcgen::{CertificateParams, DistinguishedName, DnType, PKCS_RSA_SHA256};
|
||||
use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, PKCS_RSA_SHA256};
|
||||
use rootcause::prelude::*;
|
||||
use rsa::{
|
||||
RsaPrivateKey,
|
||||
pkcs8::{DecodePrivateKey, EncodePublicKey},
|
||||
pkcs1::EncodeRsaPublicKey,
|
||||
pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding},
|
||||
};
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use tracing::{error, info};
|
||||
use x509_certificate::X509Certificate;
|
||||
|
||||
use crate::{
|
||||
dev::{
|
||||
certificates::CertificatesApi, developer_session::DeveloperSession, teams::DeveloperTeam,
|
||||
},
|
||||
sideload::builder::MaxCertsBehavior,
|
||||
util::storage::SideloadingStorage,
|
||||
};
|
||||
|
||||
pub struct CertificateIdentity {
|
||||
pub machine_id: String,
|
||||
pub machine_name: String,
|
||||
pub certificate: X509Certificate,
|
||||
}
|
||||
|
||||
impl CertificateIdentity {
|
||||
@@ -26,70 +31,82 @@ impl CertificateIdentity {
|
||||
developer_session: &mut DeveloperSession,
|
||||
team: &DeveloperTeam,
|
||||
storage: &dyn SideloadingStorage,
|
||||
max_certs_behavior: &MaxCertsBehavior,
|
||||
) -> Result<Self, Report> {
|
||||
let stored = Self::retrieve_from_storage(
|
||||
machine_name,
|
||||
apple_email,
|
||||
developer_session,
|
||||
team,
|
||||
storage,
|
||||
)
|
||||
.await;
|
||||
if let Ok(Some(cert)) = stored {
|
||||
let pr = Self::retrieve_private_key(apple_email, storage).await?;
|
||||
|
||||
let found = Self::find_matching(&pr, machine_name, developer_session, team).await;
|
||||
if let Ok(Some(cert)) = found {
|
||||
info!("Found matching certificate");
|
||||
return Ok(cert);
|
||||
}
|
||||
|
||||
if let Err(e) = stored {
|
||||
error!("Failed to load stored certificate: {:?}", e);
|
||||
} else {
|
||||
info!("No stored certificate found");
|
||||
if let Err(e) = found {
|
||||
error!("Failed to check for matching certificate: {:?}", e);
|
||||
}
|
||||
|
||||
todo!("generate CSR")
|
||||
info!("Requesting new certificate");
|
||||
Self::request_certificate(
|
||||
&pr,
|
||||
machine_name.to_string(),
|
||||
developer_session,
|
||||
team,
|
||||
max_certs_behavior,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn retrieve_from_storage(
|
||||
machine_name: &str,
|
||||
async fn retrieve_private_key(
|
||||
apple_email: &str,
|
||||
developer_session: &mut DeveloperSession,
|
||||
team: &DeveloperTeam,
|
||||
storage: &dyn SideloadingStorage,
|
||||
) -> Result<Option<Self>, Report> {
|
||||
) -> Result<RsaPrivateKey, Report> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(apple_email.as_bytes());
|
||||
let email_hash = hex::encode(hasher.finalize());
|
||||
|
||||
let private_key = storage.retrieve(&format!("{}/key", email_hash))?;
|
||||
if private_key.is_none() {
|
||||
return Ok(None);
|
||||
if private_key.is_some() {
|
||||
return Ok(RsaPrivateKey::from_pkcs8_pem(&private_key.unwrap())?);
|
||||
}
|
||||
let private_key = RsaPrivateKey::from_pkcs8_pem(&private_key.unwrap())?;
|
||||
let public_key_der = private_key.to_public_key().to_public_key_der()?;
|
||||
|
||||
let mut rng = rand::rng();
|
||||
let private_key = RsaPrivateKey::new(&mut rng, 2048)?;
|
||||
storage.store(
|
||||
&format!("{}/key", email_hash),
|
||||
&private_key.to_pkcs8_pem(Default::default())?.to_string(),
|
||||
)?;
|
||||
|
||||
Ok(private_key)
|
||||
}
|
||||
|
||||
async fn find_matching(
|
||||
private_key: &RsaPrivateKey,
|
||||
machine_name: &str,
|
||||
developer_session: &mut DeveloperSession,
|
||||
team: &DeveloperTeam,
|
||||
) -> Result<Option<Self>, Report> {
|
||||
let public_key_der = private_key
|
||||
.to_public_key()
|
||||
.to_pkcs1_der()?
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
for cert in developer_session
|
||||
.list_ios_certs(team)
|
||||
.await?
|
||||
.iter()
|
||||
.filter(|c| {
|
||||
c.cert_content.is_some() && c.machine_name.as_deref().unwrap_or("") == machine_name
|
||||
c.cert_content.is_some()
|
||||
&& c.machine_name.as_deref().unwrap_or("") == machine_name
|
||||
&& c.machine_id.is_some()
|
||||
})
|
||||
{
|
||||
let x509_cert =
|
||||
x509_parser::parse_x509_certificate(cert.cert_content.as_ref().unwrap().as_ref())?;
|
||||
if x509_cert
|
||||
.1
|
||||
.tbs_certificate
|
||||
.subject_pki
|
||||
.subject_public_key
|
||||
.data
|
||||
== public_key_der.as_ref()
|
||||
{
|
||||
X509Certificate::from_der(cert.cert_content.as_ref().unwrap().as_ref())?;
|
||||
|
||||
if public_key_der == x509_cert.public_key_data().as_ref() {
|
||||
return Ok(Some(Self {
|
||||
machine_id: cert
|
||||
.machine_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| x509_cert.1.tbs_certificate.subject.to_string()),
|
||||
machine_name: machine_name.to_string(),
|
||||
machine_id: cert.machine_id.clone().unwrap_or_default(),
|
||||
machine_name: cert.machine_name.clone().unwrap_or_default(),
|
||||
certificate: x509_cert,
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -98,16 +115,46 @@ impl CertificateIdentity {
|
||||
}
|
||||
|
||||
async fn request_certificate(
|
||||
machine_name: &str,
|
||||
private_key: &RsaPrivateKey,
|
||||
machine_name: String,
|
||||
developer_session: &mut DeveloperSession,
|
||||
team: &DeveloperTeam,
|
||||
max_certs_behavior: &MaxCertsBehavior,
|
||||
) -> Result<Self, Report> {
|
||||
Ok(())
|
||||
let csr = Self::build_csr(private_key).context("Failed to generate CSR")?;
|
||||
|
||||
let request = developer_session
|
||||
.submit_development_csr(team, csr, machine_name, None)
|
||||
.await?;
|
||||
|
||||
// TODO: Handle max certs behavior properly instead of just always revoking
|
||||
|
||||
let apple_certs = developer_session.list_ios_certs(team).await?;
|
||||
|
||||
let apple_cert = apple_certs
|
||||
.iter()
|
||||
.find(|c| c.certificate_id == Some(request.cert_request_id.clone()))
|
||||
.ok_or_else(|| report!("Failed to find certificate after submitting CSR"))?;
|
||||
|
||||
let x509_cert = X509Certificate::from_der(
|
||||
apple_cert
|
||||
.cert_content
|
||||
.as_ref()
|
||||
.ok_or_else(|| report!("Certificate content missing"))?
|
||||
.as_ref(),
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
machine_id: apple_cert.machine_id.clone().unwrap_or_default(),
|
||||
machine_name: apple_cert.machine_name.clone().unwrap_or_default(),
|
||||
certificate: x509_cert,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_csr(private_key: &RsaPrivateKey) -> Result<String, Report> {
|
||||
let mut params = CertificateParams::new(vec![])?;
|
||||
let mut dn = DistinguishedName::new();
|
||||
|
||||
dn.push(DnType::CountryName, "US");
|
||||
dn.push(DnType::StateOrProvinceName, "STATE");
|
||||
dn.push(DnType::LocalityName, "LOCAL");
|
||||
@@ -115,6 +162,11 @@ impl CertificateIdentity {
|
||||
dn.push(DnType::CommonName, "CN");
|
||||
params.distinguished_name = dn;
|
||||
|
||||
Ok(())
|
||||
let subject_key = KeyPair::from_pkcs8_pem_and_sign_algo(
|
||||
&private_key.to_pkcs8_pem(LineEnding::LF)?,
|
||||
&PKCS_RSA_SHA256,
|
||||
)?;
|
||||
|
||||
Ok(params.serialize_request(&subject_key)?.pem()?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::{
|
||||
devices::DevicesApi,
|
||||
teams::{DeveloperTeam, TeamsApi},
|
||||
},
|
||||
sideload::TeamSelection,
|
||||
sideload::{TeamSelection, builder::MaxCertsBehavior, certificate::CertificateIdentity},
|
||||
util::{device::IdeviceInfo, storage::SideloadingStorage},
|
||||
};
|
||||
|
||||
@@ -18,18 +18,27 @@ pub struct Sideloader {
|
||||
team_selection: TeamSelection,
|
||||
storage: Box<dyn SideloadingStorage>,
|
||||
dev_session: DeveloperSession,
|
||||
machine_name: String,
|
||||
apple_email: String,
|
||||
max_certs_behavior: MaxCertsBehavior,
|
||||
}
|
||||
|
||||
impl Sideloader {
|
||||
pub fn new(
|
||||
team_selection: TeamSelection,
|
||||
storage: Box<dyn SideloadingStorage>,
|
||||
dev_session: DeveloperSession,
|
||||
apple_email: String,
|
||||
team_selection: TeamSelection,
|
||||
max_certs_behavior: MaxCertsBehavior,
|
||||
machine_name: String,
|
||||
storage: Box<dyn SideloadingStorage>,
|
||||
) -> Self {
|
||||
Sideloader {
|
||||
team_selection,
|
||||
storage,
|
||||
dev_session,
|
||||
machine_name,
|
||||
apple_email,
|
||||
max_certs_behavior,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +55,21 @@ impl Sideloader {
|
||||
.ensure_device_registered(&team, &device_info.name, &device_info.udid, None)
|
||||
.await?;
|
||||
|
||||
let cert_identity = CertificateIdentity::retrieve(
|
||||
&self.machine_name,
|
||||
&self.apple_email,
|
||||
&mut self.dev_session,
|
||||
&team,
|
||||
self.storage.as_ref(),
|
||||
&self.max_certs_behavior,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// info!(
|
||||
// "Using certificate for machine {} with ID {}",
|
||||
// cert_identity.machine_name, cert_identity.machine_id
|
||||
// );
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
|
||||
use base64::prelude::*;
|
||||
use rootcause::prelude::*;
|
||||
|
||||
pub trait SideloadingStorage: Send + Sync {
|
||||
|
||||
Reference in New Issue
Block a user