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 * 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