bplist_parser.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  1. #include <inttypes.h>
  2. #include <string.h>
  3. #include "plist.h"
  4. // Binary plist object types (high nibble of marker byte)
  5. #define BPLIST_NULL 0x00
  6. #define BPLIST_BOOL 0x00
  7. #define BPLIST_INT 0x10
  8. #define BPLIST_REAL 0x20
  9. #define BPLIST_DATE 0x30
  10. #define BPLIST_DATA 0x40
  11. #define BPLIST_STRING 0x50
  12. #define BPLIST_UNICODE 0x60
  13. #define BPLIST_UID 0x80
  14. #define BPLIST_ARRAY 0xA0
  15. #define BPLIST_SET 0xC0
  16. #define BPLIST_DICT 0xD0
  17. static uint64_t read_be_int(const uint8_t *data, size_t bytes) {
  18. uint64_t val = 0;
  19. for (size_t i = 0; i < bytes; i++) {
  20. val = (val << 8) | data[i];
  21. }
  22. return val;
  23. }
  24. static bool bplist_parse_trailer(const uint8_t *plist, size_t plist_len,
  25. uint8_t *offset_size, uint8_t *ref_size,
  26. uint64_t *num_objects, uint64_t *top_object,
  27. uint64_t *offset_table_offset) {
  28. if (plist_len < 32) {
  29. return false;
  30. }
  31. const uint8_t *trailer = plist + plist_len - 32;
  32. *offset_size = trailer[6];
  33. *ref_size = trailer[7];
  34. *num_objects = read_be_int(trailer + 8, 8);
  35. *top_object = read_be_int(trailer + 16, 8);
  36. *offset_table_offset = read_be_int(trailer + 24, 8);
  37. return (*offset_size > 0 && *offset_size <= 8 && *ref_size > 0 &&
  38. *ref_size <= 8 && *offset_table_offset < plist_len);
  39. }
  40. static uint64_t bplist_get_offset(const uint8_t *plist,
  41. uint64_t offset_table_offset,
  42. uint8_t offset_size, uint64_t obj_idx) {
  43. const uint8_t *entry = plist + offset_table_offset + obj_idx * offset_size;
  44. return read_be_int(entry, offset_size);
  45. }
  46. static bool bplist_read_string(const uint8_t *plist, size_t plist_len,
  47. uint64_t offset, char *out,
  48. size_t out_capacity) {
  49. if (offset >= plist_len) {
  50. return false;
  51. }
  52. uint8_t marker = plist[offset];
  53. uint8_t type = marker & 0xF0;
  54. size_t len = marker & 0x0F;
  55. size_t pos = offset + 1;
  56. if (len == 0x0F) {
  57. if (pos >= plist_len) {
  58. return false;
  59. }
  60. uint8_t len_marker = plist[pos++];
  61. if ((len_marker & 0xF0) != BPLIST_INT) {
  62. return false;
  63. }
  64. size_t len_bytes = 1 << (len_marker & 0x0F);
  65. if (pos + len_bytes > plist_len) {
  66. return false;
  67. }
  68. len = (size_t)read_be_int(plist + pos, len_bytes);
  69. pos += len_bytes;
  70. }
  71. if (type == BPLIST_STRING) {
  72. if (pos + len > plist_len || len >= out_capacity) {
  73. return false;
  74. }
  75. memcpy(out, plist + pos, len);
  76. out[len] = '\0';
  77. return true;
  78. }
  79. if (type == BPLIST_UNICODE) {
  80. size_t bytes = len * 2;
  81. if (pos + bytes > plist_len || len >= out_capacity) {
  82. return false;
  83. }
  84. for (size_t i = 0; i < len; i++) {
  85. uint16_t code =
  86. (uint16_t)(plist[pos + i * 2] << 8) | plist[pos + i * 2 + 1];
  87. if (code > 0x7F) {
  88. return false;
  89. }
  90. out[i] = (char)code;
  91. }
  92. out[len] = '\0';
  93. return true;
  94. }
  95. return false;
  96. }
  97. static bool bplist_read_data(const uint8_t *plist, size_t plist_len,
  98. uint64_t offset, uint8_t *out, size_t out_capacity,
  99. size_t *out_len) {
  100. if (offset >= plist_len) {
  101. return false;
  102. }
  103. uint8_t marker = plist[offset];
  104. uint8_t type = marker & 0xF0;
  105. size_t len = marker & 0x0F;
  106. size_t pos = offset + 1;
  107. if (len == 0x0F) {
  108. if (pos >= plist_len) {
  109. return false;
  110. }
  111. uint8_t len_marker = plist[pos++];
  112. if ((len_marker & 0xF0) != BPLIST_INT) {
  113. return false;
  114. }
  115. size_t len_bytes = 1 << (len_marker & 0x0F);
  116. if (pos + len_bytes > plist_len) {
  117. return false;
  118. }
  119. len = (size_t)read_be_int(plist + pos, len_bytes);
  120. pos += len_bytes;
  121. }
  122. if (type == BPLIST_DATA) {
  123. if (pos + len > plist_len || len > out_capacity) {
  124. return false;
  125. }
  126. memcpy(out, plist + pos, len);
  127. *out_len = len;
  128. return true;
  129. }
  130. return false;
  131. }
  132. static bool bplist_read_data_len(const uint8_t *plist, size_t plist_len,
  133. uint64_t offset, size_t *out_len) {
  134. if (offset >= plist_len) {
  135. return false;
  136. }
  137. uint8_t marker = plist[offset];
  138. uint8_t type = marker & 0xF0;
  139. size_t len = marker & 0x0F;
  140. size_t pos = offset + 1;
  141. if (len == 0x0F) {
  142. if (pos >= plist_len) {
  143. return false;
  144. }
  145. uint8_t len_marker = plist[pos++];
  146. if ((len_marker & 0xF0) != BPLIST_INT) {
  147. return false;
  148. }
  149. size_t len_bytes = 1 << (len_marker & 0x0F);
  150. if (pos + len_bytes > plist_len) {
  151. return false;
  152. }
  153. len = (size_t)read_be_int(plist + pos, len_bytes);
  154. pos += len_bytes;
  155. }
  156. if (type == BPLIST_DATA) {
  157. if (pos + len > plist_len) {
  158. return false;
  159. }
  160. *out_len = len;
  161. return true;
  162. }
  163. return false;
  164. }
  165. static bool bplist_read_string_len(const uint8_t *plist, size_t plist_len,
  166. uint64_t offset, size_t *out_len) {
  167. if (offset >= plist_len) {
  168. return false;
  169. }
  170. uint8_t marker = plist[offset];
  171. uint8_t type = marker & 0xF0;
  172. size_t len = marker & 0x0F;
  173. size_t pos = offset + 1;
  174. if (len == 0x0F) {
  175. if (pos >= plist_len) {
  176. return false;
  177. }
  178. uint8_t len_marker = plist[pos++];
  179. if ((len_marker & 0xF0) != BPLIST_INT) {
  180. return false;
  181. }
  182. size_t len_bytes = 1 << (len_marker & 0x0F);
  183. if (pos + len_bytes > plist_len) {
  184. return false;
  185. }
  186. len = (size_t)read_be_int(plist + pos, len_bytes);
  187. pos += len_bytes;
  188. }
  189. if (type == BPLIST_STRING) {
  190. if (pos + len > plist_len) {
  191. return false;
  192. }
  193. *out_len = len;
  194. return true;
  195. }
  196. if (type == BPLIST_UNICODE) {
  197. size_t bytes = len * 2;
  198. if (pos + bytes > plist_len) {
  199. return false;
  200. }
  201. *out_len = len;
  202. return true;
  203. }
  204. return false;
  205. }
  206. static bool bplist_read_int(const uint8_t *plist, size_t plist_len,
  207. uint64_t offset, int64_t *out) {
  208. if (offset >= plist_len) {
  209. return false;
  210. }
  211. uint8_t marker = plist[offset];
  212. uint8_t type = marker & 0xF0;
  213. if (type == BPLIST_INT) {
  214. size_t len = 1 << (marker & 0x0F);
  215. if (offset + 1 + len > plist_len) {
  216. return false;
  217. }
  218. *out = (int64_t)read_be_int(plist + offset + 1, len);
  219. return true;
  220. }
  221. return false;
  222. }
  223. static bool bplist_read_real(const uint8_t *plist, size_t plist_len,
  224. uint64_t offset, double *out) {
  225. if (offset >= plist_len) {
  226. return false;
  227. }
  228. uint8_t marker = plist[offset];
  229. uint8_t type = marker & 0xF0;
  230. if (type == BPLIST_REAL) {
  231. size_t len = 1 << (marker & 0x0F);
  232. if (offset + 1 + len > plist_len) {
  233. return false;
  234. }
  235. if (len == 4) {
  236. uint32_t bits = (uint32_t)read_be_int(plist + offset + 1, 4);
  237. float f;
  238. memcpy(&f, &bits, sizeof(f));
  239. *out = (double)f;
  240. return true;
  241. } else if (len == 8) {
  242. uint64_t bits = read_be_int(plist + offset + 1, 8);
  243. memcpy(out, &bits, sizeof(*out));
  244. return true;
  245. }
  246. }
  247. return false;
  248. }
  249. static bool bplist_parse_count(const uint8_t *plist, size_t plist_len,
  250. uint64_t offset, size_t *count,
  251. size_t *header_len) {
  252. if (offset >= plist_len) {
  253. return false;
  254. }
  255. uint8_t marker = plist[offset];
  256. size_t info = marker & 0x0F;
  257. size_t pos = offset + 1;
  258. if (info == 0x0F) {
  259. if (pos >= plist_len) {
  260. return false;
  261. }
  262. uint8_t len_marker = plist[pos++];
  263. size_t len_bytes = 1 << (len_marker & 0x0F);
  264. if (pos + len_bytes > plist_len) {
  265. return false;
  266. }
  267. *count = (size_t)read_be_int(plist + pos, len_bytes);
  268. pos += len_bytes;
  269. } else {
  270. *count = info;
  271. }
  272. *header_len = pos - offset;
  273. return true;
  274. }
  275. static bool bplist_find_data_in_dict(const uint8_t *plist, size_t plist_len,
  276. uint64_t dict_offset,
  277. uint64_t offset_table_offset,
  278. uint8_t offset_size, uint8_t ref_size,
  279. const char *key, uint8_t *out_data,
  280. size_t out_capacity, size_t *out_len) {
  281. if (dict_offset >= plist_len) {
  282. return false;
  283. }
  284. uint8_t marker = plist[dict_offset];
  285. if ((marker & 0xF0) != BPLIST_DICT) {
  286. return false;
  287. }
  288. size_t dict_size = 0;
  289. size_t header_len = 0;
  290. if (!bplist_parse_count(plist, plist_len, dict_offset, &dict_size,
  291. &header_len)) {
  292. return false;
  293. }
  294. size_t pos = dict_offset + header_len;
  295. if (pos + dict_size * 2 * ref_size > plist_len) {
  296. return false;
  297. }
  298. const uint8_t *key_refs = plist + pos;
  299. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  300. for (size_t i = 0; i < dict_size; i++) {
  301. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  302. uint64_t key_offset =
  303. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  304. char found_key[64];
  305. if (bplist_read_string(plist, plist_len, key_offset, found_key,
  306. sizeof(found_key))) {
  307. if (strcmp(found_key, key) == 0) {
  308. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  309. uint64_t val_offset =
  310. bplist_get_offset(plist, offset_table_offset, offset_size, val_idx);
  311. return bplist_read_data(plist, plist_len, val_offset, out_data,
  312. out_capacity, out_len);
  313. }
  314. }
  315. }
  316. return false;
  317. }
  318. static bool bplist_find_data_recursive(const uint8_t *plist, size_t plist_len,
  319. uint64_t obj_idx,
  320. uint64_t offset_table_offset,
  321. uint8_t offset_size, uint8_t ref_size,
  322. const char *key, uint8_t *out_data,
  323. size_t out_capacity, size_t *out_len,
  324. int depth) {
  325. if (depth > 10) {
  326. return false;
  327. }
  328. uint64_t offset =
  329. bplist_get_offset(plist, offset_table_offset, offset_size, obj_idx);
  330. if (offset >= plist_len) {
  331. return false;
  332. }
  333. uint8_t marker = plist[offset];
  334. uint8_t type = marker & 0xF0;
  335. if (type == BPLIST_DICT) {
  336. size_t dict_size = 0;
  337. size_t header_len = 0;
  338. if (!bplist_parse_count(plist, plist_len, offset, &dict_size,
  339. &header_len)) {
  340. return false;
  341. }
  342. size_t pos = offset + header_len;
  343. if (pos + dict_size * 2 * ref_size > plist_len) {
  344. return false;
  345. }
  346. const uint8_t *key_refs = plist + pos;
  347. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  348. for (size_t i = 0; i < dict_size; i++) {
  349. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  350. uint64_t key_offset =
  351. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  352. char found_key[64];
  353. if (bplist_read_string(plist, plist_len, key_offset, found_key,
  354. sizeof(found_key))) {
  355. if (strcmp(found_key, key) == 0) {
  356. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  357. uint64_t val_offset = bplist_get_offset(plist, offset_table_offset,
  358. offset_size, val_idx);
  359. return bplist_read_data(plist, plist_len, val_offset, out_data,
  360. out_capacity, out_len);
  361. }
  362. }
  363. }
  364. for (size_t i = 0; i < dict_size; i++) {
  365. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  366. if (bplist_find_data_recursive(
  367. plist, plist_len, val_idx, offset_table_offset, offset_size,
  368. ref_size, key, out_data, out_capacity, out_len, depth + 1)) {
  369. return true;
  370. }
  371. }
  372. } else if (type == BPLIST_ARRAY || type == BPLIST_SET) {
  373. size_t count = 0;
  374. size_t header_len = 0;
  375. if (!bplist_parse_count(plist, plist_len, offset, &count, &header_len)) {
  376. return false;
  377. }
  378. size_t pos = offset + header_len;
  379. if (pos + count * ref_size > plist_len) {
  380. return false;
  381. }
  382. for (size_t i = 0; i < count; i++) {
  383. uint64_t idx = read_be_int(plist + pos + i * ref_size, ref_size);
  384. if (bplist_find_data_recursive(plist, plist_len, idx, offset_table_offset,
  385. offset_size, ref_size, key, out_data,
  386. out_capacity, out_len, depth + 1)) {
  387. return true;
  388. }
  389. }
  390. }
  391. return false;
  392. }
  393. bool bplist_find_data(const uint8_t *plist, size_t plist_len, const char *key,
  394. uint8_t *out_data, size_t out_capacity, size_t *out_len) {
  395. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  396. return false;
  397. }
  398. uint8_t offset_size = 0;
  399. uint8_t ref_size = 0;
  400. uint64_t num_objects = 0;
  401. uint64_t top_object = 0;
  402. uint64_t offset_table_offset = 0;
  403. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  404. &num_objects, &top_object, &offset_table_offset)) {
  405. return false;
  406. }
  407. uint64_t top_offset =
  408. bplist_get_offset(plist, offset_table_offset, offset_size, top_object);
  409. if (top_offset >= plist_len) {
  410. return false;
  411. }
  412. return bplist_find_data_in_dict(plist, plist_len, top_offset,
  413. offset_table_offset, offset_size, ref_size,
  414. key, out_data, out_capacity, out_len);
  415. }
  416. bool bplist_find_data_deep(const uint8_t *plist, size_t plist_len,
  417. const char *key, uint8_t *out_data,
  418. size_t out_capacity, size_t *out_len) {
  419. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  420. return false;
  421. }
  422. uint8_t offset_size = 0;
  423. uint8_t ref_size = 0;
  424. uint64_t num_objects = 0;
  425. uint64_t top_object = 0;
  426. uint64_t offset_table_offset = 0;
  427. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  428. &num_objects, &top_object, &offset_table_offset)) {
  429. return false;
  430. }
  431. (void)num_objects;
  432. return bplist_find_data_recursive(plist, plist_len, top_object,
  433. offset_table_offset, offset_size, ref_size,
  434. key, out_data, out_capacity, out_len, 0);
  435. }
  436. bool bplist_find_int(const uint8_t *plist, size_t plist_len, const char *key,
  437. int64_t *out_value) {
  438. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  439. return false;
  440. }
  441. uint8_t offset_size = 0;
  442. uint8_t ref_size = 0;
  443. uint64_t num_objects = 0;
  444. uint64_t top_object = 0;
  445. uint64_t offset_table_offset = 0;
  446. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  447. &num_objects, &top_object, &offset_table_offset)) {
  448. return false;
  449. }
  450. uint64_t top_offset =
  451. bplist_get_offset(plist, offset_table_offset, offset_size, top_object);
  452. if (top_offset >= plist_len) {
  453. return false;
  454. }
  455. uint8_t marker = plist[top_offset];
  456. if ((marker & 0xF0) != BPLIST_DICT) {
  457. return false;
  458. }
  459. size_t dict_size = marker & 0x0F;
  460. size_t pos = top_offset + 1;
  461. if (dict_size == 0x0F) {
  462. if (pos >= plist_len) {
  463. return false;
  464. }
  465. uint8_t len_marker = plist[pos++];
  466. size_t len_bytes = 1 << (len_marker & 0x0F);
  467. if (pos + len_bytes > plist_len) {
  468. return false;
  469. }
  470. dict_size = (size_t)read_be_int(plist + pos, len_bytes);
  471. pos += len_bytes;
  472. }
  473. if (pos + dict_size * 2 * ref_size > plist_len) {
  474. return false;
  475. }
  476. const uint8_t *key_refs = plist + pos;
  477. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  478. for (size_t i = 0; i < dict_size; i++) {
  479. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  480. uint64_t key_offset =
  481. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  482. char found_key[64];
  483. if (bplist_read_string(plist, plist_len, key_offset, found_key,
  484. sizeof(found_key))) {
  485. if (strcmp(found_key, key) == 0) {
  486. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  487. uint64_t val_offset =
  488. bplist_get_offset(plist, offset_table_offset, offset_size, val_idx);
  489. return bplist_read_int(plist, plist_len, val_offset, out_value);
  490. }
  491. }
  492. }
  493. return false;
  494. }
  495. bool bplist_find_real(const uint8_t *plist, size_t plist_len, const char *key,
  496. double *out_value) {
  497. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  498. return false;
  499. }
  500. uint8_t offset_size = 0;
  501. uint8_t ref_size = 0;
  502. uint64_t num_objects = 0;
  503. uint64_t top_object = 0;
  504. uint64_t offset_table_offset = 0;
  505. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  506. &num_objects, &top_object, &offset_table_offset)) {
  507. return false;
  508. }
  509. uint64_t top_offset =
  510. bplist_get_offset(plist, offset_table_offset, offset_size, top_object);
  511. if (top_offset >= plist_len) {
  512. return false;
  513. }
  514. uint8_t marker = plist[top_offset];
  515. if ((marker & 0xF0) != BPLIST_DICT) {
  516. return false;
  517. }
  518. size_t dict_size = marker & 0x0F;
  519. size_t pos = top_offset + 1;
  520. if (dict_size == 0x0F) {
  521. if (pos >= plist_len) {
  522. return false;
  523. }
  524. uint8_t len_marker = plist[pos++];
  525. size_t len_bytes = 1 << (len_marker & 0x0F);
  526. if (pos + len_bytes > plist_len) {
  527. return false;
  528. }
  529. dict_size = (size_t)read_be_int(plist + pos, len_bytes);
  530. pos += len_bytes;
  531. }
  532. if (pos + dict_size * 2 * ref_size > plist_len) {
  533. return false;
  534. }
  535. const uint8_t *key_refs = plist + pos;
  536. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  537. for (size_t i = 0; i < dict_size; i++) {
  538. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  539. uint64_t key_offset =
  540. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  541. char found_key[64];
  542. if (bplist_read_string(plist, plist_len, key_offset, found_key,
  543. sizeof(found_key))) {
  544. if (strcmp(found_key, key) == 0) {
  545. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  546. uint64_t val_offset =
  547. bplist_get_offset(plist, offset_table_offset, offset_size, val_idx);
  548. if (bplist_read_real(plist, plist_len, val_offset, out_value)) {
  549. return true;
  550. }
  551. int64_t int_val = 0;
  552. if (bplist_read_int(plist, plist_len, val_offset, &int_val)) {
  553. *out_value = (double)int_val;
  554. return true;
  555. }
  556. return false;
  557. }
  558. }
  559. }
  560. return false;
  561. }
  562. bool bplist_find_string(const uint8_t *plist, size_t plist_len, const char *key,
  563. char *out_str, size_t out_capacity) {
  564. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  565. return false;
  566. }
  567. uint8_t offset_size = 0;
  568. uint8_t ref_size = 0;
  569. uint64_t num_objects = 0;
  570. uint64_t top_object = 0;
  571. uint64_t offset_table_offset = 0;
  572. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  573. &num_objects, &top_object, &offset_table_offset)) {
  574. return false;
  575. }
  576. uint64_t top_offset =
  577. bplist_get_offset(plist, offset_table_offset, offset_size, top_object);
  578. if (top_offset >= plist_len) {
  579. return false;
  580. }
  581. uint8_t marker = plist[top_offset];
  582. if ((marker & 0xF0) != BPLIST_DICT) {
  583. return false;
  584. }
  585. size_t dict_size = marker & 0x0F;
  586. size_t pos = top_offset + 1;
  587. if (dict_size == 0x0F) {
  588. if (pos >= plist_len) {
  589. return false;
  590. }
  591. uint8_t len_marker = plist[pos++];
  592. size_t len_bytes = 1 << (len_marker & 0x0F);
  593. if (pos + len_bytes > plist_len) {
  594. return false;
  595. }
  596. dict_size = (size_t)read_be_int(plist + pos, len_bytes);
  597. pos += len_bytes;
  598. }
  599. if (pos + dict_size * 2 * ref_size > plist_len) {
  600. return false;
  601. }
  602. const uint8_t *key_refs = plist + pos;
  603. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  604. for (size_t i = 0; i < dict_size; i++) {
  605. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  606. uint64_t key_offset =
  607. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  608. char found_key[64];
  609. if (bplist_read_string(plist, plist_len, key_offset, found_key,
  610. sizeof(found_key))) {
  611. if (strcmp(found_key, key) == 0) {
  612. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  613. uint64_t val_offset =
  614. bplist_get_offset(plist, offset_table_offset, offset_size, val_idx);
  615. return bplist_read_string(plist, plist_len, val_offset, out_str,
  616. out_capacity);
  617. }
  618. }
  619. }
  620. return false;
  621. }
  622. bool bplist_get_streams_count(const uint8_t *plist, size_t plist_len,
  623. size_t *count) {
  624. if (!count) {
  625. return false;
  626. }
  627. *count = 0;
  628. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  629. return false;
  630. }
  631. uint8_t offset_size = 0;
  632. uint8_t ref_size = 0;
  633. uint64_t num_objects = 0;
  634. uint64_t top_object = 0;
  635. uint64_t offset_table_offset = 0;
  636. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  637. &num_objects, &top_object, &offset_table_offset)) {
  638. return false;
  639. }
  640. uint64_t top_offset =
  641. bplist_get_offset(plist, offset_table_offset, offset_size, top_object);
  642. if (top_offset >= plist_len) {
  643. return false;
  644. }
  645. size_t streams_key_len = 0;
  646. uint64_t streams_key_offset = 0;
  647. for (uint64_t i = 0; i < num_objects; i++) {
  648. uint64_t offset =
  649. bplist_get_offset(plist, offset_table_offset, offset_size, i);
  650. if (offset >= plist_len) {
  651. continue;
  652. }
  653. char key[16];
  654. if (bplist_read_string(plist, plist_len, offset, key, sizeof(key))) {
  655. if (strcmp(key, "streams") == 0) {
  656. streams_key_offset = offset;
  657. if (!bplist_read_string_len(plist, plist_len, offset,
  658. &streams_key_len)) {
  659. return false;
  660. }
  661. break;
  662. }
  663. }
  664. }
  665. if (streams_key_len == 0) {
  666. return false;
  667. }
  668. uint64_t top_dict_offset = top_offset;
  669. uint8_t marker = plist[top_dict_offset];
  670. if ((marker & 0xF0) != BPLIST_DICT) {
  671. return false;
  672. }
  673. size_t dict_size = marker & 0x0F;
  674. size_t pos = top_dict_offset + 1;
  675. if (dict_size == 0x0F) {
  676. if (pos >= plist_len) {
  677. return false;
  678. }
  679. uint8_t len_marker = plist[pos++];
  680. size_t len_bytes = 1 << (len_marker & 0x0F);
  681. if (pos + len_bytes > plist_len) {
  682. return false;
  683. }
  684. dict_size = (size_t)read_be_int(plist + pos, len_bytes);
  685. pos += len_bytes;
  686. }
  687. if (pos + dict_size * 2 * ref_size > plist_len) {
  688. return false;
  689. }
  690. const uint8_t *key_refs = plist + pos;
  691. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  692. for (size_t i = 0; i < dict_size; i++) {
  693. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  694. uint64_t key_offset =
  695. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  696. if (key_offset == streams_key_offset) {
  697. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  698. uint64_t val_offset =
  699. bplist_get_offset(plist, offset_table_offset, offset_size, val_idx);
  700. uint8_t val_marker = plist[val_offset];
  701. if ((val_marker & 0xF0) != BPLIST_ARRAY) {
  702. return false;
  703. }
  704. size_t array_count = 0;
  705. size_t header_len = 0;
  706. if (!bplist_parse_count(plist, plist_len, val_offset, &array_count,
  707. &header_len)) {
  708. return false;
  709. }
  710. *count = array_count;
  711. return true;
  712. }
  713. }
  714. return false;
  715. }
  716. bool bplist_get_stream_info(const uint8_t *plist, size_t plist_len,
  717. size_t index, int64_t *type, size_t *ekey_len,
  718. size_t *eiv_len, size_t *shk_len) {
  719. if (!type) {
  720. return false;
  721. }
  722. *type = -1;
  723. if (ekey_len) {
  724. *ekey_len = 0;
  725. }
  726. if (eiv_len) {
  727. *eiv_len = 0;
  728. }
  729. if (shk_len) {
  730. *shk_len = 0;
  731. }
  732. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  733. return false;
  734. }
  735. uint8_t offset_size = 0;
  736. uint8_t ref_size = 0;
  737. uint64_t num_objects = 0;
  738. uint64_t top_object = 0;
  739. uint64_t offset_table_offset = 0;
  740. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  741. &num_objects, &top_object, &offset_table_offset)) {
  742. return false;
  743. }
  744. uint64_t top_offset =
  745. bplist_get_offset(plist, offset_table_offset, offset_size, top_object);
  746. if (top_offset >= plist_len) {
  747. return false;
  748. }
  749. size_t streams_key_len = 0;
  750. uint64_t streams_key_offset = 0;
  751. for (uint64_t i = 0; i < num_objects; i++) {
  752. uint64_t offset =
  753. bplist_get_offset(plist, offset_table_offset, offset_size, i);
  754. if (offset >= plist_len) {
  755. continue;
  756. }
  757. char key[16];
  758. if (bplist_read_string(plist, plist_len, offset, key, sizeof(key))) {
  759. if (strcmp(key, "streams") == 0) {
  760. streams_key_offset = offset;
  761. if (!bplist_read_string_len(plist, plist_len, offset,
  762. &streams_key_len)) {
  763. return false;
  764. }
  765. break;
  766. }
  767. }
  768. }
  769. if (streams_key_len == 0) {
  770. return false;
  771. }
  772. uint64_t top_dict_offset = top_offset;
  773. uint8_t marker = plist[top_dict_offset];
  774. if ((marker & 0xF0) != BPLIST_DICT) {
  775. return false;
  776. }
  777. size_t dict_size = marker & 0x0F;
  778. size_t pos = top_dict_offset + 1;
  779. if (dict_size == 0x0F) {
  780. if (pos >= plist_len) {
  781. return false;
  782. }
  783. uint8_t len_marker = plist[pos++];
  784. size_t len_bytes = 1 << (len_marker & 0x0F);
  785. if (pos + len_bytes > plist_len) {
  786. return false;
  787. }
  788. dict_size = (size_t)read_be_int(plist + pos, len_bytes);
  789. pos += len_bytes;
  790. }
  791. if (pos + dict_size * 2 * ref_size > plist_len) {
  792. return false;
  793. }
  794. const uint8_t *key_refs = plist + pos;
  795. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  796. for (size_t i = 0; i < dict_size; i++) {
  797. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  798. uint64_t key_offset =
  799. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  800. if (key_offset == streams_key_offset) {
  801. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  802. uint64_t val_offset =
  803. bplist_get_offset(plist, offset_table_offset, offset_size, val_idx);
  804. uint8_t val_marker = plist[val_offset];
  805. if ((val_marker & 0xF0) != BPLIST_ARRAY) {
  806. return false;
  807. }
  808. size_t array_count = 0;
  809. size_t header_len = 0;
  810. if (!bplist_parse_count(plist, plist_len, val_offset, &array_count,
  811. &header_len)) {
  812. return false;
  813. }
  814. if (index >= array_count) {
  815. return false;
  816. }
  817. size_t array_pos = val_offset + header_len;
  818. if (array_pos + array_count * ref_size > plist_len) {
  819. return false;
  820. }
  821. uint64_t stream_idx =
  822. read_be_int(plist + array_pos + index * ref_size, ref_size);
  823. uint64_t stream_offset = bplist_get_offset(plist, offset_table_offset,
  824. offset_size, stream_idx);
  825. uint8_t stream_marker = plist[stream_offset];
  826. if ((stream_marker & 0xF0) != BPLIST_DICT) {
  827. return false;
  828. }
  829. size_t stream_dict_size = 0;
  830. size_t stream_header_len = 0;
  831. if (!bplist_parse_count(plist, plist_len, stream_offset,
  832. &stream_dict_size, &stream_header_len)) {
  833. return false;
  834. }
  835. size_t stream_pos = stream_offset + stream_header_len;
  836. if (stream_pos + stream_dict_size * 2 * ref_size > plist_len) {
  837. return false;
  838. }
  839. const uint8_t *stream_key_refs = plist + stream_pos;
  840. const uint8_t *stream_val_refs =
  841. plist + stream_pos + stream_dict_size * ref_size;
  842. for (size_t j = 0; j < stream_dict_size; j++) {
  843. uint64_t stream_key_idx =
  844. read_be_int(stream_key_refs + j * ref_size, ref_size);
  845. uint64_t stream_key_offset = bplist_get_offset(
  846. plist, offset_table_offset, offset_size, stream_key_idx);
  847. char stream_key[32];
  848. if (!bplist_read_string(plist, plist_len, stream_key_offset, stream_key,
  849. sizeof(stream_key))) {
  850. continue;
  851. }
  852. uint64_t stream_val_idx =
  853. read_be_int(stream_val_refs + j * ref_size, ref_size);
  854. uint64_t stream_val_offset = bplist_get_offset(
  855. plist, offset_table_offset, offset_size, stream_val_idx);
  856. if (strcmp(stream_key, "type") == 0) {
  857. int64_t type_val = 0;
  858. if (bplist_read_int(plist, plist_len, stream_val_offset, &type_val)) {
  859. *type = type_val;
  860. }
  861. } else if (strcmp(stream_key, "ekey") == 0 && ekey_len) {
  862. bplist_read_data_len(plist, plist_len, stream_val_offset, ekey_len);
  863. } else if (strcmp(stream_key, "eiv") == 0 && eiv_len) {
  864. bplist_read_data_len(plist, plist_len, stream_val_offset, eiv_len);
  865. } else if (strcmp(stream_key, "shk") == 0 && shk_len) {
  866. bplist_read_data_len(plist, plist_len, stream_val_offset, shk_len);
  867. }
  868. }
  869. return (*type != -1);
  870. }
  871. }
  872. return false;
  873. }
  874. bool bplist_get_stream_kv_info(const uint8_t *plist, size_t plist_len,
  875. size_t index, bplist_kv_info_t *out,
  876. size_t out_capacity, size_t *out_count) {
  877. if (!out || out_capacity == 0 || !out_count) {
  878. return false;
  879. }
  880. *out_count = 0;
  881. if (plist_len < 40 || memcmp(plist, "bplist00", 8) != 0) {
  882. return false;
  883. }
  884. uint8_t offset_size = 0;
  885. uint8_t ref_size = 0;
  886. uint64_t num_objects = 0;
  887. uint64_t top_object = 0;
  888. uint64_t offset_table_offset = 0;
  889. if (!bplist_parse_trailer(plist, plist_len, &offset_size, &ref_size,
  890. &num_objects, &top_object, &offset_table_offset)) {
  891. return false;
  892. }
  893. uint64_t top_offset =
  894. bplist_get_offset(plist, offset_table_offset, offset_size, top_object);
  895. if (top_offset >= plist_len) {
  896. return false;
  897. }
  898. size_t streams_key_len = 0;
  899. uint64_t streams_key_offset = 0;
  900. for (uint64_t i = 0; i < num_objects; i++) {
  901. uint64_t offset =
  902. bplist_get_offset(plist, offset_table_offset, offset_size, i);
  903. if (offset >= plist_len) {
  904. continue;
  905. }
  906. char key[16];
  907. if (bplist_read_string(plist, plist_len, offset, key, sizeof(key))) {
  908. if (strcmp(key, "streams") == 0) {
  909. streams_key_offset = offset;
  910. if (!bplist_read_string_len(plist, plist_len, offset,
  911. &streams_key_len)) {
  912. return false;
  913. }
  914. break;
  915. }
  916. }
  917. }
  918. if (streams_key_len == 0) {
  919. return false;
  920. }
  921. uint64_t top_dict_offset = top_offset;
  922. uint8_t marker = plist[top_dict_offset];
  923. if ((marker & 0xF0) != BPLIST_DICT) {
  924. return false;
  925. }
  926. size_t dict_size = marker & 0x0F;
  927. size_t pos = top_dict_offset + 1;
  928. if (dict_size == 0x0F) {
  929. if (pos >= plist_len) {
  930. return false;
  931. }
  932. uint8_t len_marker = plist[pos++];
  933. size_t len_bytes = 1 << (len_marker & 0x0F);
  934. if (pos + len_bytes > plist_len) {
  935. return false;
  936. }
  937. dict_size = (size_t)read_be_int(plist + pos, len_bytes);
  938. pos += len_bytes;
  939. }
  940. if (pos + dict_size * 2 * ref_size > plist_len) {
  941. return false;
  942. }
  943. const uint8_t *key_refs = plist + pos;
  944. const uint8_t *val_refs = plist + pos + dict_size * ref_size;
  945. for (size_t i = 0; i < dict_size; i++) {
  946. uint64_t key_idx = read_be_int(key_refs + i * ref_size, ref_size);
  947. uint64_t key_offset =
  948. bplist_get_offset(plist, offset_table_offset, offset_size, key_idx);
  949. if (key_offset == streams_key_offset) {
  950. uint64_t val_idx = read_be_int(val_refs + i * ref_size, ref_size);
  951. uint64_t val_offset =
  952. bplist_get_offset(plist, offset_table_offset, offset_size, val_idx);
  953. uint8_t val_marker = plist[val_offset];
  954. if ((val_marker & 0xF0) != BPLIST_ARRAY) {
  955. return false;
  956. }
  957. size_t array_count = 0;
  958. size_t header_len = 0;
  959. if (!bplist_parse_count(plist, plist_len, val_offset, &array_count,
  960. &header_len)) {
  961. return false;
  962. }
  963. if (index >= array_count) {
  964. return false;
  965. }
  966. size_t array_pos = val_offset + header_len;
  967. if (array_pos + array_count * ref_size > plist_len) {
  968. return false;
  969. }
  970. uint64_t stream_idx =
  971. read_be_int(plist + array_pos + index * ref_size, ref_size);
  972. uint64_t stream_offset = bplist_get_offset(plist, offset_table_offset,
  973. offset_size, stream_idx);
  974. uint8_t stream_marker = plist[stream_offset];
  975. if ((stream_marker & 0xF0) != BPLIST_DICT) {
  976. return false;
  977. }
  978. size_t stream_dict_size = 0;
  979. size_t stream_header_len = 0;
  980. if (!bplist_parse_count(plist, plist_len, stream_offset,
  981. &stream_dict_size, &stream_header_len)) {
  982. return false;
  983. }
  984. size_t stream_pos = stream_offset + stream_header_len;
  985. if (stream_pos + stream_dict_size * 2 * ref_size > plist_len) {
  986. return false;
  987. }
  988. const uint8_t *stream_key_refs = plist + stream_pos;
  989. const uint8_t *stream_val_refs =
  990. plist + stream_pos + stream_dict_size * ref_size;
  991. for (size_t j = 0; j < stream_dict_size && *out_count < out_capacity;
  992. j++) {
  993. uint64_t stream_key_idx =
  994. read_be_int(stream_key_refs + j * ref_size, ref_size);
  995. uint64_t stream_key_offset = bplist_get_offset(
  996. plist, offset_table_offset, offset_size, stream_key_idx);
  997. char stream_key[64];
  998. if (!bplist_read_string(plist, plist_len, stream_key_offset, stream_key,
  999. sizeof(stream_key))) {
  1000. continue;
  1001. }
  1002. uint64_t stream_val_idx =
  1003. read_be_int(stream_val_refs + j * ref_size, ref_size);
  1004. uint64_t stream_val_offset = bplist_get_offset(
  1005. plist, offset_table_offset, offset_size, stream_val_idx);
  1006. bplist_kv_info_t *info = &out[*out_count];
  1007. memset(info, 0, sizeof(*info));
  1008. strlcpy(info->key, stream_key, sizeof(info->key));
  1009. uint8_t stream_val_marker = plist[stream_val_offset];
  1010. uint8_t stream_val_type = stream_val_marker & 0xF0;
  1011. if (stream_val_type == BPLIST_INT) {
  1012. info->value_type = BPLIST_VALUE_INT;
  1013. int64_t int_val = 0;
  1014. if (bplist_read_int(plist, plist_len, stream_val_offset, &int_val)) {
  1015. info->int_value = int_val;
  1016. }
  1017. } else if (stream_val_type == BPLIST_DATA) {
  1018. info->value_type = BPLIST_VALUE_DATA;
  1019. size_t len = 0;
  1020. if (bplist_read_data_len(plist, plist_len, stream_val_offset, &len)) {
  1021. info->value_len = len;
  1022. }
  1023. } else if (stream_val_type == BPLIST_STRING ||
  1024. stream_val_type == BPLIST_UNICODE) {
  1025. info->value_type = BPLIST_VALUE_STRING;
  1026. size_t len = 0;
  1027. if (bplist_read_string_len(plist, plist_len, stream_val_offset,
  1028. &len)) {
  1029. info->value_len = len;
  1030. }
  1031. } else if (stream_val_type == BPLIST_UID) {
  1032. info->value_type = BPLIST_VALUE_UID;
  1033. } else if (stream_val_type == BPLIST_ARRAY) {
  1034. info->value_type = BPLIST_VALUE_ARRAY;
  1035. } else if (stream_val_type == BPLIST_DICT) {
  1036. info->value_type = BPLIST_VALUE_DICT;
  1037. }
  1038. (*out_count)++;
  1039. }
  1040. return (*out_count > 0);
  1041. }
  1042. }
  1043. return false;
  1044. }
  1045. bool bplist_find_stream_crypto(const uint8_t *plist, size_t plist_len,
  1046. int64_t stream_type, uint8_t *ekey,
  1047. size_t ekey_capacity, size_t *ekey_len,
  1048. uint8_t *eiv, size_t eiv_capacity,
  1049. size_t *eiv_len, uint8_t *shk,
  1050. size_t shk_capacity, size_t *shk_len) {
  1051. bool found = false;
  1052. if (ekey_len) {
  1053. *ekey_len = 0;
  1054. }
  1055. if (eiv_len) {
  1056. *eiv_len = 0;
  1057. }
  1058. if (shk_len) {
  1059. *shk_len = 0;
  1060. }
  1061. size_t stream_count = 0;
  1062. if (!bplist_get_streams_count(plist, plist_len, &stream_count)) {
  1063. return false;
  1064. }
  1065. for (size_t i = 0; i < stream_count; i++) {
  1066. int64_t type = -1;
  1067. size_t local_ekey_len = 0;
  1068. size_t local_eiv_len = 0;
  1069. size_t local_shk_len = 0;
  1070. if (!bplist_get_stream_info(plist, plist_len, i, &type, &local_ekey_len,
  1071. &local_eiv_len, &local_shk_len)) {
  1072. continue;
  1073. }
  1074. if (type != stream_type) {
  1075. continue;
  1076. }
  1077. uint8_t temp_buf[512];
  1078. size_t temp_len = 0;
  1079. if (ekey && local_ekey_len > 0 && ekey_len) {
  1080. if (bplist_find_data(plist, plist_len, "ekey", temp_buf, sizeof(temp_buf),
  1081. &temp_len)) {
  1082. size_t copy_len = temp_len < ekey_capacity ? temp_len : ekey_capacity;
  1083. memcpy(ekey, temp_buf, copy_len);
  1084. *ekey_len = copy_len;
  1085. found = true;
  1086. }
  1087. }
  1088. if (eiv && local_eiv_len > 0 && eiv_len) {
  1089. if (bplist_find_data(plist, plist_len, "eiv", temp_buf, sizeof(temp_buf),
  1090. &temp_len)) {
  1091. size_t copy_len = temp_len < eiv_capacity ? temp_len : eiv_capacity;
  1092. memcpy(eiv, temp_buf, copy_len);
  1093. *eiv_len = copy_len;
  1094. found = true;
  1095. }
  1096. }
  1097. if (shk && local_shk_len > 0 && shk_len) {
  1098. if (bplist_find_data(plist, plist_len, "shk", temp_buf, sizeof(temp_buf),
  1099. &temp_len)) {
  1100. size_t copy_len = temp_len < shk_capacity ? temp_len : shk_capacity;
  1101. memcpy(shk, temp_buf, copy_len);
  1102. *shk_len = copy_len;
  1103. found = true;
  1104. }
  1105. }
  1106. break;
  1107. }
  1108. return found;
  1109. }