1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdbool.h>
18 #include <string.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 
23 #include <nanohub/nanohub.h>
24 #include <nanohub/nanoapp.h>
25 #include <nanohub/sha2.h>
26 #include <nanohub/rsa.h>
27 
28 static FILE* urandom = NULL;
29 
30 #if defined(__APPLE__) || defined(_WIN32)
bswap32(uint32_t x)31 inline uint32_t bswap32 (uint32_t x) {
32     uint32_t out = 0;
33     for (int i=0; i < 4; ++i, x >>= 8)
34         out = (out << 8) | (x & 0xFF);
35     return out;
36 }
37 
38 #define htobe32(x)  bswap32((x))
39 #define htole32(x)  ((uint32_t)(x))
40 #define be32toh(x)  bswap32((x))
41 #define le32toh(x)  ((uint32_t)(x))
42 #else
43 #include <endian.h>
44 #endif
45 
46 //read exactly one hex-encoded byte from a file, skipping all the fluff
getHexEncodedByte(uint8_t * buf,uint32_t * ppos,uint32_t size)47 static int getHexEncodedByte(uint8_t *buf, uint32_t *ppos, uint32_t size)
48 {
49     int c, i;
50     uint32_t pos = *ppos;
51     uint8_t val = 0;
52 
53     //for first byte
54     for (i = 0; i < 2; i++) {
55         val <<= 4;
56         while(1) {
57             if (pos == size)
58                 return -1;
59             c = buf[pos++];
60             *ppos = pos;
61 
62             if (c >= '0' && c <= '9')
63                 val += c - '0';
64             else if (c >= 'a' && c <= 'f')
65                 val += c + 10 - 'a';
66             else if (c >= 'A' && c <= 'F')
67                 val += c + 10 - 'A';
68             else if (i)                         //disallow everything between first and second nibble
69                 return -1;
70             else if (c > 'f' && c <= 'z')	//disallow nonalpha data
71                 return -1;
72             else if (c > 'F' && c <= 'Z')	//disallow nonalpha data
73                 return -1;
74             else
75                 continue;
76             break;
77         }
78     }
79 
80     return val;
81 }
82 
83 //provide a random number for which the following property is true ((ret & 0xFF000000) && (ret & 0xFF0000) && (ret & 0xFF00) && (ret & 0xFF))
rand32_no_zero_bytes(void)84 static uint32_t rand32_no_zero_bytes(void)
85 {
86     uint32_t i, v;
87     uint8_t byte;
88 
89     if (!urandom) {
90         urandom = fopen("/dev/urandom", "rb");
91         if (!urandom) {
92             fprintf(stderr, "Failed to open /dev/urandom. Cannot procceed!\n");
93             exit(-2);
94         }
95     }
96 
97     for (v = 0, i = 0; i < 4; i++) {
98         do {
99             if (!fread(&byte, 1, 1, urandom)) {
100                 fprintf(stderr, "Failed to read /dev/urandom. Cannot procceed!\n");
101                 exit(-3);
102             }
103         } while (!byte);
104 
105         v = (v << 8) | byte;
106     }
107 
108     return v;
109 }
110 
cleanup(void)111 static void cleanup(void)
112 {
113     if (urandom)
114         fclose(urandom);
115 }
116 
117 struct RsaData {
118     uint32_t num[RSA_LIMBS];
119     uint32_t exponent[RSA_LIMBS];
120     uint32_t modulus[RSA_LIMBS];
121     struct RsaState state;
122 };
123 
validateSignature(uint8_t * sigPack,struct RsaData * rsa,bool verbose,uint32_t * refHash,bool preset)124 static bool validateSignature(uint8_t *sigPack, struct RsaData *rsa, bool verbose, uint32_t *refHash, bool preset)
125 {
126     int i;
127     const uint32_t *rsaResult;
128     const uint32_t *le32SigPack = (const uint32_t*)sigPack;
129     //convert to native uint32_t; ignore possible alignment issues
130     for (i = 0; i < RSA_LIMBS; i++)
131         rsa->num[i] = le32toh(le32SigPack[i]);
132     //update the user
133     if (verbose)
134         printHashRev(stderr, "RSA cyphertext", rsa->num, RSA_LIMBS);
135     if (!preset)
136         memcpy(rsa->modulus, sigPack + RSA_BYTES, RSA_BYTES);
137 
138     //do rsa op
139     rsaResult = rsaPubOp(&rsa->state, rsa->num, rsa->modulus);
140 
141     //update the user
142     if (verbose)
143         printHashRev(stderr, "RSA plaintext", rsaResult, RSA_LIMBS);
144 
145     //verify padding is appropriate and valid
146     if ((rsaResult[RSA_LIMBS - 1] & 0xffff0000) != 0x00020000) {
147         fprintf(stderr, "Padding header is invalid\n");
148         return false;
149     }
150 
151     //verify first two bytes of padding
152     if (!(rsaResult[RSA_LIMBS - 1] & 0xff00) || !(rsaResult[RSA_LIMBS - 1] & 0xff)) {
153         fprintf(stderr, "Padding bytes 0..1 are invalid\n");
154         return false;
155     }
156 
157     //verify last 3 bytes of padding and the zero terminator
158     if (!(rsaResult[8] & 0xff000000) || !(rsaResult[8] & 0xff0000) || !(rsaResult[8] & 0xff00) || (rsaResult[8] & 0xff)) {
159         fprintf(stderr, "Padding last bytes & terminator invalid\n");
160         return false;
161     }
162 
163     //verify middle padding bytes
164     for (i = 9; i < RSA_LIMBS - 1; i++) {
165         if (!(rsaResult[i] & 0xff000000) || !(rsaResult[i] & 0xff0000) || !(rsaResult[i] & 0xff00) || !(rsaResult[i] & 0xff)) {
166             fprintf(stderr, "Padding word %d invalid\n", i);
167             return false;
168         }
169     }
170     if (verbose) {
171         printHash(stderr, "Recovered hash ", rsaResult, SHA2_HASH_WORDS);
172         printHash(stderr, "Calculated hash", refHash, SHA2_HASH_WORDS);
173     }
174 
175     if (!preset) {
176         // we're doing full verification, with key extracted from signature pack
177         if (memcmp(rsaResult, refHash, SHA2_HASH_SIZE)) {
178             fprintf(stderr, "hash mismatch\n");
179             return false;
180         }
181     } else {
182         // we just decode the signature with key passed as an argument
183         // in this case we return recovered hash
184         memcpy(refHash, rsaResult, SHA2_HASH_SIZE);
185     }
186     return true;
187 }
188 
189 #define SIGNATURE_BLOCK_SIZE    (2 * RSA_BYTES)
190 
handleConvertKey(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,struct RsaData * rsa)191 static int handleConvertKey(uint8_t **pbuf, uint32_t bufUsed, FILE *out, struct RsaData *rsa)
192 {
193     bool  haveNonzero = false;
194     uint8_t *buf = *pbuf;
195     int i, c;
196     uint32_t pos = 0;
197     int ret;
198 
199     for (i = 0; i < (int)RSA_BYTES; i++) {
200 
201         //get a byte, skipping all zeroes (openssl likes to prepend one at times)
202         do {
203             c = getHexEncodedByte(buf, &pos, bufUsed);
204         } while (c == 0 && !haveNonzero);
205         haveNonzero = true;
206         if (c < 0) {
207             fprintf(stderr, "Invalid text RSA input data\n");
208             return 2;
209         }
210 
211         buf[i] = c;
212     }
213 
214     // change form BE to native; ignore alignment
215     uint32_t *be32Buf = (uint32_t*)buf;
216     for (i = 0; i < RSA_LIMBS; i++)
217         rsa->num[RSA_LIMBS - i - 1] = be32toh(be32Buf[i]);
218 
219     //output in our binary format (little-endian)
220     ret = fwrite(rsa->num, 1, RSA_BYTES, out) == RSA_BYTES ? 0 : 2;
221     fprintf(stderr, "Conversion status: %d\n", ret);
222 
223     return ret;
224 }
225 
handleVerify(uint8_t ** pbuf,uint32_t bufUsed,struct RsaData * rsa,bool verbose,bool bareData)226 static int handleVerify(uint8_t **pbuf, uint32_t bufUsed, struct RsaData *rsa, bool verbose, bool bareData)
227 {
228     struct Sha2state shaState;
229     uint8_t *buf = *pbuf;
230     uint32_t masterPubKey[RSA_LIMBS];
231 
232     memcpy(masterPubKey, rsa->modulus, RSA_BYTES);
233     if (!bareData) {
234         struct ImageHeader *image = (struct ImageHeader *)buf;
235         struct AppSecSignHdr *secHdr = (struct AppSecSignHdr *)&image[1];
236         int block = 0;
237         uint8_t *sigPack;
238         bool trusted = false;
239         bool lastTrusted = false;
240         int sigData;
241 
242         if (bufUsed < (sizeof(*image) + sizeof(*secHdr))) {
243             fprintf(stderr, "Invalid signature header: file is too short\n");
244             return 2;
245         }
246 
247         if (verbose)
248             fprintf(stderr, "Original Data len=%" PRIu32 " b; file size=%" PRIu32 " b; diff=%" PRIu32 " b\n",
249                     secHdr->appDataLen, bufUsed, bufUsed - secHdr->appDataLen);
250 
251         if (!(image->aosp.flags & NANOAPP_SIGNED_FLAG)) {
252             fprintf(stderr, "image is not marked as signed, can not verify\n");
253             return 2;
254         }
255         sigData = bufUsed - (secHdr->appDataLen + sizeof(*image) + sizeof(*secHdr));
256         if (sigData <= 0 || (sigData % SIGNATURE_BLOCK_SIZE) != 0) {
257             fprintf(stderr, "Invalid signature header: data size mismatch\n");
258             return 2;
259         }
260 
261         sha2init(&shaState);
262         sha2processBytes(&shaState, buf, bufUsed - sigData);
263         int nSig = sigData / SIGNATURE_BLOCK_SIZE;
264         sigPack = buf + bufUsed - sigData;
265         for (block = 0; block < nSig; ++block) {
266             if (!validateSignature(sigPack, rsa, verbose, (uint32_t*)sha2finish(&shaState), false)) {
267                 fprintf(stderr, "Signature verification failed: signature block #%d\n", block);
268                 return 2;
269             }
270             if (memcmp(masterPubKey, rsa->modulus, RSA_BYTES) == 0) {
271                 fprintf(stderr, "Key in block %d is trusted\n", block);
272                 trusted = true;
273                 lastTrusted = true;
274             } else {
275                 lastTrusted = false;
276             }
277             sha2init(&shaState);
278             sha2processBytes(&shaState, sigPack+RSA_BYTES, RSA_BYTES);
279             sigPack += SIGNATURE_BLOCK_SIZE;
280         }
281         if (trusted && !lastTrusted) {
282             fprintf(stderr, "Trusted key is not the last in key sequence\n");
283         }
284         return trusted ? 0 : 2;
285     } else {
286         uint8_t *sigPack = buf + bufUsed - SIGNATURE_BLOCK_SIZE;
287         uint32_t *hash;
288         // can not do signature chains in bare mode
289         if (bufUsed > SIGNATURE_BLOCK_SIZE) {
290             sha2init(&shaState);
291             sha2processBytes(&shaState, buf, bufUsed - SIGNATURE_BLOCK_SIZE);
292             hash = (uint32_t*)sha2finish(&shaState);
293             printHash(stderr, "File hash", hash, SHA2_HASH_WORDS);
294             if (verbose)
295                 printHashRev(stderr, "File PubKey", (uint32_t *)(sigPack + RSA_BYTES), RSA_LIMBS);
296             if (!validateSignature(sigPack, rsa, verbose, hash, false)) {
297                 fprintf(stderr, "Signature verification failed on raw data\n");
298                 return 2;
299             }
300             if (memcmp(masterPubKey, sigPack + RSA_BYTES, RSA_BYTES) == 0) {
301                 fprintf(stderr, "Signature verification passed and the key is trusted\n");
302                 return 0;
303             } else {
304                 fprintf(stderr, "Signature verification passed but the key is not trusted\n");
305                 return 2;
306             }
307         } else {
308             fprintf(stderr, "Not enough raw data to extract signature from\n");
309             return 2;
310         }
311     }
312 
313     return 0;
314 }
315 
handleSign(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,struct RsaData * rsa,bool verbose,bool bareData)316 static int handleSign(uint8_t **pbuf, uint32_t bufUsed, FILE *out, struct RsaData *rsa, bool verbose, bool bareData)
317 {
318     struct Sha2state shaState;
319     uint8_t *buf = *pbuf;
320     uint32_t i;
321     const uint32_t *hash;
322     const uint32_t *rsaResult;
323     int ret;
324 
325     if (!bareData) {
326         struct ImageHeader *image = (struct ImageHeader *)buf;
327         struct AppSecSignHdr *secHdr = (struct AppSecSignHdr *)&image[1];
328         uint32_t grow = sizeof(*secHdr);
329         if (!(image->aosp.flags & NANOAPP_SIGNED_FLAG)) {
330             // this is the 1st signature in the chain; inject header, set flag
331             buf = reallocOrDie(buf, bufUsed + grow);
332             *pbuf = buf;
333             image = (struct ImageHeader *)buf;
334             secHdr = (struct AppSecSignHdr *)&image[1];
335 
336             fprintf(stderr, "Generating signature header\n");
337             image->aosp.flags |= NANOAPP_SIGNED_FLAG;
338             memmove((uint8_t*)&image[1] + grow, &image[1], bufUsed - sizeof(*image));
339             secHdr->appDataLen = bufUsed - sizeof(*image);
340             bufUsed += grow;
341             fprintf(stderr, "Rehashing file\n");
342             sha2init(&shaState);
343             sha2processBytes(&shaState, buf, bufUsed);
344         } else {
345             int sigSz = bufUsed - sizeof(*image) - sizeof(*secHdr) - secHdr->appDataLen;
346             int numSigs = sigSz / SIGNATURE_BLOCK_SIZE;
347             if ((numSigs * (int)SIGNATURE_BLOCK_SIZE) != sigSz) {
348                 fprintf(stderr, "Invalid signature block(s) detected\n");
349                 return 2;
350             } else {
351                 fprintf(stderr, "Found %d appended signature(s)\n", numSigs);
352                 // generating SHA256 of the last PubKey in chain
353                 fprintf(stderr, "Hashing last signature's PubKey\n");
354                 sha2init(&shaState);
355                 sha2processBytes(&shaState, buf + bufUsed- RSA_BYTES, RSA_BYTES);
356             }
357         }
358     } else {
359         fprintf(stderr, "Signing raw data\n");
360         sha2init(&shaState);
361         sha2processBytes(&shaState, buf, bufUsed);
362     }
363 
364     //update the user on the progress
365     hash = sha2finish(&shaState);
366     if (verbose)
367         printHash(stderr, "SHA2 hash", hash, SHA2_HASH_WORDS);
368 
369     memcpy(rsa->num, hash, SHA2_HASH_SIZE);
370 
371     i = SHA2_HASH_WORDS;
372     //write padding
373     rsa->num[i++] = rand32_no_zero_bytes() << 8; //low byte here must be zero as per padding spec
374     for (;i < RSA_LIMBS - 1; i++)
375         rsa->num[i] = rand32_no_zero_bytes();
376     rsa->num[i] = (rand32_no_zero_bytes() >> 16) | 0x00020000; //as per padding spec
377 
378     //update the user
379     if (verbose)
380         printHashRev(stderr, "RSA plaintext", rsa->num, RSA_LIMBS);
381 
382     //do the RSA thing
383     fprintf(stderr, "Retriculating splines...");
384     rsaResult = rsaPrivOp(&rsa->state, rsa->num, rsa->exponent, rsa->modulus);
385     fprintf(stderr, "DONE\n");
386 
387     //update the user
388     if (verbose)
389         printHashRev(stderr, "RSA cyphertext", rsaResult, RSA_LIMBS);
390 
391     // output in a format that our microcontroller will be able to digest easily & directly
392     // (an array of bytes representing little-endian 32-bit words)
393     fwrite(buf, 1, bufUsed, out);
394     fwrite(rsaResult, 1, sizeof(uint32_t[RSA_LIMBS]), out);
395     ret = (fwrite(rsa->modulus, 1, RSA_BYTES, out) == RSA_BYTES) ? 0 : 2;
396 
397     fprintf(stderr, "Status: %s (%d)\n", ret == 0 ? "success" : "failed", ret);
398     return ret;
399 
400 }
401 
fatalUsage(const char * name,const char * msg,const char * arg)402 static void fatalUsage(const char *name, const char *msg, const char *arg)
403 {
404     if (msg && arg)
405         fprintf(stderr, "Error: %s: %s\n\n", msg, arg);
406     else if (msg)
407         fprintf(stderr, "Error: %s\n\n", msg);
408 
409     fprintf(stderr, "USAGE: %s [-v] [-e <pvt key>] [-m <pub key>] [-t] [-s] [-b] <input file> [<output file>]\n"
410                     "       -v : be verbose\n"
411                     "       -b : generate binary key from text file created by OpenSSL\n"
412                     "       -s : sign post-processed file\n"
413                     "       -t : verify signature of signed post-processed file\n"
414                     "       -e : RSA binary private key\n"
415                     "       -m : RSA binary public key\n"
416                     "       -r : do not parse headers, do not generate headers (with -t, -s)\n"
417                     , name);
418     exit(1);
419 }
420 
main(int argc,char ** argv)421 int main(int argc, char **argv)
422 {
423     uint32_t bufUsed = 0;
424     uint8_t *buf = NULL;
425     int ret = -1;
426     const char **strArg = NULL;
427     const char *appName = argv[0];
428     const char *posArg[2] = { NULL };
429     uint32_t posArgCnt = 0;
430     FILE *out = NULL;
431     const char *prev = NULL;
432     bool verbose = false;
433     bool sign = false;
434     bool verify = false;
435     bool txt2bin = false;
436     bool bareData = false;
437     const char *keyPvtFile = NULL;
438     const char *keyPubFile = NULL;
439     int multi = 0;
440     struct RsaData rsa;
441     struct ImageHeader *image;
442 
443     //it might not matter, but we still like to try to cleanup after ourselves
444     (void)atexit(cleanup);
445 
446     for (int i = 1; i < argc; i++) {
447         if (argv[i][0] == '-') {
448             prev = argv[i];
449             if (!strcmp(argv[i], "-v"))
450                 verbose = true;
451             else if (!strcmp(argv[i], "-s"))
452                 sign = true;
453             else if (!strcmp(argv[i], "-t"))
454                 verify = true;
455             else if (!strcmp(argv[i], "-b"))
456                 txt2bin = true;
457             else if (!strcmp(argv[i], "-e"))
458                 strArg = &keyPvtFile;
459             else if (!strcmp(argv[i], "-m"))
460                 strArg = &keyPubFile;
461             else if (!strcmp(argv[i], "-r"))
462                 bareData = true;
463             else
464                 fatalUsage(appName, "unknown argument", argv[i]);
465         } else {
466             if (strArg) {
467                     *strArg = argv[i];
468                 strArg = NULL;
469             } else {
470                 if (posArgCnt < 2)
471                     posArg[posArgCnt++] = argv[i];
472                 else
473                     fatalUsage(appName, "too many positional arguments", argv[i]);
474             }
475             prev = 0;
476         }
477     }
478     if (prev)
479         fatalUsage(appName, "missing argument after", prev);
480 
481     if (!posArgCnt)
482         fatalUsage(appName, "missing input file name", NULL);
483 
484     if (sign)
485         multi++;
486     if (verify)
487         multi++;
488     if (txt2bin)
489         multi++;
490 
491     if (multi != 1)
492         fatalUsage(appName, "select either -s, -t, or -b", NULL);
493 
494     memset(&rsa, 0, sizeof(rsa));
495 
496     if (sign && !(keyPvtFile && keyPubFile))
497         fatalUsage(appName, "We need both PUB (-m) and PVT (-e) keys for signing", NULL);
498 
499     if (verify && (!keyPubFile || keyPvtFile))
500         fatalUsage(appName, "We only need PUB (-m)  key for signature checking", NULL);
501 
502     if (keyPvtFile) {
503         if (!readFile(rsa.exponent, sizeof(rsa.exponent), keyPvtFile))
504             fatalUsage(appName, "Can't read PVT key from", keyPvtFile);
505 #ifdef DEBUG_KEYS
506         else if (verbose)
507             printHashRev(stderr, "RSA exponent", rsa.exponent, RSA_LIMBS);
508 #endif
509     }
510 
511     if (keyPubFile) {
512         if (!readFile(rsa.modulus, sizeof(rsa.modulus), keyPubFile))
513             fatalUsage(appName, "Can't read PUB key from", keyPubFile);
514         else if (verbose)
515             printHashRev(stderr, "RSA modulus", rsa.modulus, RSA_LIMBS);
516     }
517 
518     buf = loadFile(posArg[0], &bufUsed);
519     fprintf(stderr, "Read %" PRIu32 " bytes\n", bufUsed);
520 
521     image = (struct ImageHeader *)buf;
522     if (!bareData && !txt2bin) {
523         if (bufUsed >= sizeof(*image) &&
524             image->aosp.header_version == 1 &&
525             image->aosp.magic == NANOAPP_AOSP_MAGIC &&
526             image->layout.magic == GOOGLE_LAYOUT_MAGIC) {
527             fprintf(stderr, "Found AOSP header\n");
528         } else {
529             fprintf(stderr, "Unknown binary format\n");
530             return 2;
531         }
532     }
533 
534     if (!posArg[1])
535         out = stdout;
536     else
537         out = fopen(posArg[1], "w");
538     if (!out)
539         fatalUsage(appName, "failed to create/open output file", posArg[1]);
540 
541     if (sign)
542         ret = handleSign(&buf, bufUsed, out, &rsa, verbose, bareData);
543     else if (verify)
544         ret = handleVerify(&buf, bufUsed, &rsa, verbose, bareData);
545     else if (txt2bin)
546         ret = handleConvertKey(&buf, bufUsed, out, &rsa);
547 
548     free(buf);
549     fclose(out);
550     return ret;
551 }
552