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