CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/exploits/CVE-2017-13861/liboffsetfinder64/img4.c
Views: 11784
1
//
2
// img4.c
3
// img4tool
4
//
5
// Created by tihmstar on 15.06.16.
6
// Copyright © 2016 tihmstar. All rights reserved.
7
//
8
9
#include "img4.h"
10
#include "all_img4tool.h"
11
#include <stdlib.h>
12
#include <string.h>
13
#include <sys/types.h>
14
#include <stdint.h>
15
#include "lzssdec.h"
16
17
/*#ifndef IMG4TOOL_NOLZFSE*/
18
/*#ifdef HAVE_LIBLZFSE*/
19
/*# include <lzfse.h>*/
20
/*#elif defined(HAVE_LIBCOMPRESSION)*/
21
/*# include <compression.h>*/
22
/*# define lzfse_decode_buffer(src, src_size, dst, dst_size, scratch) \*/
23
/*compression_decode_buffer(src, src_size, dst, dst_size, scratch, COMPRESSION_LZFSE)*/
24
/*#else*/
25
/*# error "either liblzfse or libcompression is needed"*/
26
/*#endif*/
27
/*#endif*/
28
29
/*#ifndef IMG4TOOL_NOOPENSSL*/
30
/*# include <openssl/x509.h>*/
31
/*# include <openssl/evp.h>*/
32
/*# include <openssl/sha.h>*/
33
/*#elif defined(__APPLE__)*/
34
/*# include <CommonCrypto/CommonDigest.h>*/
35
/*# define SHA1(d, n, md) CC_SHA1(d, n, md)*/
36
/*# define SHA_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH*/
37
/*#else*/
38
/*# error openssl is required on non-Apple*/
39
/*#endif*/
40
41
#define safeFree(buf) if (buf) free(buf), buf = NULL
42
#define assure(a) do{ if ((a) == 0){err=1; goto error;} }while(0)
43
#define retassure(retcode, a) do{ if ((a) == 0){err=retcode; goto error;} }while(0)
44
#define asn1Tag(a) ((t_asn1Tag*)a)
45
46
t_asn1ElemLen asn1Len(const char buf[4]){
47
t_asn1Length *sTmp = (t_asn1Length *)buf;
48
size_t outSize = 0;
49
int sizeBytes_ = 0;
50
51
unsigned char *sbuf = (unsigned char *)buf;
52
53
if (!sTmp->isLong) outSize = sTmp->len;
54
else{
55
sizeBytes_ = sTmp->len;
56
for (int i=0; i<sizeBytes_; i++) {
57
outSize *= 0x100;
58
outSize += sbuf[1+i];
59
}
60
}
61
62
t_asn1ElemLen ret;
63
ret.dataLen = outSize;
64
ret.sizeBytes = sizeBytes_+1;
65
return ret;
66
}
67
68
char *ans1GetString(char *buf, char **outString, size_t *strlen){
69
70
t_asn1Tag *tag = (t_asn1Tag *)buf;
71
72
if (!(tag->tagNumber | kASN1TagIA5String)) {
73
error("not a string\n");
74
return 0;
75
}
76
77
t_asn1ElemLen len = asn1Len(++buf);
78
*strlen = len.dataLen;
79
buf+=len.sizeBytes;
80
if (outString) *outString = buf;
81
82
return buf+*strlen;
83
}
84
85
int asn1ElementAtIndexWithCounter(const char *buf, int index, t_asn1Tag **tagret){
86
int ret = 0;
87
88
if (!((t_asn1Tag *)buf)->isConstructed) return 0;
89
t_asn1ElemLen len = asn1Len(++buf);
90
91
buf +=len.sizeBytes;
92
93
while (len.dataLen) {
94
if (ret == index && tagret){
95
*tagret = (t_asn1Tag*)buf;
96
return ret;
97
}
98
99
if (*buf == kASN1TagPrivate) {
100
size_t sb;
101
asn1GetPrivateTagnum((t_asn1Tag*)buf,&sb);
102
buf+=sb;
103
len.dataLen-=sb;
104
}else if (*buf == (char)0x9F){
105
//buf is element in set and it's value is encoded in the next byte
106
t_asn1ElemLen l = asn1Len(++buf);
107
if (l.sizeBytes > 1) l.dataLen += 0x80;
108
buf += l.sizeBytes;
109
len.dataLen -= 1 + l.sizeBytes;
110
}else
111
buf++,len.dataLen--;
112
113
t_asn1ElemLen sublen = asn1Len(buf);
114
size_t toadd =sublen.dataLen + sublen.sizeBytes;
115
len.dataLen -=toadd;
116
buf +=toadd;
117
ret ++;
118
}
119
120
return ret;
121
}
122
123
int asn1ElementsInObject(const char *buf){
124
return asn1ElementAtIndexWithCounter(buf, -1, NULL);
125
}
126
127
char *asn1ElementAtIndex(const char *buf, int index){
128
t_asn1Tag *ret;
129
asn1ElementAtIndexWithCounter(buf, index, &ret);
130
return (char*)ret;
131
}
132
133
int getSequenceName(const char *buf,char**name, size_t *nameLen){
134
#define reterror(a ...){error(a); err = -1; goto error;}
135
int err = 0;
136
if (((t_asn1Tag*)buf)->tagNumber != kASN1TagSEQUENCE) reterror("not a SEQUENCE\n");
137
int elems = asn1ElementsInObject(buf);
138
if (!elems) reterror("no elements in SEQUENCE\n");
139
size_t len;
140
ans1GetString((char*)asn1ElementAtIndex(buf,0),name,&len);
141
if (nameLen) *nameLen = len;
142
error:
143
return err;
144
#undef reterror
145
}
146
147
size_t asn1GetPrivateTagnum(t_asn1Tag *tag, size_t *sizebytes){
148
if (*(unsigned char*)tag != 0xff) {
149
error("not a private TAG 0x%02x\n",*(unsigned int*)tag);
150
return 0;
151
}
152
size_t sb = 1;
153
t_asn1ElemLen taglen = asn1Len((char*)++tag);
154
taglen.sizeBytes-=1;
155
if (taglen.sizeBytes != 4){
156
/*
157
WARNING: seems like apple's private tag is always 4 bytes long
158
i first assumed 0x84 can be parsed as long size with 4 bytes,
159
but 0x86 also seems to be 4 bytes size even if one would assume it means 6 bytes size.
160
This opens the question what the 4 or 6 nibble means.
161
*/
162
taglen.sizeBytes = 4;
163
}
164
size_t tagname =0;
165
do {
166
tagname *=0x100;
167
tagname>>=1;
168
tagname += ((t_asn1PrivateTag*)tag)->num;
169
sb++;
170
} while (((t_asn1PrivateTag*)tag++)->more);
171
if (sizebytes) *sizebytes = sb;
172
return tagname;
173
}
174
175
uint64_t ans1GetNumberFromTag(t_asn1Tag *tag){
176
if (tag->tagNumber != kASN1TagINTEGER) return (error("not an INTEGER\n"),0);
177
uint64_t ret = 0;
178
t_asn1ElemLen len = asn1Len((char*)++tag);
179
unsigned char *data = (unsigned char*)tag+len.sizeBytes;
180
while (len.dataLen--) {
181
ret *= 0x100;
182
ret+= *data++;
183
}
184
185
return ret;
186
}
187
188
void printStringWithKey(char*key, t_asn1Tag *string){
189
char *str = 0;
190
size_t strlen;
191
ans1GetString((char*)string,&str,&strlen);
192
printf("%s",key);
193
putStr(str, strlen);
194
putchar('\n');
195
}
196
197
void printPrivtag(size_t privTag){
198
char *ptag = (char*)&privTag;
199
int len = 0;
200
while (*ptag) ptag++,len++;
201
while (len--) putchar(*--ptag);
202
}
203
204
void printHexString(t_asn1Tag *str){
205
if (str->tagNumber != kASN1TagOCTET){
206
error("not an OCTET string\n");
207
return;
208
}
209
210
t_asn1ElemLen len = asn1Len((char*)str+1);
211
212
unsigned char *string = (unsigned char*)str + len.sizeBytes +1;
213
214
while (len.dataLen--) printf("%02x",*string++);
215
}
216
217
void printI5AString(t_asn1Tag *str){
218
if (str->tagNumber != kASN1TagIA5String){
219
error("not an I5A string\n");
220
return;
221
}
222
223
t_asn1ElemLen len = asn1Len((char*)++str);
224
putStr(((char*)str)+len.sizeBytes, len.dataLen);
225
}
226
227
void printKBAGOctet(char *octet){
228
#define reterror(a ...){error(a);goto error;}
229
if (((t_asn1Tag*)octet)->tagNumber != kASN1TagOCTET) reterror("not an OCTET\n");
230
231
t_asn1ElemLen octetlen = asn1Len(++octet);
232
octet +=octetlen.sizeBytes;
233
//main seq
234
int subseqs = asn1ElementsInObject(octet);
235
for (int i=0; i<subseqs; i++) {
236
char *s = (char*)asn1ElementAtIndex(octet, i);
237
int elems = asn1ElementsInObject(s);
238
239
if (elems--){
240
//integer (currently unknown?)
241
t_asn1Tag *num = (t_asn1Tag*)asn1ElementAtIndex(s, 0);
242
if (num->tagNumber != kASN1TagINTEGER) warning("skipping unexpected tag\n");
243
else{
244
char n = *(char*)(num+2);
245
printf("num: %d\n",n);
246
}
247
}
248
if (elems--)printHexString((t_asn1Tag*)asn1ElementAtIndex(s, 1)),putchar('\n');
249
if (elems--)printHexString((t_asn1Tag*)asn1ElementAtIndex(s, 2)),putchar('\n');
250
}
251
252
error:
253
return;
254
#undef reterror
255
}
256
257
void printNumber(t_asn1Tag *tag){
258
if (tag->tagNumber != kASN1TagINTEGER) {
259
error("tag not an INTEGER\n");
260
return;
261
}
262
t_asn1ElemLen len = asn1Len((char*)++tag);
263
uint32_t num = 0;
264
while (len.sizeBytes--) {
265
num *=0x100;
266
num += *(unsigned char*)++tag;
267
}
268
printf("%u",num);
269
}
270
271
void printIM4P(char *buf){
272
#define reterror(a ...){error(a);goto error;}
273
274
char *magic;
275
size_t l;
276
getSequenceName(buf, &magic, &l);
277
if (strncmp("IM4P", magic, l)) reterror("unexpected \"%.*s\", expected \"IM4P\"\n",(int)l,magic);
278
279
int elems = asn1ElementsInObject(buf);
280
if (--elems>0) printStringWithKey("type: ",(t_asn1Tag*)asn1ElementAtIndex(buf, 1));
281
if (--elems>0) printStringWithKey("desc: ",(t_asn1Tag*)asn1ElementAtIndex(buf, 2));
282
if (--elems>0) {
283
//data
284
t_asn1Tag *data = (t_asn1Tag*)asn1ElementAtIndex(buf, 3);
285
if (data->tagNumber != kASN1TagOCTET) warning("skipped an unexpected tag where OCTETSTING was expected\n");
286
else printf("size: 0x%08zx\n",asn1Len((char*)data+1).dataLen);
287
}
288
if (--elems>0) {
289
//kbag values
290
printf("\nKBAG\n");
291
printKBAGOctet((char*)asn1ElementAtIndex(buf, 4));
292
}else{
293
printf("\nIM4P does not contain KBAG values\n");
294
}
295
296
error:
297
return;
298
#undef reterror
299
}
300
301
char* extractPayloadFromIM4P(const char* buf, const char** compname, size_t *len) {
302
int elems = asn1ElementsInObject(buf);
303
if (elems < 4) {
304
error("not enough elements in SEQUENCE: %d", elems);
305
return NULL;
306
}
307
308
char *name = NULL;
309
size_t namelen = 0;
310
char *krnl_tag = asn1ElementAtIndex(buf, 1);
311
char *rv = ans1GetString(krnl_tag, &name, &namelen);
312
313
if (rv == NULL || namelen != 4 || strncmp(name, "krnl", 4) != 0) {
314
printf("Not a krnl\n");
315
return NULL;
316
}
317
318
char *dataTag = asn1ElementAtIndex(buf, 3)+1;
319
t_asn1ElemLen dlen = asn1Len(dataTag);
320
char *data = dataTag+dlen.sizeBytes;
321
322
char *kernel = NULL;
323
const char* comp = NULL;
324
325
if (strncmp(data, "complzss", 8) == 0) {
326
comp = "lzss";
327
kernel = tryLZSS(data, len);
328
} else if (strncmp(data, "bvx2", 4) == 0) {
329
comp = "lzfse";
330
#ifndef IMG4TOOL_NOLZFSE
331
char *compTag = data + dlen.dataLen;
332
char *fakeCompSizeTag = asn1ElementAtIndex(compTag, 0);
333
char *uncompSizeTag = asn1ElementAtIndex(compTag, 1);
334
335
size_t fake_src_size = ans1GetNumberFromTag(asn1Tag(fakeCompSizeTag));
336
size_t dst_size = ans1GetNumberFromTag(asn1Tag(uncompSizeTag));
337
338
size_t src_size = dlen.dataLen;
339
340
if (fake_src_size != 1) {
341
printf("fake_src_size not 1 but 0x%zx!\n", fake_src_size);
342
}
343
344
kernel = malloc(dst_size);
345
346
size_t uncomp_size = lzfse_decode_buffer(
347
(uint8_t*) kernel, dst_size,
348
(uint8_t*) data, src_size,
349
NULL);
350
351
if (uncomp_size != dst_size) {
352
printf("expected to decompress %zu bytes but only got %zu\n", dst_size, uncomp_size);
353
free(kernel);
354
kernel = NULL;
355
} else {
356
*len = dst_size;
357
}
358
#else
359
printf("Can't unpack data because img4tool was compiled without lzfse!\n");
360
#endif
361
}
362
363
*compname = comp;
364
return kernel;
365
}
366
367
/*
368
int extractFileFromIM4P(char *buf, const char *dstFilename){
369
int elems = asn1ElementsInObject(buf);
370
if (elems < 4){
371
error("not enough elements in SEQUENCE %d\n",elems);
372
return -2;
373
}
374
375
376
char *dataTag = asn1ElementAtIndex(buf, 3)+1;
377
t_asn1ElemLen dlen = asn1Len(dataTag);
378
char *data = dataTag+dlen.sizeBytes;
379
380
char* kernel = NULL;
381
{
382
size_t kernel_len = 0;
383
const char* compname = NULL;
384
kernel = extractPayloadFromIM4P(buf, &compname, &kernel_len);
385
386
if (compname != NULL) {
387
printf("Kernelcache detected, uncompressing (%s): %s\n", compname, kernel ? "ok" : "failure");
388
}
389
390
if (kernel != NULL) {
391
data = kernel;
392
dlen.dataLen = kernel_len;
393
}
394
}
395
396
FILE *f = fopen(dstFilename, "wb");
397
if (!f) {
398
error("can't open file %s\n",dstFilename);
399
return -1;
400
}
401
fwrite(data, dlen.dataLen, 1, f);
402
fclose(f);
403
404
if (kernel)
405
free(kernel);
406
407
return 0;
408
}
409
*/
410
411
int sequenceHasName(const char *buf, char *name){
412
char *magic;
413
size_t l;
414
int err = getSequenceName(buf, &magic, &l);
415
return !err && strncmp(name, magic, l) == 0;
416
}
417
418
char *getElementFromIMG4(char *buf, char* element){
419
#define reterror(a ...) return (error(a),NULL)
420
if (!sequenceHasName(buf, "IMG4")) reterror("not img4 sequcence\n");
421
422
int elems = asn1ElementsInObject(buf);
423
for (int i=0; i<elems; i++) {
424
425
char *elemen = asn1ElementAtIndex(buf, i);
426
427
if (asn1Tag(elemen)->tagNumber != kASN1TagSEQUENCE && asn1Tag(elemen)->tagClass == kASN1TagClassContextSpecific) {
428
//assuming we found a "subcontainer"
429
elemen += asn1Len((char*)elemen+1).sizeBytes+1;
430
}
431
432
if (asn1Tag(elemen)->tagNumber == kASN1TagSEQUENCE && sequenceHasName(elemen, element)) {
433
return (char*)elemen;
434
}
435
}
436
reterror("element %s not found in IMG4\n",element);
437
#undef reterror
438
}
439
440
int extractElementFromIMG4(char *buf, char* element, const char *dstFilename){
441
#define reterror(a ...) return (error(a),-1)
442
443
char *elemen = getElementFromIMG4(buf, element);
444
if (!elemen) return -1;
445
FILE *f = fopen(dstFilename, "wb");
446
if (!f) {
447
error("can't open file %s\n",dstFilename);
448
return -1;
449
}
450
451
t_asn1ElemLen len = asn1Len((char*)elemen+1);
452
size_t flen = len.dataLen + len.sizeBytes +1;
453
fwrite(elemen, flen, 1, f);
454
fclose(f);
455
456
return 0;
457
#undef reterror
458
}
459
460
int asn1MakeSize(char *sizeBytesDst, size_t size){
461
int off = 0;
462
if (size >= 0x1000000) {
463
// 1+4 bytes length
464
sizeBytesDst[off++] = 0x84;
465
sizeBytesDst[off++] = (size >> 24) & 0xFF;
466
sizeBytesDst[off++] = (size >> 16) & 0xFF;
467
sizeBytesDst[off++] = (size >> 8) & 0xFF;
468
sizeBytesDst[off++] = size & 0xFF;
469
} else if (size >= 0x10000) {
470
// 1+3 bytes length
471
sizeBytesDst[off++] = 0x83;
472
sizeBytesDst[off++] = (size >> 16) & 0xFF;
473
sizeBytesDst[off++] = (size >> 8) & 0xFF;
474
sizeBytesDst[off++] = size & 0xFF;
475
} else if (size >= 0x100) {
476
// 1+2 bytes length
477
sizeBytesDst[off++] = 0x82;
478
sizeBytesDst[off++] = (size >> 8) & 0xFF;
479
sizeBytesDst[off++] = (size & 0xFF);
480
} else if (size >= 0x80) {
481
// 1+1 byte length
482
sizeBytesDst[off++] = 0x81;
483
sizeBytesDst[off++] = (size & 0xFF);
484
} else {
485
// 1 byte length
486
sizeBytesDst[off++] = size & 0xFF;
487
}
488
return off;
489
}
490
491
char *asn1PrepandTag(char *buf, t_asn1Tag tag){
492
t_asn1ElemLen len = asn1Len(buf+1);
493
494
//alloc mem for oldTag+oldSizebytes+oldData + newTag + newTagSizebytesMax
495
char *ret = malloc(len.sizeBytes + len.dataLen +1 +1+4);
496
ret[0] = *(char*)&tag;
497
int nSizeBytes = asn1MakeSize(ret+1, len.sizeBytes + len.dataLen +1);
498
memcpy(ret + nSizeBytes+1, buf, len.sizeBytes + len.dataLen +1);
499
return ret;
500
}
501
502
char *asn1AppendToTag(char *buf, char *toappend){
503
t_asn1ElemLen buflen = asn1Len(buf+1);
504
t_asn1ElemLen apndLen = asn1Len(toappend+1);
505
506
//alloc memory for bufdata + buftag + apndData + apndSizebytes + apndTag + maxSizeBytesForBuf
507
size_t containerLen;
508
char *ret = malloc(1 +(containerLen = buflen.dataLen +apndLen.sizeBytes + apndLen.dataLen +1) +4);
509
510
ret[0] = buf[0];
511
int nSizeBytes = asn1MakeSize(ret+1, containerLen);
512
//copy old data
513
memcpy(ret + nSizeBytes+1, buf+1+buflen.sizeBytes, buflen.dataLen);
514
515
516
memcpy(ret +nSizeBytes+1+ buflen.dataLen, toappend, apndLen.sizeBytes +apndLen.dataLen +1);
517
free(buf);
518
519
return ret;
520
}
521
522
char *makeIM4RWithNonce(char *nonce){
523
char template[] = {0xA1, 0x23, 0x30, 0x21, 0x16, 0x04, 0x49, 0x4D,
524
0x34, 0x52, 0x31, 0x19, 0xFF, 0x84, 0x92, 0xB9,
525
0x86, 0x4E, 0x12, 0x30, 0x10, 0x16, 0x04, 0x42,
526
0x4E, 0x43, 0x4E, 0x04, 0x08};
527
char *ret = malloc(sizeof(template)+8);
528
strncpy(ret, template,sizeof(template));
529
strncpy(ret+sizeof(template), nonce, 8);
530
return ret;
531
}
532
/*
533
534
char *makeIMG4(char *im4p, char *im4m, char *im4r, size_t *size){
535
t_asn1Tag elem0;
536
elem0.tagNumber = 0;
537
elem0.tagClass = kASN1TagClassContextSpecific;
538
elem0.isConstructed = 1;
539
if (im4m) im4m = asn1PrepandTag(im4m, elem0);
540
541
char *sequence = malloc(2);
542
sequence[0] = 0x30;
543
sequence[1] = 0x00;
544
545
char iA5String_IMG4[] = {0x16, 0x04, 0x49, 0x4D, 0x47, 0x34};
546
547
sequence = asn1AppendToTag(sequence, iA5String_IMG4);
548
if (im4p) sequence = asn1AppendToTag(sequence, im4p);
549
if (im4m) sequence = asn1AppendToTag(sequence, im4m);
550
if (im4r) {
551
char *noncebuf = makeIM4RWithNonce(im4r);
552
sequence = asn1AppendToTag(sequence, noncebuf);
553
free(noncebuf);
554
}
555
556
if (size){
557
t_asn1ElemLen retlen = asn1Len(sequence+1);
558
*size = 1+ retlen.dataLen + retlen.sizeBytes;
559
}
560
free(im4m); //only freeing local copy, not actually freeing outside im4m buffer
561
562
return sequence;
563
}
564
565
int replaceNameInIM4P(char *buf, const char *newName){
566
567
if (asn1ElementsInObject(buf)<2){
568
error("not enough objects in sequence\n");
569
return -1;
570
}
571
572
char *nameTag = asn1ElementAtIndex(buf, 1);
573
574
if (asn1Tag(nameTag)->tagNumber != kASN1TagIA5String){
575
error("nameTag is not IA5String\n");
576
return -2;
577
}
578
t_asn1ElemLen len;
579
if ((len = asn1Len(nameTag+1)).dataLen !=4){
580
error("nameTag has not a length of 4 Bytes, actual len=%ld\n",len.dataLen);
581
return -2;
582
}
583
584
memmove(nameTag + 1 + len.sizeBytes, newName, 4);
585
586
return 0;
587
}
588
589
590
char *getValueForTagInSet(char *set, uint32_t tag){
591
#define reterror(a) return (error(a),NULL)
592
593
if (((t_asn1Tag*)set)->tagNumber != kASN1TagSET) reterror("not a SET\n");
594
t_asn1ElemLen setlen = asn1Len(++set);
595
596
for (char *setelems = set+setlen.sizeBytes; setelems<set+setlen.dataLen;) {
597
598
if (*(unsigned char*)setelems == 0xff) {
599
//priv tag
600
size_t sb;
601
size_t ptag = asn1GetPrivateTagnum((t_asn1Tag*)setelems,&sb);
602
setelems += sb;
603
t_asn1ElemLen len = asn1Len(setelems);
604
setelems += len.sizeBytes;
605
if (tag == ptag) return setelems;
606
setelems +=len.dataLen;
607
}else{
608
//normal tag
609
t_asn1ElemLen len = asn1Len(setelems);
610
setelems += len.sizeBytes + 1;
611
if (((t_asn1Tag*)setelems)->tagNumber == tag) return setelems;
612
setelems += len.dataLen;
613
}
614
}
615
return 0;
616
#undef reterror
617
}
618
619
void printElemsInIMG4(char *buf, bool printAll, bool im4pOnly){
620
#define reterror(a...) {error(a); goto error;}
621
char *magic;
622
size_t l;
623
getSequenceName(buf, &magic, &l);
624
if (strncmp("IMG4", magic, l)) reterror("unexpected \"%.*s\", expected \"IMG4\"\n",(int)l,magic);
625
printf("IMG4:\n");
626
int elems = asn1ElementsInObject(buf);
627
628
for (int i=1; i<elems; i++) {
629
char *tag = (char*)asn1ElementAtIndex(buf, i);
630
631
if (((t_asn1Tag*)tag)->tagClass == kASN1TagClassContextSpecific) {
632
tag += asn1Len((char*)tag+1).sizeBytes +1;
633
}
634
635
char *magic = 0;
636
size_t l;
637
getSequenceName((char*)tag, &magic, &l);
638
639
putStr(magic, l);printf(": ---------\n");
640
641
if (!im4pOnly && strncmp("IM4R", magic, l) == 0) printIM4R(tag);
642
if (!im4pOnly && strncmp("IM4M", magic, l) == 0) printIM4M(tag,printAll);
643
if (strncmp("IM4P", magic, l) == 0) printIM4P(tag);
644
putchar('\n');
645
}
646
647
error:
648
return;
649
#undef reterror
650
}
651
652
653
void printIM4R(char *buf){
654
#define reterror(a ...){error(a);goto error;}
655
656
char *magic;
657
size_t l;
658
getSequenceName(buf, &magic, &l);
659
if (strncmp("IM4R", magic, l)) reterror("unexpected \"%.*s\", expected \"IM4R\"\n",(int)l,magic);
660
661
int elems = asn1ElementsInObject(buf);
662
if (elems<2) reterror("expecting at least 2 elements\n");
663
664
t_asn1Tag *set = (t_asn1Tag*)asn1ElementAtIndex(buf, 1);
665
if (set->tagNumber != kASN1TagSET) reterror("expecting SET type\n");
666
667
set += asn1Len((char*)set+1).sizeBytes+1;
668
669
if (set->tagClass != kASN1TagClassPrivate) reterror("expecting PRIVATE type\n");
670
671
printPrivtag(asn1GetPrivateTagnum(set++,0));
672
printf("\n");
673
674
set += asn1Len((char*)set).sizeBytes+1;
675
elems = asn1ElementsInObject((char*)set);
676
if (elems<2) reterror("expecting at least 2 elements\n");
677
678
printI5AString((t_asn1Tag*)asn1ElementAtIndex((char*)set, 0));
679
printf(": ");
680
printHexString((t_asn1Tag*)asn1ElementAtIndex((char*)set, 1));
681
putchar('\n');
682
683
error:
684
return;
685
#undef reterror
686
}
687
688
char *getIM4PFromIMG4(char *buf){
689
char *magic;
690
size_t l;
691
getSequenceName(buf, &magic, &l);
692
if (strncmp("IMG4", magic, l)) return error("unexpected \"%.*s\", expected \"IMG4\"\n",(int)l,magic),NULL;
693
if (asn1ElementsInObject(buf)<2) return error("not enough elements in SEQUENCE"),NULL;
694
char *ret = (char*)asn1ElementAtIndex(buf, 1);
695
getSequenceName(ret, &magic, &l);
696
return (strncmp("IM4P", magic, 4) == 0) ? ret : (error("unexpected \"%.*s\", expected \"IM4P\"\n",(int)l,magic),NULL);
697
}
698
699
char *getIM4MFromIMG4(char *buf){
700
char *magic;
701
size_t l;
702
getSequenceName(buf, &magic, &l);
703
if (strncmp("IMG4", magic, l)) return error("unexpected \"%.*s\", expected \"IMG4\"\n",(int)l,magic),NULL;
704
if (asn1ElementsInObject(buf)<3) return error("not enough elements in SEQUENCE"),NULL;
705
char *ret = (char*)asn1ElementAtIndex(buf, 2);
706
if (((t_asn1Tag*)ret)->tagClass != kASN1TagClassContextSpecific) return error("unexpected Tag 0x%02x, expected SET\n",*(unsigned char*)ret),NULL;
707
ret += asn1Len(ret+1).sizeBytes + 1;
708
getSequenceName(ret, &magic, &l);
709
return (strncmp("IM4M", magic, 4) == 0) ? ret : NULL;
710
}
711
712
void printIM4M(char *buf, bool printAll){
713
#define reterror(a ...){error(a);goto error;}
714
715
char *magic;
716
size_t l;
717
getSequenceName(buf, &magic, &l);
718
if (strncmp("IM4M", magic, l)) reterror("unexpected \"%.*s\", expected \"IM4M\"\n",(int)l,magic);
719
720
int elems = asn1ElementsInObject(buf);
721
if (elems<2) reterror("expecting at least 2 elements\n");
722
723
if (--elems>0) {
724
printf("Version: ");
725
printNumber((t_asn1Tag*)asn1ElementAtIndex(buf, 1));
726
putchar('\n');
727
}
728
if (--elems>0) {
729
t_asn1Tag *manbset = (t_asn1Tag*)asn1ElementAtIndex(buf, 2);
730
if (manbset->tagNumber != kASN1TagSET) reterror("expecting SET\n");
731
732
t_asn1Tag *privtag = manbset + asn1Len((char*)manbset+1).sizeBytes+1;
733
size_t sb;
734
printPrivtag(asn1GetPrivateTagnum(privtag++,&sb));
735
printf("\n");
736
char *manbseq = (char*)privtag+sb;
737
manbseq+= asn1Len(manbseq).sizeBytes+1;
738
printMANB(manbseq, printAll);
739
if (!printAll) return;
740
}
741
742
error:
743
return;
744
#undef reterror
745
}
746
747
void asn1PrintValue(t_asn1Tag *tag){
748
if (tag->tagNumber == kASN1TagIA5String){
749
printI5AString(tag);
750
}else if (tag->tagNumber == kASN1TagOCTET){
751
printHexString(tag);
752
}else if (tag->tagNumber == kASN1TagINTEGER){
753
t_asn1ElemLen len = asn1Len((char*)tag+1);
754
unsigned char *num = (unsigned char*)tag+1 + len.sizeBytes;
755
uint64_t pnum = 0;
756
while (len.dataLen--) {
757
pnum *=0x100;
758
pnum += *num++;
759
760
//ungly workaround for WIN32
761
if (sizeof(uint64_t) != 8) printf("%02x",num[-1]);
762
763
}
764
if (sizeof(uint64_t) == 8) printf("%llu",pnum);
765
else printf(" (hex)");
766
}else if (tag->tagNumber == kASN1TagBOOLEAN){
767
printf("%s",(*(char*)tag+2 == 0) ? "false" : "true");
768
}else{
769
error("can't print unknown tag %02x\n",*(unsigned char*)tag);
770
}
771
}
772
773
void asn1PrintRecKeyVal(char *buf){
774
775
if (((t_asn1Tag*)buf)->tagNumber == kASN1TagSEQUENCE) {
776
int i;
777
if ((i = asn1ElementsInObject(buf)) != 2){
778
error("expecting 2 elements found %d\n",i);
779
return;
780
}
781
printI5AString((t_asn1Tag*)asn1ElementAtIndex(buf, 0));
782
printf(": ");
783
asn1PrintRecKeyVal(asn1ElementAtIndex(buf, 1));
784
printf("\n");
785
return;
786
}else if (((t_asn1Tag*)buf)->tagNumber != kASN1TagSET){
787
asn1PrintValue((t_asn1Tag *)buf);
788
return;
789
}
790
791
792
//must be a SET
793
printf("------------------------------\n");
794
for (int i = 0; i<asn1ElementsInObject(buf); i++) {
795
char *elem = (char*)asn1ElementAtIndex(buf, i);
796
size_t sb;
797
printPrivtag(asn1GetPrivateTagnum((t_asn1Tag*)elem,&sb));
798
printf(": ");
799
elem+=sb;
800
elem += asn1Len(elem+1).sizeBytes;
801
asn1PrintRecKeyVal(elem);
802
}
803
804
}
805
806
void printMANB(char *buf, bool printAll){
807
#define reterror(a ...){error(a);goto error;}
808
809
char *magic;
810
size_t l;
811
getSequenceName(buf, &magic, &l);
812
if (strncmp("MANB", magic, l)) reterror("unexpected \"%.*s\", expected \"MANB\"\n",(int)l,magic);
813
814
int manbElemsCnt = asn1ElementsInObject(buf);
815
if (manbElemsCnt<2) reterror("not enough elements in MANB\n");
816
char *manbSeq = (char*)asn1ElementAtIndex(buf, 1);
817
818
for (int i=0; i<asn1ElementsInObject(manbSeq); i++) {
819
t_asn1Tag *manbElem = (t_asn1Tag*)asn1ElementAtIndex(manbSeq, i);
820
size_t privTag = 0;
821
if (*(char*)manbElem == kASN1TagPrivate) {
822
size_t sb;
823
printPrivtag(privTag = asn1GetPrivateTagnum(manbElem,&sb));
824
printf(": ");
825
manbElem+=sb;
826
}else manbElem++;
827
828
manbElem += asn1Len((char*)manbElem).sizeBytes;
829
830
asn1PrintRecKeyVal((char*)manbElem);
831
if (!printAll && strncmp((char*)&privTag, "PNAM", 4) == 0){
832
break;
833
}
834
}
835
836
837
error:
838
return;
839
#undef reterror
840
}
841
842
843
char *getSHA1ofSqeuence(char * buf){
844
if (((t_asn1Tag*)buf)->tagNumber != kASN1TagSEQUENCE){
845
error("tag not seuqnece");
846
return 0;
847
}
848
t_asn1ElemLen bLen = asn1Len(buf+1);
849
size_t buflen = 1 + bLen.dataLen + bLen.sizeBytes;
850
char *ret = malloc(SHA_DIGEST_LENGTH);
851
if (ret)
852
SHA1((unsigned char*)buf, (unsigned int)buflen, (unsigned char *)ret);
853
854
return ret;
855
}
856
857
*/
858
859
/*int hasBuildidentityElementWithHash(plist_t identity, char *hash, uint64_t hashSize){*/
860
/*#define reterror(a ...){rt=0;error(a);goto error;}*/
861
/*#define skipelem(e) if (strcmp(key, e) == 0) {[>warning("skipping element=%s\n",key);<]goto skip;} //seems to work as it is, we don't need to see that warning anymore*/
862
863
/*int rt = 0;*/
864
/*plist_dict_iter dictIterator = NULL;*/
865
866
/*plist_t manifest = plist_dict_get_item(identity, "Manifest");*/
867
/*if (!manifest)*/
868
/*reterror("can't find Manifest\n");*/
869
870
/*plist_t node = NULL;*/
871
/*char *key = NULL;*/
872
/*plist_dict_new_iter(manifest, &dictIterator);*/
873
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
874
/*do {*/
875
/*skipelem("BasebandFirmware")*/
876
/*skipelem("ftap")*/
877
/*skipelem("ftsp")*/
878
/*skipelem("rfta")*/
879
/*skipelem("rfts")*/
880
/*skipelem("SE,Bootloader")*/
881
/*skipelem("SE,Firmware")*/
882
/*skipelem("SE,MigrationOS")*/
883
/*skipelem("SE,OS")*/
884
/*skipelem("SE,UpdatePayload")*/
885
886
/*plist_t digest = plist_dict_get_item(node, "Digest");*/
887
/*if (!digest || plist_get_node_type(digest) != PLIST_DATA)*/
888
/*reterror("can't find digest for key=%s\n",key);*/
889
890
/*char *dgstData = NULL;*/
891
/*uint64_t len = 0;*/
892
/*plist_get_data_val(digest, &dgstData, &len);*/
893
/*if (!dgstData)*/
894
/*reterror("can't get dgstData for key=%s.\n",key);*/
895
896
/*if (len == hashSize && memcmp(dgstData, hash, len) == 0)*/
897
/*rt = 1;*/
898
899
/*free(dgstData);*/
900
/*skip:*/
901
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
902
/*} while (!rt && node);*/
903
/*error:*/
904
/*free(dictIterator),dictIterator = NULL;*/
905
/*return rt;*/
906
/*#undef skipelem*/
907
/*#undef reterror*/
908
/*}*/
909
910
/*plist_t findAnyBuildidentityForFilehash(plist_t identities, char *hash, uint64_t hashSize){*/
911
/*#define skipelem(e) if (strcmp(key, e) == 0) {[>warning("skipping element=%s\n",key);<]goto skip;} //seems to work as it is, we don't need to see that warning anymore*/
912
/*#define reterror(a ...){rt=NULL;error(a);goto error;}*/
913
/*plist_t rt = NULL;*/
914
/*plist_dict_iter dictIterator = NULL;*/
915
916
/*for (int i=0; !rt && i<plist_array_get_size(identities); i++) {*/
917
/*plist_t idi = plist_array_get_item(identities, i);*/
918
919
/*plist_t manifest = plist_dict_get_item(idi, "Manifest");*/
920
/*if (!manifest)*/
921
/*reterror("can't find Manifest. i=%d\n",i);*/
922
923
/*plist_t node = NULL;*/
924
/*char *key = NULL;*/
925
/*plist_dict_new_iter(manifest, &dictIterator);*/
926
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
927
/*do {*/
928
/*skipelem("BasebandFirmware")*/
929
/*skipelem("ftap")*/
930
/*skipelem("ftsp")*/
931
/*skipelem("rfta")*/
932
/*skipelem("rfts")*/
933
934
/*plist_t digest = plist_dict_get_item(node, "Digest");*/
935
/*if (!digest || plist_get_node_type(digest) != PLIST_DATA)*/
936
/*reterror("can't find digest for key=%s. i=%d\n",key,i);*/
937
938
/*char *dgstData = NULL;*/
939
/*uint64_t len = 0;*/
940
/*plist_get_data_val(digest, &dgstData, &len);*/
941
/*if (!dgstData)*/
942
/*reterror("can't get dgstData for key=%s. i=%d\n",key,i);*/
943
944
/*if (len == hashSize && memcmp(dgstData, hash, len) == 0)*/
945
/*rt = idi;*/
946
947
/*free(dgstData);*/
948
/*skip:*/
949
/*plist_dict_next_item(manifest, dictIterator, &key, &node);*/
950
/*} while (!rt && node);*/
951
952
/*free(dictIterator),dictIterator = NULL;*/
953
/*}*/
954
955
/*error:*/
956
/*if (dictIterator) free(dictIterator);*/
957
/*return rt;*/
958
/*#undef reterror*/
959
/*#undef skipelem*/
960
/*}*/
961
962
/*int doForDGSTinIM4M(const char *im4m, void *state, int (*loop_cb)(char elemNameStr[4], char *dgstData, size_t dgstDataLen, void *state)){*/
963
/*int err = 0;*/
964
/*#define reterror(code, msg ...) do {error(msg);err=code;goto error;}while(0)*/
965
966
/*if (!sequenceHasName(im4m, "IM4M"))*/
967
/*reterror(-1,"can't find IM4M tag\n");*/
968
969
/*char *im4mset = (char *)asn1ElementAtIndex(im4m, 2);*/
970
/*if (!im4mset)*/
971
/*reterror(-2,"can't find im4mset\n");*/
972
/*char *manbSeq = getValueForTagInSet(im4mset, *(uint32_t*)"BNAM");*/
973
/*if (!manbSeq)*/
974
/*reterror(-3,"can't find manbSeq\n");*/
975
976
/*char *manbSet = (char*)asn1ElementAtIndex(manbSeq, 1);*/
977
/*if (!manbSet)*/
978
/*reterror(-4,"can't find manbSet\n");*/
979
980
/*for (int i=0; i<asn1ElementsInObject(manbSet); i++) {*/
981
/*char *curr = asn1ElementAtIndex(manbSet, i);*/
982
983
/*size_t sb;*/
984
/*if (asn1GetPrivateTagnum((t_asn1Tag*)curr, &sb) == *(uint32_t*)"PNAM")*/
985
/*continue;*/
986
/*char *cSeq = (char*)curr+sb;*/
987
/*cSeq += asn1Len(cSeq).sizeBytes;*/
988
989
/*char *elemName = asn1ElementAtIndex(cSeq, 0);*/
990
/*t_asn1ElemLen elemNameLen = asn1Len(elemName+1);*/
991
/*char *elemNameStr = elemName + elemNameLen.sizeBytes+1;*/
992
993
/*char *elemSet = (char*)asn1ElementAtIndex(cSeq, 1);*/
994
/*if (!elemSet)*/
995
/*reterror(-5, "can't find elemSet. i=%d\n",i);*/
996
997
/*char *dgstSeq = getValueForTagInSet(elemSet, *(uint32_t*)"TSGD");*/
998
/*if (!dgstSeq)*/
999
/*reterror(-6, "can't find dgstSeq. i=%d\n",i);*/
1000
1001
1002
/*char *dgst = asn1ElementAtIndex(dgstSeq, 1);*/
1003
/*if (!dgst || asn1Tag(dgst)->tagNumber != kASN1TagOCTET)*/
1004
/*reterror(-7, "can't find DGST. i=%d\n",i);*/
1005
1006
/*t_asn1ElemLen lenDGST = asn1Len((char*)dgst+1);*/
1007
/*char *dgstData = (char*)dgst+lenDGST.sizeBytes+1;*/
1008
1009
1010
/*if ((err = loop_cb(elemNameStr, dgstData, lenDGST.dataLen, state))){*/
1011
/*if (err > 0){ //restart loop if err > 0*/
1012
/*i = -1;*/
1013
/*err = 0;*/
1014
/*continue;*/
1015
/*}*/
1016
/*break;*/
1017
/*}*/
1018
/*}*/
1019
1020
/*error:*/
1021
/*return err;*/
1022
/*#undef reterror*/
1023
/*}*/
1024
1025
1026
/*int im4m_buildidentity_check_cb(char elemNameStr[4], char *dgstData, size_t dgstDataLen, struct {plist_t rt; plist_t identities;} *state){*/
1027
/*#define skipelem(e) if (strncmp(e, elemNameStr,4) == 0) return 0*/
1028
/*skipelem("ftsp");*/
1029
/*skipelem("ftap");*/
1030
/*skipelem("rfta");*/
1031
/*skipelem("rfts");*/
1032
1033
/*if (state->rt){*/
1034
/*if (!hasBuildidentityElementWithHash(state->rt, dgstData, dgstDataLen)){*/
1035
/*//remove identity we are not looking for and start comparing all hashes again*/
1036
/*plist_array_remove_item(state->identities, plist_array_get_item_index(state->rt));*/
1037
/*state->rt = NULL;*/
1038
/*return 1; //trigger loop restart*/
1039
/*}*/
1040
/*}else{*/
1041
/*if (!(state->rt = findAnyBuildidentityForFilehash(state->identities, dgstData, dgstDataLen)))*/
1042
/*return (error("can't find any identity which matches all hashes inside IM4M\n"),-1);*/
1043
1044
/*}*/
1045
1046
/*#undef skipelem*/
1047
/*return 0;*/
1048
/*}*/
1049
1050
/*plist_t getBuildIdentityForIM4M(const char *buf, const plist_t buildmanifest){*/
1051
/*#define reterror(a ...){state.rt=NULL;error(a);goto error;}*/
1052
/*#define skipelem(e) if (strncmp(elemNameStr, e, 4) == 0) {[>warning("skipping element=%s\n",e);<]continue;} //seems to work as it is, we don't need to see that warning anymore*/
1053
1054
/*plist_t manifest = plist_copy(buildmanifest);*/
1055
1056
/*struct {plist_t rt; plist_t identities;} state;*/
1057
/*state.rt = NULL;*/
1058
1059
/*state.identities = plist_dict_get_item(manifest, "BuildIdentities");*/
1060
/*if (!state.identities)*/
1061
/*reterror("can't find BuildIdentities\n");*/
1062
1063
1064
/*doForDGSTinIM4M(buf, (void*)&state, (int (*)(char[4], char *, size_t, void *))im4m_buildidentity_check_cb);*/
1065
1066
/*plist_t finfo = plist_dict_get_item(state.rt, "Info");*/
1067
/*plist_t fdevclass = plist_dict_get_item(finfo, "DeviceClass");*/
1068
/*plist_t fresbeh = plist_dict_get_item(finfo, "RestoreBehavior");*/
1069
1070
/*if (!finfo || !fdevclass || !fresbeh)*/
1071
/*reterror("found buildidentiy, but can't read information\n");*/
1072
1073
/*plist_t origIdentities = plist_dict_get_item(buildmanifest, "BuildIdentities");*/
1074
1075
/*for (int i=0; i<plist_array_get_size(origIdentities); i++) {*/
1076
/*plist_t curr = plist_array_get_item(origIdentities, i);*/
1077
1078
/*plist_t cinfo = plist_dict_get_item(curr, "Info");*/
1079
/*plist_t cdevclass = plist_dict_get_item(cinfo, "DeviceClass");*/
1080
/*plist_t cresbeh = plist_dict_get_item(cinfo, "RestoreBehavior");*/
1081
1082
/*if (plist_compare_node_value(cresbeh, fresbeh) && plist_compare_node_value(cdevclass, fdevclass)) {*/
1083
/*state.rt = curr;*/
1084
/*goto error;*/
1085
/*}*/
1086
/*}*/
1087
/*//fails if loop ended without jumping to error*/
1088
/*reterror("found indentity, but failed to match it with orig copy\n");*/
1089
1090
/*error:*/
1091
/*plist_free(manifest);*/
1092
/*return state.rt;*/
1093
/*#undef reterror*/
1094
/*}*/
1095
1096
/*void printGeneralBuildIdentityInformation(plist_t buildidentity){*/
1097
/*plist_t info = plist_dict_get_item(buildidentity, "Info");*/
1098
/*plist_dict_iter iter = NULL;*/
1099
/*plist_dict_new_iter(info, &iter);*/
1100
1101
/*plist_type t;*/
1102
/*plist_t node = NULL;*/
1103
/*char *key = NULL;*/
1104
1105
/*while (plist_dict_next_item(info, iter, &key, &node),node) {*/
1106
/*char *str = NULL;*/
1107
/*switch (t = plist_get_node_type(node)) {*/
1108
/*case PLIST_STRING:*/
1109
/*plist_get_string_val(node, &str);*/
1110
/*printf("%s : %s\n",key,str);*/
1111
/*break;*/
1112
/*case PLIST_BOOLEAN:*/
1113
/*plist_get_bool_val(node, (uint8_t*)&t);*/
1114
/*printf("%s : %s\n",key,((uint8_t)t) ? "YES" : "NO" );*/
1115
/*default:*/
1116
/*break;*/
1117
/*}*/
1118
/*if (str) free(str);*/
1119
/*}*/
1120
/*if (iter) free(iter);*/
1121
/*}*/
1122
1123
/*int verify_signature(char *data, char *sig, char *certificate, int useSHA384){*/
1124
/*#ifndef IMG4TOOL_NOOPENSSL*/
1125
/*//return 0 if signature valid, 1 if invalid, <0 if error occured*/
1126
/*int err = 0;*/
1127
/*EVP_MD_CTX *mdctx = NULL;*/
1128
/*#define reterror(a ...){err=1;error(a);goto error;}*/
1129
1130
/*t_asn1ElemLen dataSize = asn1Len(data+1);*/
1131
/*t_asn1ElemLen sigSize = asn1Len(sig+1);*/
1132
/*t_asn1ElemLen certSize = asn1Len(certificate+1);*/
1133
1134
/*X509 *cert = d2i_X509(NULL, (const unsigned char**)&certificate, certSize.dataLen + certSize.sizeBytes + 1);*/
1135
/*EVP_PKEY *certpubkey = X509_get_pubkey(cert);*/
1136
1137
/*retassure(-1, mdctx = EVP_MD_CTX_create());*/
1138
1139
/*retassure(-2, EVP_DigestVerifyInit(mdctx, NULL, (useSHA384) ? EVP_sha384() : EVP_sha1(), NULL, certpubkey) == 1);*/
1140
1141
/*retassure(-3,EVP_DigestVerifyUpdate(mdctx, data, dataSize.dataLen + dataSize.sizeBytes +1) == 1);*/
1142
1143
/*err = (EVP_DigestVerifyFinal(mdctx, (unsigned char*)sig+1 + sigSize.sizeBytes, sigSize.dataLen) != 1);*/
1144
1145
/*error:*/
1146
/*if(mdctx) EVP_MD_CTX_destroy(mdctx);*/
1147
/*return err;*/
1148
/*#undef reterror*/
1149
/*#else*/
1150
/*printf("[FATAL!] can't verify signature, because img4tool was compiled without openssl\n");*/
1151
/*return 0;*/
1152
/*#endif*/
1153
/*}*/
1154
1155
/*int find_dgst_cb(char elemNameStr[4], char *dgstData, size_t dgstDataLen, void *state){*/
1156
/*return memcmp(dgstData, state, dgstDataLen) == 0 ? -255 : 0; //-255 is not an error in this case, but indicates that we found our hash*/
1157
/*}*/
1158
1159
/*int verifyIM4MSignature(const char *buf){*/
1160
/*int err = 0;*/
1161
/*#define reterror(code,a ...){error(a);err=code;goto error;}*/
1162
1163
/*retassure(-1,asn1ElementsInObject(buf) == 5);*/
1164
/*char *im4m = asn1ElementAtIndex(buf, 2);*/
1165
/*char *sig = asn1ElementAtIndex(buf, 3);*/
1166
/*char *certs = asn1ElementAtIndex(buf, 4);*/
1167
1168
/*int elems = 0;*/
1169
/*retassure(-2, (elems = asn1ElementsInObject(certs)) >=1); //iPhone7 has 1 cert, while pre-iPhone7 have 2 certs*/
1170
1171
/*// char *bootAuthority = asn1ElementAtIndex(certs, 0); //does not exist on iPhone7*/
1172
/*char *tssAuthority = asn1ElementAtIndex(certs, elems-1); //is always last item*/
1173
1174
/*err = verify_signature(im4m, sig, tssAuthority, elems < 2); //use SHA384 if elems is 2 otherwise use SHA1*/
1175
1176
/*error:*/
1177
/*return err;*/
1178
/*#undef reterror*/
1179
/*}*/
1180
1181
/*char *getBNCHFromIM4M(const char* im4m, size_t *nonceSize){*/
1182
/*#define reterror(a ...){error(a);ret=NULL;goto error;}*/
1183
/*char *ret = NULL;*/
1184
/*char *mainSet = NULL;*/
1185
/*char *manbSet = NULL;*/
1186
/*char *manpSet = NULL;*/
1187
/*char *nonceOctet = NULL;*/
1188
/*char *bnch = NULL;*/
1189
/*size_t bnchSize = 0;*/
1190
/*char *manb = NULL;*/
1191
/*char *manp = NULL;*/
1192
/*char *certs = NULL;*/
1193
1194
/*if (!im4m) reterror("Got empty IM4M\n");*/
1195
1196
/*if (asn1ElementsInObject(im4m) != 5) {*/
1197
/*error("unexpected number of Elements (%d) in IM4M sequence\n", asn1ElementsInObject(im4m));*/
1198
/*goto error;*/
1199
/*}*/
1200
/*mainSet = asn1ElementAtIndex(im4m, 2);*/
1201
/*certs = asn1ElementAtIndex(im4m, 4);*/
1202
1203
/*manb = getValueForTagInSet((char*)mainSet, *(uint32_t*)"BNAM"); //MANB priv Tag*/
1204
/*if (asn1ElementsInObject(manb)< 2){*/
1205
/*error("unexpected number of Elements in MANB sequence\n");*/
1206
/*goto error;*/
1207
/*}*/
1208
/*manbSet = asn1ElementAtIndex(manb, 1);*/
1209
1210
/*manp = getValueForTagInSet((char*)manbSet, *(uint32_t*)"PNAM"); //MANP priv Tag*/
1211
/*if (asn1ElementsInObject(manp)< 2){*/
1212
/*error("unexpected number of Elements in MANP sequence\n");*/
1213
/*goto error;*/
1214
/*}*/
1215
/*manpSet = asn1ElementAtIndex(manp, 1);*/
1216
1217
/*bnch = getValueForTagInSet((char*)manpSet, *(uint32_t*)"HCNB"); //BNCH priv Tag*/
1218
/*if (asn1ElementsInObject(bnch)< 2){*/
1219
/*error("unexpected number of Elements in BNCH sequence\n");*/
1220
/*goto error;*/
1221
/*}*/
1222
/*nonceOctet = (char*)asn1ElementAtIndex(bnch, 1);*/
1223
/*nonceOctet++;*/
1224
1225
/*ret = nonceOctet + asn1Len(nonceOctet).sizeBytes;*/
1226
/*bnchSize = asn1Len(nonceOctet).dataLen;*/
1227
/*// iPhone 7 and above use 32 byte nonce*/
1228
/*if (bnchSize != (asn1ElementsInObject(certs) == 1 ? 32 : 20)) {*/
1229
/*reterror("BNCH size incorrect\n");*/
1230
/*}*/
1231
/*if (nonceSize) *nonceSize = bnchSize;*/
1232
1233
/*error:*/
1234
/*return ret;*/
1235
/*#undef reterror*/
1236
/*}*/
1237
1238
/*int verifyIMG4(char *buf, plist_t buildmanifest){*/
1239
/*//return 0 on valid file, positive value on invalid file, negative value when errors occured*/
1240
/*int err = 0;*/
1241
/*#define reterror(code,a ...){error(a);err=code;goto error;}*/
1242
/*char *im4pSHA = NULL;*/
1243
/*if (sequenceHasName(buf, "IMG4")){*/
1244
/*//verify IMG4*/
1245
/*char *im4p = getIM4PFromIMG4(buf);*/
1246
/*im4pSHA = getSHA1ofSqeuence(im4p);*/
1247
1248
/*if (!im4p) goto error;*/
1249
1250
/*buf = getElementFromIMG4(buf, "IM4M");*/
1251
/*}*/
1252
1253
/*if (!sequenceHasName(buf, "IM4M"))*/
1254
/*reterror(-1,"unable to find IM4M tag");*/
1255
1256
/*if (im4pSHA){*/
1257
/*if (doForDGSTinIM4M(buf, im4pSHA, find_dgst_cb) == -255)*/
1258
/*printf("[OK] IM4P is valid for the attached IM4M\n");*/
1259
/*else*/
1260
/*reterror(1,"IM4P can't be verified by IM4M\n");*/
1261
/*}*/
1262
1263
/*if ((err = verifyIM4MSignature(buf))){*/
1264
/*reterror((err < 0) ? err : 2, "Signature verification of IM4M failed with error=%d\n",err);*/
1265
/*}else*/
1266
/*printf("[OK] IM4M signature is verified by TssAuthority\n");*/
1267
1268
/*#warning TODO verify certificate chain*/
1269
1270
/*if (buildmanifest) {*/
1271
/*plist_t identity = getBuildIdentityForIM4M(buf, buildmanifest);*/
1272
/*if (identity){*/
1273
/*printf("[OK] IM4M is valid for the given BuildManifest for the following restore:\n\n");*/
1274
/*printGeneralBuildIdentityInformation(identity);*/
1275
1276
/*}else{*/
1277
/*reterror(3,"IM4M is not valid for any restore within the Buildmanifest\n");*/
1278
/*}*/
1279
/*}else{*/
1280
/*warning("No BuildManifest specified, can't verify restore type of APTicket\n");*/
1281
/*}*/
1282
1283
1284
/*error:*/
1285
/*safeFree(im4pSHA);*/
1286
/*return err;*/
1287
/*#undef reterror*/
1288
/*}*/
1289
1290
1291
1292
1293
1294
1295