├── .gitignore ├── .gitmodules ├── Cargo.lock ├── Cargo.toml ├── README.md ├── apple-auth-py ├── Cargo.toml ├── README.md └── src │ └── lib.rs ├── apple-auth-utils ├── Cargo.toml ├── build.rs └── src │ ├── lib.rs │ └── requests.rs └── sample_data └── machine_info.json /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "apple-auth-utils/apple_crypto"] 2 | path = apple-auth-utils/apple_crypto 3 | url = https://github.com/Smoothstep/apple-gen.git 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "apple-auth-py" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "apple-auth-utils", 16 | "pyo3", 17 | ] 18 | 19 | [[package]] 20 | name = "apple-auth-utils" 21 | version = "0.1.0" 22 | dependencies = [ 23 | "cc", 24 | "cmake", 25 | "libc", 26 | "plist", 27 | "rustls", 28 | "serde", 29 | "serde_json", 30 | "ureq", 31 | ] 32 | 33 | [[package]] 34 | name = "autocfg" 35 | version = "1.1.0" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 38 | 39 | [[package]] 40 | name = "base64" 41 | version = "0.21.4" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" 44 | 45 | [[package]] 46 | name = "bitflags" 47 | version = "1.3.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 50 | 51 | [[package]] 52 | name = "bumpalo" 53 | version = "3.14.0" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 56 | 57 | [[package]] 58 | name = "cc" 59 | version = "1.0.83" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 62 | dependencies = [ 63 | "libc", 64 | ] 65 | 66 | [[package]] 67 | name = "cfg-if" 68 | version = "1.0.0" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 71 | 72 | [[package]] 73 | name = "cmake" 74 | version = "0.1.50" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 77 | dependencies = [ 78 | "cc", 79 | ] 80 | 81 | [[package]] 82 | name = "crc32fast" 83 | version = "1.3.2" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 86 | dependencies = [ 87 | "cfg-if", 88 | ] 89 | 90 | [[package]] 91 | name = "deranged" 92 | version = "0.3.8" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" 95 | 96 | [[package]] 97 | name = "flate2" 98 | version = "1.0.27" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" 101 | dependencies = [ 102 | "crc32fast", 103 | "miniz_oxide", 104 | ] 105 | 106 | [[package]] 107 | name = "form_urlencoded" 108 | version = "1.2.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 111 | dependencies = [ 112 | "percent-encoding", 113 | ] 114 | 115 | [[package]] 116 | name = "hashbrown" 117 | version = "0.12.3" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 120 | 121 | [[package]] 122 | name = "idna" 123 | version = "0.4.0" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" 126 | dependencies = [ 127 | "unicode-bidi", 128 | "unicode-normalization", 129 | ] 130 | 131 | [[package]] 132 | name = "indexmap" 133 | version = "1.9.3" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 136 | dependencies = [ 137 | "autocfg", 138 | "hashbrown", 139 | ] 140 | 141 | [[package]] 142 | name = "indoc" 143 | version = "1.0.9" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" 146 | 147 | [[package]] 148 | name = "itoa" 149 | version = "1.0.9" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 152 | 153 | [[package]] 154 | name = "js-sys" 155 | version = "0.3.64" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" 158 | dependencies = [ 159 | "wasm-bindgen", 160 | ] 161 | 162 | [[package]] 163 | name = "libc" 164 | version = "0.2.148" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" 167 | 168 | [[package]] 169 | name = "line-wrap" 170 | version = "0.1.1" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" 173 | dependencies = [ 174 | "safemem", 175 | ] 176 | 177 | [[package]] 178 | name = "lock_api" 179 | version = "0.4.10" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 182 | dependencies = [ 183 | "autocfg", 184 | "scopeguard", 185 | ] 186 | 187 | [[package]] 188 | name = "log" 189 | version = "0.4.20" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 192 | 193 | [[package]] 194 | name = "memchr" 195 | version = "2.6.3" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" 198 | 199 | [[package]] 200 | name = "memoffset" 201 | version = "0.9.0" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 204 | dependencies = [ 205 | "autocfg", 206 | ] 207 | 208 | [[package]] 209 | name = "miniz_oxide" 210 | version = "0.7.1" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 213 | dependencies = [ 214 | "adler", 215 | ] 216 | 217 | [[package]] 218 | name = "once_cell" 219 | version = "1.18.0" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 222 | 223 | [[package]] 224 | name = "parking_lot" 225 | version = "0.12.1" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 228 | dependencies = [ 229 | "lock_api", 230 | "parking_lot_core", 231 | ] 232 | 233 | [[package]] 234 | name = "parking_lot_core" 235 | version = "0.9.8" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" 238 | dependencies = [ 239 | "cfg-if", 240 | "libc", 241 | "redox_syscall", 242 | "smallvec", 243 | "windows-targets", 244 | ] 245 | 246 | [[package]] 247 | name = "percent-encoding" 248 | version = "2.3.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 251 | 252 | [[package]] 253 | name = "plist" 254 | version = "1.5.0" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06" 257 | dependencies = [ 258 | "base64", 259 | "indexmap", 260 | "line-wrap", 261 | "quick-xml", 262 | "serde", 263 | "time", 264 | ] 265 | 266 | [[package]] 267 | name = "proc-macro2" 268 | version = "1.0.67" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" 271 | dependencies = [ 272 | "unicode-ident", 273 | ] 274 | 275 | [[package]] 276 | name = "pyo3" 277 | version = "0.19.2" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" 280 | dependencies = [ 281 | "cfg-if", 282 | "indoc", 283 | "libc", 284 | "memoffset", 285 | "parking_lot", 286 | "pyo3-build-config", 287 | "pyo3-ffi", 288 | "pyo3-macros", 289 | "unindent", 290 | ] 291 | 292 | [[package]] 293 | name = "pyo3-build-config" 294 | version = "0.19.2" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5" 297 | dependencies = [ 298 | "once_cell", 299 | "target-lexicon", 300 | ] 301 | 302 | [[package]] 303 | name = "pyo3-ffi" 304 | version = "0.19.2" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9" 307 | dependencies = [ 308 | "libc", 309 | "pyo3-build-config", 310 | ] 311 | 312 | [[package]] 313 | name = "pyo3-macros" 314 | version = "0.19.2" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1" 317 | dependencies = [ 318 | "proc-macro2", 319 | "pyo3-macros-backend", 320 | "quote", 321 | "syn 1.0.109", 322 | ] 323 | 324 | [[package]] 325 | name = "pyo3-macros-backend" 326 | version = "0.19.2" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536" 329 | dependencies = [ 330 | "proc-macro2", 331 | "quote", 332 | "syn 1.0.109", 333 | ] 334 | 335 | [[package]] 336 | name = "quick-xml" 337 | version = "0.29.0" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" 340 | dependencies = [ 341 | "memchr", 342 | ] 343 | 344 | [[package]] 345 | name = "quote" 346 | version = "1.0.33" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 349 | dependencies = [ 350 | "proc-macro2", 351 | ] 352 | 353 | [[package]] 354 | name = "redox_syscall" 355 | version = "0.3.5" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 358 | dependencies = [ 359 | "bitflags", 360 | ] 361 | 362 | [[package]] 363 | name = "ring" 364 | version = "0.16.20" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 367 | dependencies = [ 368 | "cc", 369 | "libc", 370 | "once_cell", 371 | "spin", 372 | "untrusted", 373 | "web-sys", 374 | "winapi", 375 | ] 376 | 377 | [[package]] 378 | name = "rustls" 379 | version = "0.21.7" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" 382 | dependencies = [ 383 | "log", 384 | "ring", 385 | "rustls-webpki 0.101.6", 386 | "sct", 387 | ] 388 | 389 | [[package]] 390 | name = "rustls-webpki" 391 | version = "0.100.3" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" 394 | dependencies = [ 395 | "ring", 396 | "untrusted", 397 | ] 398 | 399 | [[package]] 400 | name = "rustls-webpki" 401 | version = "0.101.6" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" 404 | dependencies = [ 405 | "ring", 406 | "untrusted", 407 | ] 408 | 409 | [[package]] 410 | name = "ryu" 411 | version = "1.0.15" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 414 | 415 | [[package]] 416 | name = "safemem" 417 | version = "0.3.3" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" 420 | 421 | [[package]] 422 | name = "scopeguard" 423 | version = "1.2.0" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 426 | 427 | [[package]] 428 | name = "sct" 429 | version = "0.7.0" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 432 | dependencies = [ 433 | "ring", 434 | "untrusted", 435 | ] 436 | 437 | [[package]] 438 | name = "serde" 439 | version = "1.0.188" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" 442 | dependencies = [ 443 | "serde_derive", 444 | ] 445 | 446 | [[package]] 447 | name = "serde_derive" 448 | version = "1.0.188" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" 451 | dependencies = [ 452 | "proc-macro2", 453 | "quote", 454 | "syn 2.0.37", 455 | ] 456 | 457 | [[package]] 458 | name = "serde_json" 459 | version = "1.0.107" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" 462 | dependencies = [ 463 | "itoa", 464 | "ryu", 465 | "serde", 466 | ] 467 | 468 | [[package]] 469 | name = "smallvec" 470 | version = "1.11.1" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" 473 | 474 | [[package]] 475 | name = "spin" 476 | version = "0.5.2" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 479 | 480 | [[package]] 481 | name = "syn" 482 | version = "1.0.109" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 485 | dependencies = [ 486 | "proc-macro2", 487 | "quote", 488 | "unicode-ident", 489 | ] 490 | 491 | [[package]] 492 | name = "syn" 493 | version = "2.0.37" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" 496 | dependencies = [ 497 | "proc-macro2", 498 | "quote", 499 | "unicode-ident", 500 | ] 501 | 502 | [[package]] 503 | name = "target-lexicon" 504 | version = "0.12.11" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" 507 | 508 | [[package]] 509 | name = "time" 510 | version = "0.3.29" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" 513 | dependencies = [ 514 | "deranged", 515 | "itoa", 516 | "serde", 517 | "time-core", 518 | "time-macros", 519 | ] 520 | 521 | [[package]] 522 | name = "time-core" 523 | version = "0.1.2" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 526 | 527 | [[package]] 528 | name = "time-macros" 529 | version = "0.2.15" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" 532 | dependencies = [ 533 | "time-core", 534 | ] 535 | 536 | [[package]] 537 | name = "tinyvec" 538 | version = "1.6.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 541 | dependencies = [ 542 | "tinyvec_macros", 543 | ] 544 | 545 | [[package]] 546 | name = "tinyvec_macros" 547 | version = "0.1.1" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 550 | 551 | [[package]] 552 | name = "unicode-bidi" 553 | version = "0.3.13" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 556 | 557 | [[package]] 558 | name = "unicode-ident" 559 | version = "1.0.12" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 562 | 563 | [[package]] 564 | name = "unicode-normalization" 565 | version = "0.1.22" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 568 | dependencies = [ 569 | "tinyvec", 570 | ] 571 | 572 | [[package]] 573 | name = "unindent" 574 | version = "0.1.11" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" 577 | 578 | [[package]] 579 | name = "untrusted" 580 | version = "0.7.1" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 583 | 584 | [[package]] 585 | name = "ureq" 586 | version = "2.7.1" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" 589 | dependencies = [ 590 | "base64", 591 | "flate2", 592 | "log", 593 | "once_cell", 594 | "rustls", 595 | "rustls-webpki 0.100.3", 596 | "url", 597 | "webpki-roots", 598 | ] 599 | 600 | [[package]] 601 | name = "url" 602 | version = "2.4.1" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" 605 | dependencies = [ 606 | "form_urlencoded", 607 | "idna", 608 | "percent-encoding", 609 | ] 610 | 611 | [[package]] 612 | name = "wasm-bindgen" 613 | version = "0.2.87" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" 616 | dependencies = [ 617 | "cfg-if", 618 | "wasm-bindgen-macro", 619 | ] 620 | 621 | [[package]] 622 | name = "wasm-bindgen-backend" 623 | version = "0.2.87" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" 626 | dependencies = [ 627 | "bumpalo", 628 | "log", 629 | "once_cell", 630 | "proc-macro2", 631 | "quote", 632 | "syn 2.0.37", 633 | "wasm-bindgen-shared", 634 | ] 635 | 636 | [[package]] 637 | name = "wasm-bindgen-macro" 638 | version = "0.2.87" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" 641 | dependencies = [ 642 | "quote", 643 | "wasm-bindgen-macro-support", 644 | ] 645 | 646 | [[package]] 647 | name = "wasm-bindgen-macro-support" 648 | version = "0.2.87" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" 651 | dependencies = [ 652 | "proc-macro2", 653 | "quote", 654 | "syn 2.0.37", 655 | "wasm-bindgen-backend", 656 | "wasm-bindgen-shared", 657 | ] 658 | 659 | [[package]] 660 | name = "wasm-bindgen-shared" 661 | version = "0.2.87" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" 664 | 665 | [[package]] 666 | name = "web-sys" 667 | version = "0.3.64" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" 670 | dependencies = [ 671 | "js-sys", 672 | "wasm-bindgen", 673 | ] 674 | 675 | [[package]] 676 | name = "webpki-roots" 677 | version = "0.23.1" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" 680 | dependencies = [ 681 | "rustls-webpki 0.100.3", 682 | ] 683 | 684 | [[package]] 685 | name = "winapi" 686 | version = "0.3.9" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 689 | dependencies = [ 690 | "winapi-i686-pc-windows-gnu", 691 | "winapi-x86_64-pc-windows-gnu", 692 | ] 693 | 694 | [[package]] 695 | name = "winapi-i686-pc-windows-gnu" 696 | version = "0.4.0" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 699 | 700 | [[package]] 701 | name = "winapi-x86_64-pc-windows-gnu" 702 | version = "0.4.0" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 705 | 706 | [[package]] 707 | name = "windows-targets" 708 | version = "0.48.5" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 711 | dependencies = [ 712 | "windows_aarch64_gnullvm", 713 | "windows_aarch64_msvc", 714 | "windows_i686_gnu", 715 | "windows_i686_msvc", 716 | "windows_x86_64_gnu", 717 | "windows_x86_64_gnullvm", 718 | "windows_x86_64_msvc", 719 | ] 720 | 721 | [[package]] 722 | name = "windows_aarch64_gnullvm" 723 | version = "0.48.5" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 726 | 727 | [[package]] 728 | name = "windows_aarch64_msvc" 729 | version = "0.48.5" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 732 | 733 | [[package]] 734 | name = "windows_i686_gnu" 735 | version = "0.48.5" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 738 | 739 | [[package]] 740 | name = "windows_i686_msvc" 741 | version = "0.48.5" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 744 | 745 | [[package]] 746 | name = "windows_x86_64_gnu" 747 | version = "0.48.5" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 750 | 751 | [[package]] 752 | name = "windows_x86_64_gnullvm" 753 | version = "0.48.5" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 756 | 757 | [[package]] 758 | name = "windows_x86_64_msvc" 759 | version = "0.48.5" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 762 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "apple-auth-utils", 4 | "apple-auth-py" 5 | ] 6 | 7 | [workspace.dependencies] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **WIP** 2 | 3 | # Description 4 | 5 | The following projects contain wrapper functions around apple-gen for: 6 | 1) Generating validation data 7 | 2) Encryption of io platform variables / IOPower variables 8 | 3) Generating anisette data (TBD) 9 | 10 | There is also a native python module to give access to the rust library through PYO3, which builds wheels for your desired python version with maturin. 11 | 12 | apple-auth-utils requires [apple-gen](https://github.com/Smoothstep/apple-gen) to build correctly. 13 | 14 | # Instructions 15 | 16 | clone the repo and make sure to pull the submodules 17 | 18 | `git clone --recursive https://github.com/Smoothstep/apple-gen-rs.git` 19 | 20 | To build python wheels, maturin is needed: 21 | 22 | `pip install maturin` 23 | 24 | cd into apple-auth-py and execute the command (README). 25 | 26 | # Status 27 | 28 | This is only an early implementation, thus most code is subject to change. 29 | For more information, refer to the apple-gen repository. 30 | 31 | # Hints 32 | 33 | Apple ID service & validation data: 34 | 35 | - When registering with different machine data, it's adviced to not change the product name from your initial device as it could trigger an automatic block. 36 | - For most variables, there are no validation checks, making it possible to use random inputs. 37 | 38 | Only few inputs have been tested so far. 39 | 40 | ## Generating validation data in Python 41 | 42 | Once the wheels are built with maturin and installed with pip (pip install [wheels] --force-reinstall), you should be able to call into the stub like so: 43 | 44 | ``` 45 | # Import necessary libraries 46 | import uuid 47 | import string 48 | import random 49 | import json 50 | import apple_auth 51 | 52 | # Function to generate a random UUID 53 | def gen_uuid(): 54 | random_uuid = uuid.uuid4() 55 | uuid_str = str(random_uuid).upper() 56 | return uuid_str 57 | 58 | # Valid characters for generating serial 59 | characters = string.ascii_uppercase + string.digits 60 | 61 | # Function to generate validation data 62 | def get_validation_data(): 63 | # Generate random MAC address 64 | mac = [0x5c, 0xf7, random.randrange(0, 255), 0x00, 0x00, 0x0f] 65 | # Generate random UUIDs for boot and platform 66 | boot = gen_uuid() 67 | platform = gen_uuid() 68 | # Generate random serial number 69 | serial = "C02" + ''.join(random.choice(characters) for _ in range(5)) + "JK7M" 70 | # Generate random ROM address 71 | rom = [0x57, 0xD0, random.randrange(0, 255), 0x9D, 0xD6, 0x86] 72 | # Generate random MLB (Main Logic Board) serial 73 | mlb = "".join([random.choice(characters) for _ in range(17)]) 74 | # Information dictionary 75 | info = { 76 | "rom": "".join(hex(c)[2:].zfill(2) for c in rom), 77 | "board_id": "Mac-27AD2F918AE68F65", 78 | "product_name": "MacPro7,1", 79 | "mac": ":".join(hex(c)[2:].zfill(2) for c in mac), 80 | "platform_serial": serial, 81 | "mlb": mlb, 82 | "root_disk_uuid": boot, 83 | "platform_uuid": platform 84 | } 85 | # Request validation data from apple_auth module and return it as bytes 86 | return bytes(apple_auth.IDS(json.dumps(info)).request_validation_data()) 87 | ``` 88 | -------------------------------------------------------------------------------- /apple-auth-py/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "apple-auth-py" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | name = "apple_auth" 8 | path = "src/lib.rs" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies.apple-auth-utils] 12 | path = "../apple-auth-utils" 13 | 14 | [dependencies] 15 | pyo3 = { version = "0.19", features = ["extension-module"] } -------------------------------------------------------------------------------- /apple-auth-py/README.md: -------------------------------------------------------------------------------- 1 | # Build steps 2 | 3 | To build wheels (pyd module) execute: 4 | *maturin build -i [YOUR_PYTHON_VERSION]* -------------------------------------------------------------------------------- /apple-auth-py/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::{pymodule, Python, types::PyModule, PyResult, pyclass, pymethods, PyRef}; 2 | 3 | extern crate pyo3; 4 | 5 | #[pyclass] 6 | struct IDS { 7 | validator: apple_auth_utils::IDSValidator 8 | } 9 | 10 | #[pymethods] 11 | impl IDS { 12 | #[new] 13 | fn new(js: &str, cert: Option>) -> PyResult { 14 | match apple_auth_utils::IDSValidator::from_json(js, cert) { 15 | Err(err) => Err(pyo3::exceptions::PyRuntimeError::new_err(std::format!("{}", err))), 16 | Ok(validator) => Ok(Self { 17 | validator 18 | }) 19 | } 20 | } 21 | 22 | fn request_validation_data(self_: PyRef<'_, Self>) -> PyResult> { 23 | let validator = &self_.validator; 24 | 25 | self_.py().allow_threads(move || -> PyResult> { 26 | match validator.request_validation_data() { 27 | Err(err) => Err(pyo3::exceptions::PyRuntimeError::new_err(std::format!("{}", err))), 28 | Ok(data) => Ok(data) 29 | }}) 30 | } 31 | 32 | fn encrypt_io_data(self_: PyRef<'_, Self>, data: &[u8]) -> PyResult> { 33 | self_.py().allow_threads(move || -> PyResult> { 34 | match apple_auth_utils::IDSValidator::encrypt_value(data) { 35 | Err(err) => Err(pyo3::exceptions::PyRuntimeError::new_err(std::format!("{}", err))), 36 | Ok(data) => Ok(data) 37 | }}) 38 | } 39 | } 40 | 41 | #[pymodule] 42 | fn apple_auth(_py: Python, m: &PyModule) -> PyResult<()> { 43 | m.add_class::()?; 44 | Ok(()) 45 | } 46 | 47 | #[cfg(test)] 48 | mod tests { 49 | use pyo3::{types::PyModule, PyCell, py_run}; 50 | 51 | #[test] 52 | fn test_ids() { 53 | pyo3::prepare_freethreaded_python(); 54 | 55 | pyo3::marker::Python::with_gil(|py| { 56 | let module = PyModule::new(py, "apple_auth").unwrap(); 57 | crate::apple_auth(py, &module).unwrap(); 58 | 59 | let sample_data = r#"{ 60 | "rom": "0C66833E0010", 61 | "board_id": "Mac-27AD2F918AE68F65", 62 | "product_name": "MacPro7,1", 63 | "mac": "5C:F7:FF:00:00:0F", 64 | "platform_serial": "F5KGCVYKP7QM", 65 | "mlb": "F5K925600QXFHDD1M", 66 | "root_disk_uuid": "6015372F-2EA0-4634-B85D-AEFB9E03DF00", 67 | "platform_uuid": "564D3AEF-EAF0-868D-B8B2-623A10E88A26" 68 | }"#; 69 | 70 | let ids = crate::IDS::new(sample_data, None).expect("Failed to construct ids"); 71 | let ids = PyCell::new(py, ids).expect("Failed to create PyCell from IDS"); 72 | 73 | py_run!(py, ids, r#"assert len(ids.request_validation_data()) >= 389"#); 74 | }); 75 | } 76 | } -------------------------------------------------------------------------------- /apple-auth-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "apple-auth-utils" 3 | version = "0.1.0" 4 | edition = "2021" 5 | build = "build.rs" 6 | 7 | [lib] 8 | name = "apple_auth_utils" 9 | 10 | [build-dependencies] 11 | cmake = "0.1" 12 | cc = "1.0" 13 | 14 | [dependencies] 15 | libc = "0.2" 16 | plist = "1.5" 17 | ureq = "2.7" 18 | rustls = { version = "0.21", features = ["dangerous_configuration"] } 19 | serde = { version = "1", features = ["derive"] } 20 | serde_json = "1" -------------------------------------------------------------------------------- /apple-auth-utils/build.rs: -------------------------------------------------------------------------------- 1 | use std::{path}; 2 | 3 | extern crate cc; 4 | extern crate cmake; 5 | use cmake::Config; 6 | 7 | fn main() { 8 | let mut config = Config::new(path::Path::new("apple_crypto")); 9 | 10 | #[cfg(target_os = "windows")] 11 | { 12 | config.generator_toolset("ClangCL"); 13 | } 14 | 15 | config.very_verbose(true).build(); 16 | 17 | let cargo_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); 18 | let out_dir = std::env::var("OUT_DIR").unwrap(); 19 | 20 | println!("cargo:rustc-link-search={}", path::Path::new(&cargo_dir).join("../").display()); 21 | println!("cargo:rustc-link-search={}", path::Path::new(&out_dir).display()); 22 | println!("cargo:rustc-link-search=."); 23 | 24 | 25 | //println!("cargo:rustc-link-lib=apple_crypto"); 26 | //println!("cargo:rustc-link-lib=apple_crypto"); 27 | 28 | println!("cargo:rustc-link-lib=static=apple_crypto"); 29 | 30 | #[cfg(target_os = "linux")] 31 | { 32 | println!("cargo:rustc-link-lib=stdc++"); 33 | } 34 | } -------------------------------------------------------------------------------- /apple-auth-utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate libc; 2 | extern crate plist; 3 | extern crate serde; 4 | extern crate serde_json; 5 | 6 | mod requests; 7 | 8 | use std::ffi::CString; 9 | use std::fmt::Debug; 10 | use serde::{Deserialize, Serialize}; 11 | 12 | macro_rules! wrap_call { 13 | ($n:ident($($p:ident: $t:ty),*)) => { 14 | #[link(name = "apple_crypto", kind = "static")] 15 | extern "C" { 16 | fn $n($($p: $t),*) -> NacError; 17 | } 18 | 19 | pub mod $n { 20 | use super::*; 21 | 22 | pub fn call($($p: $t),*) -> Result<(), super::NacError> { 23 | let err = unsafe { 24 | super::$n($($p),*) 25 | }; 26 | if err != super::NacError::NacNoError { 27 | Err(err) 28 | } 29 | else { 30 | Ok(()) 31 | } 32 | } 33 | } 34 | }; 35 | } 36 | 37 | pub mod external { 38 | use std::ops::{DerefMut, Deref}; 39 | 40 | use serde::{Deserialize, Serialize}; 41 | 42 | mod serde_str_array { 43 | use serde::{Deserialize, Serializer, Deserializer}; 44 | 45 | pub fn serialize(t: &[i8; N], serializer: S) -> Result 46 | where 47 | S: Serializer 48 | { 49 | unsafe { 50 | let unsigned: &[u8; N] = std::mem::transmute(t); 51 | 52 | let ser_tuple = serializer.serialize_str( 53 | &String::from_utf8_lossy(unsigned)[0..unsigned.iter().position(|&x| x == 0u8).unwrap_or(N)]); 54 | ser_tuple 55 | } 56 | } 57 | 58 | pub fn deserialize<'de, const N: usize, S>(deserializer: S) -> Result<[i8; N], S::Error> 59 | where 60 | S: Deserializer<'de> 61 | { 62 | let ser_tuple = String::deserialize(deserializer)?; 63 | 64 | unsafe { 65 | let mut result: [i8; N] = [Default::default(); N]; 66 | 67 | let slice = ser_tuple.as_bytes(); 68 | let signed: &[i8] = std::mem::transmute(slice); 69 | let len = std::cmp::min(signed.len(), N); 70 | 71 | result[..len].copy_from_slice(&signed[..len]); 72 | 73 | Ok(result) 74 | } 75 | } 76 | } 77 | 78 | pub const REQUEST_LEN: usize = 338; 79 | pub const CERTIFICATE_LEN: usize = 2385; 80 | pub const SESSION_DATA_LEN: usize = 698; 81 | pub const VALIDATION_CTX_LEN: usize = 824; 82 | 83 | #[repr(C)] 84 | #[derive(Serialize, Deserialize, Clone, Copy, PartialEq)] 85 | pub struct MachineInfo 86 | { 87 | #[serde(with = "serde_str_array")] 88 | pub board_id: [i8; 64], 89 | 90 | // boot uuid [uuid4] 91 | #[serde(with = "serde_str_array")] 92 | pub root_disk_uuid: [i8; 38], 93 | 94 | // product name [MacPro7,1] 95 | #[serde(with = "serde_str_array")] 96 | pub product_name: [i8; 64], 97 | 98 | // platform serial [uuid4] 99 | #[serde(with = "serde_str_array")] 100 | pub platform_serial: [i8; 38], 101 | 102 | // platform uuid [uuid4] 103 | #[serde(with = "serde_str_array")] 104 | pub platform_uuid: [i8; 38], 105 | 106 | // mlb [C02923200KVKN3YAG] 107 | #[serde(with = "serde_str_array")] 108 | pub mlb: [i8; 64], 109 | 110 | // rom bytes 111 | pub rom: [u8; 6], 112 | 113 | // mac address bytes 114 | pub mac: [u8; 6], 115 | 116 | // Optional Gq3489ugfi 117 | pub platform_serial_encrypted: [u8; 17], 118 | 119 | // Optional Fyp98tpgj 120 | pub platform_uuid_encrypted: [u8; 17], 121 | 122 | // Optional kbjfrfpoJU 123 | pub root_disk_uuid_encrypted: [u8; 17], 124 | 125 | // Optional oycqAZloTNDm 126 | pub rom_encrypted: [u8; 17], 127 | 128 | // Optional abKPld1EcMni 129 | pub mlb_encrypted: [u8; 17], 130 | } 131 | 132 | #[repr(C)] 133 | #[derive(PartialEq, Debug)] 134 | pub enum NacError 135 | { 136 | NacNoError = 0, 137 | NacInvalidParameter = 1, 138 | NacInitError = 2, 139 | NacRequestError = 3, 140 | NacSignError = 4, 141 | NacEncryptError = 5 142 | } 143 | 144 | #[repr(C)] 145 | pub struct ValidationContext(pub [u8; VALIDATION_CTX_LEN]); 146 | 147 | #[repr(C)] 148 | pub struct ValidationContextPtr(*mut ValidationContext); 149 | 150 | impl Deref for ValidationContextPtr { 151 | type Target = ValidationContext; 152 | 153 | fn deref(&self) -> &Self::Target { 154 | unsafe { 155 | &*self.0 156 | } 157 | } 158 | } 159 | 160 | impl DerefMut for ValidationContextPtr { 161 | fn deref_mut(&mut self) -> &mut Self::Target { 162 | unsafe { 163 | &mut *self.0 164 | } 165 | } 166 | } 167 | 168 | impl Default for ValidationContextPtr { 169 | fn default() -> Self { 170 | Self(std::ptr::null_mut()) 171 | } 172 | } 173 | 174 | #[repr(C)] 175 | pub struct ValidationRequest(pub *mut u8); 176 | 177 | impl Default for ValidationRequest { 178 | fn default() -> Self { 179 | Self(std::ptr::null_mut()) 180 | } 181 | } 182 | 183 | #[repr(C)] 184 | pub struct SessionData(pub [u8; SESSION_DATA_LEN]); 185 | 186 | #[repr(C)] 187 | pub struct ValidationSignature(pub *mut u8); 188 | 189 | impl Default for ValidationSignature { 190 | fn default() -> Self { 191 | Self(std::ptr::null_mut()) 192 | } 193 | } 194 | 195 | #[repr(C)] 196 | pub struct ValidationCert(pub [u8; CERTIFICATE_LEN]); 197 | 198 | wrap_call!(build_machine_info( 199 | board_id: *const i8, 200 | root_disk_uuid: *const i8, 201 | product_name: *const i8, 202 | platform_serial: *const i8, 203 | platform_uuid: *const i8, 204 | mlb: *const i8, 205 | rom: *const i8, 206 | mac: *const i8, 207 | info: *mut MachineInfo 208 | )); 209 | 210 | wrap_call!(encrypt_io_data( 211 | data: *const u8, 212 | size: u32, 213 | output: *mut u8)); 214 | 215 | wrap_call!(init_nac_request( 216 | cert: *const ValidationCert, 217 | machine_info: *const MachineInfo, 218 | out_context: *mut ValidationContextPtr, 219 | out_request: *mut ValidationRequest 220 | )); 221 | 222 | wrap_call!(sign_nac_request( 223 | context: *mut ValidationContext, 224 | session: *const SessionData, 225 | out_validation: *mut ValidationSignature, 226 | out_validation_length: *mut usize 227 | )); 228 | 229 | wrap_call!(free_nac( 230 | context: *mut ValidationContext 231 | )); 232 | 233 | wrap_call!(free_data( 234 | context: *mut u8 235 | )); 236 | 237 | impl Drop for ValidationContextPtr { 238 | fn drop(&mut self) { 239 | free_nac::call(self.0).expect("Failed to free NAC"); 240 | } 241 | } 242 | 243 | impl Drop for ValidationRequest { 244 | fn drop(&mut self) { 245 | unsafe { 246 | free_data(self.0); 247 | } 248 | } 249 | } 250 | 251 | impl Drop for ValidationSignature { 252 | fn drop(&mut self) { 253 | unsafe { 254 | free_data(self.0); 255 | } 256 | } 257 | } 258 | } 259 | 260 | use external::*; 261 | 262 | #[derive(Serialize, Deserialize)] 263 | pub struct RequiredSystemFields { 264 | board_id: CString, 265 | root_disk_uuid: CString, 266 | product_name: CString, 267 | platform_serial: CString, 268 | platform_uuid: CString, 269 | mlb: CString, 270 | rom: CString, 271 | mac: CString, 272 | } 273 | 274 | pub struct FieldLengthError { 275 | field: &'static str, 276 | length: usize 277 | } 278 | 279 | macro_rules! check_len_valid { 280 | ($self:ident, $x:ident, $max_len:literal) => { 281 | if $self.$x.as_bytes().len() == 0 || $self.$x.as_bytes().len() >= $max_len { 282 | return Some(FieldLengthError{ 283 | field: stringify!($x), 284 | length: $self.$x.as_bytes().len() 285 | }) 286 | } 287 | }; 288 | } 289 | 290 | impl RequiredSystemFields { 291 | pub fn check_error(&self) -> Option { 292 | check_len_valid!(self, board_id, 64); 293 | check_len_valid!(self, root_disk_uuid, 64); 294 | check_len_valid!(self, product_name, 64); 295 | check_len_valid!(self, platform_serial, 38); 296 | check_len_valid!(self, platform_uuid, 38); 297 | check_len_valid!(self, mlb, 38); 298 | check_len_valid!(self, rom, 64); 299 | check_len_valid!(self, mac, 64); 300 | 301 | return None; 302 | } 303 | } 304 | 305 | pub struct IDSValidator { 306 | machine_info: external::MachineInfo, 307 | cert: external::ValidationCert 308 | } 309 | 310 | pub enum IDSErrorType { 311 | NoError, 312 | InvalidJsonField(FieldLengthError), 313 | RequestError(requests::RequestError), 314 | NacError(NacError), 315 | InvalidSession, 316 | InvalidJson(serde_json::Error) 317 | } 318 | 319 | pub struct IDSError { 320 | kind: IDSErrorType 321 | } 322 | 323 | impl std::fmt::Display for IDSError { 324 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 325 | ::fmt(&self, f) 326 | } 327 | } 328 | 329 | impl Debug for IDSError { 330 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 331 | match &self.kind { 332 | IDSErrorType::NoError => { 333 | f.write_str("No error") 334 | }, 335 | IDSErrorType::InvalidSession => { 336 | f.write_str("Session length invalid") 337 | }, 338 | IDSErrorType::InvalidJson(err) => { 339 | f.write_fmt(format_args!("Json error: {:?}", err)) 340 | }, 341 | IDSErrorType::RequestError(err) => { 342 | f.write_fmt(format_args!("Request error: {:?}", err)) 343 | }, 344 | IDSErrorType::NacError(err) => { 345 | f.write_fmt(format_args!("Nac error: {:?}", err)) 346 | }, 347 | IDSErrorType::InvalidJsonField(err) => { 348 | f.write_fmt(format_args!("Json error: Json field {} has invalid length: {}", err.field, err.length)) 349 | } 350 | } 351 | } 352 | } 353 | 354 | impl IDSError { 355 | fn new(kind: IDSErrorType) -> Self { 356 | Self { kind } 357 | } 358 | } 359 | 360 | impl From for IDSError { 361 | fn from(value: requests::RequestError) -> Self { 362 | Self { 363 | kind: IDSErrorType::RequestError(value) 364 | } 365 | } 366 | } 367 | 368 | impl From for IDSError { 369 | fn from(value: serde_json::Error) -> Self { 370 | Self { 371 | kind: IDSErrorType::InvalidJson(value) 372 | } 373 | } 374 | } 375 | 376 | impl From for IDSError { 377 | fn from(value: NacError) -> Self { 378 | Self { 379 | kind: IDSErrorType::NacError(value) 380 | } 381 | } 382 | } 383 | 384 | impl IDSValidator { 385 | pub fn from_json(js: &str, cert: Option>) -> Result { 386 | let info: RequiredSystemFields = serde_json::from_str(js)?; 387 | Self::from_required_fields(&info, cert) 388 | } 389 | 390 | pub fn get_json(&self) -> Result { 391 | Ok(serde_json::to_string(&self.machine_info)?) 392 | } 393 | 394 | pub fn get_machine_info(&self) -> MachineInfo { 395 | self.machine_info 396 | } 397 | 398 | pub fn from_required_fields(info: &RequiredSystemFields, cert: Option>) -> Result { 399 | if let Some(e) = info.check_error() { 400 | return Err(IDSError::new(IDSErrorType::InvalidJsonField(e))); 401 | } 402 | 403 | Ok(Self { 404 | machine_info: Self::create_machine_info(info)?, 405 | cert: ValidationCert(cert.ok_or(IDSError::new(IDSErrorType::NoError)) 406 | .or_else(|_| requests::IDSRequests::request_certificate())? 407 | .try_into().expect("Invalid cert size")) 408 | }) 409 | } 410 | 411 | pub fn from_system_info(info: MachineInfo, cert: Option>) -> Result { 412 | Ok(Self { 413 | machine_info: info, 414 | cert: ValidationCert(cert.ok_or(IDSError::new(IDSErrorType::NoError)) 415 | .or_else(|_| requests::IDSRequests::request_certificate())? 416 | .try_into().expect("Invalid cert size")) 417 | }) 418 | } 419 | 420 | pub fn request_validation_data(&self) -> Result, IDSError> { 421 | unsafe { 422 | let mut context = ValidationContextPtr::default(); 423 | let mut request = ValidationRequest::default(); 424 | 425 | init_nac_request::call( 426 | &self.cert, 427 | &self.machine_info, 428 | &mut context, 429 | &mut request)?; 430 | 431 | let session_data = requests::IDSRequests::request_session( 432 | std::slice::from_raw_parts(request.0, REQUEST_LEN).to_vec())?; 433 | 434 | if session_data.len() != SESSION_DATA_LEN { 435 | return Err(IDSError{ kind: IDSErrorType::InvalidSession }); 436 | } 437 | 438 | let session_data = SessionData(session_data.try_into().unwrap()); 439 | 440 | let mut validation_sig = ValidationSignature::default(); 441 | let mut validation_len = 0usize; 442 | 443 | sign_nac_request::call( 444 | &mut *context, 445 | &session_data, 446 | &mut validation_sig, 447 | &mut validation_len)?; 448 | 449 | let data = std::slice::from_raw_parts(validation_sig.0, validation_len); 450 | 451 | Ok(data.to_vec()) 452 | } 453 | } 454 | 455 | pub fn encrypt_value>(value: T) -> Result, IDSError> { 456 | let slice = value.as_ref(); 457 | let mut output: [u8; 17] = [0u8; 17]; 458 | encrypt_io_data::call(slice.as_ptr(), slice.len() as u32, output.as_mut_ptr())?; 459 | Ok(output.to_vec()) 460 | } 461 | 462 | fn create_machine_info(info: &RequiredSystemFields) -> Result { 463 | unsafe { 464 | let mut machine = std::mem::zeroed::(); 465 | 466 | build_machine_info::call( 467 | info.board_id.as_ptr(), 468 | info.root_disk_uuid.as_ptr(), 469 | info.product_name.as_ptr(), 470 | info.platform_serial.as_ptr(), 471 | info.platform_uuid.as_ptr(), 472 | info.mlb.as_ptr(), 473 | info.rom.as_ptr(), 474 | info.mac.as_ptr(), 475 | &mut machine).map(|_| machine) 476 | } 477 | } 478 | } 479 | 480 | #[cfg(test)] 481 | mod tests { 482 | use crate::external::*; 483 | use crate::*; 484 | 485 | #[test] 486 | fn test_ids() { 487 | let sample_data = r#"{ 488 | "rom": "0C66833E0010", 489 | "board_id": "Mac-27AD2F918AE68F65", 490 | "product_name": "MacPro7,1", 491 | "mac": "5C:F7:FF:00:00:0F", 492 | "platform_serial": "F5KGCVYKP7QM", 493 | "mlb": "F5K925600QXFHDD1M", 494 | "root_disk_uuid": "6015372F-2EA0-4634-B85D-AEFB9E03DF00", 495 | "platform_uuid": "564D3AEF-EAF0-868D-B8B2-623A10E88A26" 496 | }"#; 497 | let ids = crate::IDSValidator::from_json(sample_data, None).expect("Failed to create ids"); 498 | let validation_data = ids.request_validation_data().expect("Failed to obtain validation data"); 499 | assert!(validation_data.len() >= 389); 500 | 501 | let js = ids.get_json().expect("Failed to obtain machine info json"); 502 | let obj: MachineInfo = serde_json::from_str(&js).expect("Failed to parse json into machine info"); 503 | assert!(obj == ids.get_machine_info()); 504 | } 505 | 506 | #[test] 507 | fn test_validation() { 508 | unsafe { 509 | let mut machine = std::mem::zeroed::(); 510 | let rom = CString::new("0C66833E0010").unwrap(); 511 | let board_id = CString::new("Mac-27AD2F918AE68F65").unwrap(); 512 | let product_name = CString::new("MacPro7,1").unwrap(); 513 | let mac = CString::new("5C:F7:FF:00:00:0F").unwrap(); 514 | let io_platform_serial = CString::new("F5KGCVYKP7QM").unwrap(); 515 | let mlb = CString::new("F5K925600QXFHDD1M").unwrap(); 516 | let root_disk_uuid = CString::new("6015372F-2EA0-4634-B85D-AEFB9E03DF00").unwrap(); 517 | let io_platform_uuid = CString::new("564D3AEF-EAF0-868D-B8B2-623A10E88A26").unwrap(); 518 | 519 | build_machine_info::call( 520 | board_id.as_ptr(), 521 | root_disk_uuid.as_ptr(), 522 | product_name.as_ptr(), 523 | io_platform_serial.as_ptr(), 524 | io_platform_uuid.as_ptr(), 525 | mlb.as_ptr(), 526 | rom.as_ptr(), 527 | mac.as_ptr(), 528 | &mut machine).expect("Failed to build machine info"); 529 | 530 | let cert = ValidationCert(requests::IDSRequests::request_certificate() 531 | .expect("Failed to request certificate").try_into() 532 | .expect("Invalid cert size")); 533 | 534 | let mut context = ValidationContextPtr::default(); 535 | let mut request = ValidationRequest::default(); 536 | 537 | init_nac_request::call(&cert, &machine, &mut context, &mut request) 538 | .expect("Failed to init nac"); 539 | 540 | let session_data = SessionData(requests::IDSRequests::request_session( 541 | std::slice::from_raw_parts(request.0, 338).to_vec()) 542 | .expect("Failed to request session data").try_into() 543 | .expect("Invalid session size")); 544 | 545 | let mut validation_sig = ValidationSignature::default(); 546 | let mut validation_len = 0usize; 547 | 548 | sign_nac_request::call(&mut *context, &session_data, &mut validation_sig, &mut validation_len) 549 | .expect("Failed to sign validation data"); 550 | 551 | let data = std::slice::from_raw_parts(validation_sig.0, validation_len); 552 | assert!(data.len() >= 389); 553 | } 554 | } 555 | 556 | #[test] 557 | fn gen_machine() { 558 | unsafe { 559 | let mut machine = std::mem::zeroed::(); 560 | let rom = CString::new("0C66833E0010").unwrap(); 561 | let board_id = CString::new("Mac-27AD2F918AE68F65").unwrap(); 562 | let product_name = CString::new("MacPro7,1").unwrap(); 563 | let mac = CString::new("5C:F7:FF:00:00:0F").unwrap(); 564 | let io_platform_serial = CString::new("F5KGCVYKP7QM").unwrap(); 565 | let mlb = CString::new("F5K925600QXFHDD1M").unwrap(); 566 | let root_disk_uuid = CString::new("6015372F-2EA0-4634-B85D-AEFB9E03DF00").unwrap(); 567 | let io_platform_uuid = CString::new("564D3AEF-EAF0-868D-B8B2-623A10E88A26").unwrap(); 568 | 569 | build_machine_info::call( 570 | board_id.as_ptr(), 571 | root_disk_uuid.as_ptr(), 572 | product_name.as_ptr(), 573 | io_platform_serial.as_ptr(), 574 | io_platform_uuid.as_ptr(), 575 | mlb.as_ptr(), 576 | rom.as_ptr(), 577 | mac.as_ptr(), 578 | &mut machine).expect("Failed to build machine info"); 579 | } 580 | } 581 | } 582 | -------------------------------------------------------------------------------- /apple-auth-utils/src/requests.rs: -------------------------------------------------------------------------------- 1 | use std::{sync::Arc, fmt::Display}; 2 | 3 | #[derive(Debug, Clone)] 4 | pub enum RequestErrorType { 5 | InvalidResponse { 6 | error_code: Option 7 | }, 8 | InvalidRead, 9 | InvalidPList, 10 | RequestError { 11 | code: u16 12 | } 13 | } 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct RequestError { 17 | kind: RequestErrorType 18 | } 19 | 20 | impl Display for RequestError { 21 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 22 | match &self.kind { 23 | RequestErrorType::InvalidResponse { error_code } => { 24 | f.write_str(&format!("Response returned error {}", error_code.unwrap_or_default())) 25 | }, 26 | RequestErrorType::InvalidPList => { 27 | f.write_str("Failed to parse plist") 28 | }, 29 | RequestErrorType::RequestError { code } => { 30 | f.write_str(&format!("Request error with code {}", code)) 31 | }, 32 | RequestErrorType::InvalidRead => { 33 | f.write_str("Failed to read response") 34 | } 35 | } 36 | } 37 | } 38 | 39 | impl From for RequestError { 40 | fn from(_: plist::Error) -> Self { 41 | Self { 42 | kind: RequestErrorType::InvalidPList 43 | } 44 | } 45 | } 46 | 47 | impl From for RequestError { 48 | fn from(_: std::io::Error) -> Self { 49 | Self { 50 | kind: RequestErrorType::InvalidRead 51 | } 52 | } 53 | } 54 | 55 | impl From for RequestError { 56 | fn from(error: ureq::Error) -> Self { 57 | Self { 58 | kind: RequestErrorType::RequestError{ 59 | code: error.into_response().map_or(0, |r| r.status()) 60 | } 61 | } 62 | } 63 | } 64 | 65 | fn get_rustls_config_dangerous() -> Result { 66 | let mut config = rustls::ClientConfig::builder() 67 | .with_safe_defaults() 68 | .with_root_certificates(rustls::RootCertStore::empty()) 69 | .with_no_client_auth(); 70 | 71 | let mut dangerous_config = rustls::ClientConfig::dangerous(&mut config); 72 | dangerous_config.set_certificate_verifier(Arc::new(NoCertificateVerification {})); 73 | 74 | Ok(config) 75 | } 76 | 77 | struct NoCertificateVerification {} 78 | 79 | impl rustls::client::ServerCertVerifier for NoCertificateVerification { 80 | fn verify_server_cert( 81 | &self, 82 | _end_entity: &rustls::Certificate, 83 | _intermediates: &[rustls::Certificate], 84 | _server_name: &rustls::ServerName, 85 | _scts: &mut dyn Iterator, 86 | _ocsp: &[u8], 87 | _now: std::time::SystemTime, 88 | ) -> Result { 89 | Ok(rustls::client::ServerCertVerified::assertion()) 90 | } 91 | } 92 | 93 | pub struct IDSRequests; 94 | 95 | impl IDSRequests { 96 | pub fn request_session(request: Vec) -> Result, RequestError> { 97 | let pl = plist::from_value::(&plist::Value::Data(request))?; 98 | 99 | let mut dict = plist::Dictionary::new(); 100 | { 101 | dict.insert("session-info-request".into(), pl); 102 | } 103 | 104 | let mut bytes = Vec::::new(); 105 | { 106 | plist::to_writer_xml(std::io::BufWriter::new(&mut bytes), &dict)? 107 | } 108 | 109 | let agent = ureq::AgentBuilder::new().tls_config( 110 | Arc::new(get_rustls_config_dangerous().expect("Failed to build rustls config"))).build(); 111 | 112 | let mut reader = agent.post("https://identity.ess.apple.com/WebObjects/TDIdentityService.woa/wa/initializeValidation") 113 | .send_bytes(&bytes)?.into_reader(); 114 | 115 | let mut bytes = Vec::::new(); 116 | { 117 | reader.read_to_end(&mut bytes)?; 118 | } 119 | 120 | let dict = plist::from_bytes::(&bytes)?; 121 | 122 | match dict.get("session-info").and_then(|v| v.as_data()) { 123 | Some(bytes) => { 124 | Ok(bytes.to_vec()) 125 | }, 126 | None => { 127 | Err(RequestError { 128 | kind: RequestErrorType::InvalidResponse { 129 | error_code: dict.get("status").and_then(|s| s.as_unsigned_integer()) 130 | } 131 | }) 132 | } 133 | } 134 | } 135 | 136 | pub fn request_certificate() -> Result, RequestError> { 137 | let mut reader = ureq::get("http://static.ess.apple.com/identity/validation/cert-1.0.plist") 138 | .call()?.into_reader(); 139 | 140 | let mut bytes = Vec::::new(); 141 | { 142 | reader.read_to_end(&mut bytes)?; 143 | } 144 | 145 | let dict = plist::from_bytes::(&bytes)?; 146 | 147 | match dict.get("cert").and_then(|v| v.as_data()) { 148 | Some(bytes) => { 149 | Ok(bytes.to_vec()) 150 | }, 151 | None => { 152 | Err(RequestError { 153 | kind: RequestErrorType::InvalidResponse { 154 | error_code: dict.get("status").and_then(|s| s.as_unsigned_integer()) 155 | } 156 | }) 157 | } 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /sample_data/machine_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "rom": "0C66833E0010", 3 | "board_id": "Mac-27AD2F918AE68F65", 4 | "product_name": "MacPro7,1", 5 | "mac": "5C:F7:FF:00:00:0F", 6 | "platform_serial": "F5KGCVYKP7QM", 7 | "mlb": "F5K925600QXFHDD1M", 8 | "root_disk_uuid": "6015372F-2EA0-4634-B85D-AEFB9E03DF00", 9 | "platform_uuid": "564D3AEF-EAF0-868D-B8B2-623A10E88A26" 10 | } --------------------------------------------------------------------------------