diff options
Diffstat (limited to 'verifier.cpp')
-rw-r--r-- | verifier.cpp | 265 |
1 files changed, 124 insertions, 141 deletions
diff --git a/verifier.cpp b/verifier.cpp index 61e5adf0..9a2d60c6 100644 --- a/verifier.cpp +++ b/verifier.cpp | |||
@@ -113,7 +113,7 @@ static bool read_pkcs7(uint8_t* pkcs7_der, size_t pkcs7_der_len, uint8_t** sig_d | |||
113 | // or no key matches the signature). | 113 | // or no key matches the signature). |
114 | 114 | ||
115 | int verify_file(unsigned char* addr, size_t length, | 115 | int verify_file(unsigned char* addr, size_t length, |
116 | const Certificate* pKeys, unsigned int numKeys) { | 116 | const std::vector<Certificate>& keys) { |
117 | ui->SetProgress(0.0); | 117 | ui->SetProgress(0.0); |
118 | 118 | ||
119 | // An archive with a whole-file signature will end in six bytes: | 119 | // An archive with a whole-file signature will end in six bytes: |
@@ -176,8 +176,7 @@ int verify_file(unsigned char* addr, size_t length, | |||
176 | return VERIFY_FAILURE; | 176 | return VERIFY_FAILURE; |
177 | } | 177 | } |
178 | 178 | ||
179 | size_t i; | 179 | for (size_t i = 4; i < eocd_size-3; ++i) { |
180 | for (i = 4; i < eocd_size-3; ++i) { | ||
181 | if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b && | 180 | if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b && |
182 | eocd[i+2] == 0x05 && eocd[i+3] == 0x06) { | 181 | eocd[i+2] == 0x05 && eocd[i+3] == 0x06) { |
183 | // if the sequence $50 $4b $05 $06 appears anywhere after | 182 | // if the sequence $50 $4b $05 $06 appears anywhere after |
@@ -193,8 +192,8 @@ int verify_file(unsigned char* addr, size_t length, | |||
193 | 192 | ||
194 | bool need_sha1 = false; | 193 | bool need_sha1 = false; |
195 | bool need_sha256 = false; | 194 | bool need_sha256 = false; |
196 | for (i = 0; i < numKeys; ++i) { | 195 | for (const auto& key : keys) { |
197 | switch (pKeys[i].hash_len) { | 196 | switch (key.hash_len) { |
198 | case SHA_DIGEST_SIZE: need_sha1 = true; break; | 197 | case SHA_DIGEST_SIZE: need_sha1 = true; break; |
199 | case SHA256_DIGEST_SIZE: need_sha256 = true; break; | 198 | case SHA256_DIGEST_SIZE: need_sha256 = true; break; |
200 | } | 199 | } |
@@ -225,7 +224,7 @@ int verify_file(unsigned char* addr, size_t length, | |||
225 | const uint8_t* sha1 = SHA_final(&sha1_ctx); | 224 | const uint8_t* sha1 = SHA_final(&sha1_ctx); |
226 | const uint8_t* sha256 = SHA256_final(&sha256_ctx); | 225 | const uint8_t* sha256 = SHA256_final(&sha256_ctx); |
227 | 226 | ||
228 | uint8_t* sig_der = NULL; | 227 | uint8_t* sig_der = nullptr; |
229 | size_t sig_der_length = 0; | 228 | size_t sig_der_length = 0; |
230 | 229 | ||
231 | size_t signature_size = signature_start - FOOTER_SIZE; | 230 | size_t signature_size = signature_start - FOOTER_SIZE; |
@@ -240,9 +239,10 @@ int verify_file(unsigned char* addr, size_t length, | |||
240 | * any key can match, we need to try each before determining a verification | 239 | * any key can match, we need to try each before determining a verification |
241 | * failure has happened. | 240 | * failure has happened. |
242 | */ | 241 | */ |
243 | for (i = 0; i < numKeys; ++i) { | 242 | size_t i = 0; |
243 | for (const auto& key : keys) { | ||
244 | const uint8_t* hash; | 244 | const uint8_t* hash; |
245 | switch (pKeys[i].hash_len) { | 245 | switch (key.hash_len) { |
246 | case SHA_DIGEST_SIZE: hash = sha1; break; | 246 | case SHA_DIGEST_SIZE: hash = sha1; break; |
247 | case SHA256_DIGEST_SIZE: hash = sha256; break; | 247 | case SHA256_DIGEST_SIZE: hash = sha256; break; |
248 | default: continue; | 248 | default: continue; |
@@ -250,15 +250,15 @@ int verify_file(unsigned char* addr, size_t length, | |||
250 | 250 | ||
251 | // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that | 251 | // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that |
252 | // the signing tool appends after the signature itself. | 252 | // the signing tool appends after the signature itself. |
253 | if (pKeys[i].key_type == Certificate::RSA) { | 253 | if (key.key_type == Certificate::RSA) { |
254 | if (sig_der_length < RSANUMBYTES) { | 254 | if (sig_der_length < RSANUMBYTES) { |
255 | // "signature" block isn't big enough to contain an RSA block. | 255 | // "signature" block isn't big enough to contain an RSA block. |
256 | LOGI("signature is too short for RSA key %zu\n", i); | 256 | LOGI("signature is too short for RSA key %zu\n", i); |
257 | continue; | 257 | continue; |
258 | } | 258 | } |
259 | 259 | ||
260 | if (!RSA_verify(pKeys[i].rsa, sig_der, RSANUMBYTES, | 260 | if (!RSA_verify(key.rsa.get(), sig_der, RSANUMBYTES, |
261 | hash, pKeys[i].hash_len)) { | 261 | hash, key.hash_len)) { |
262 | LOGI("failed to verify against RSA key %zu\n", i); | 262 | LOGI("failed to verify against RSA key %zu\n", i); |
263 | continue; | 263 | continue; |
264 | } | 264 | } |
@@ -266,8 +266,8 @@ int verify_file(unsigned char* addr, size_t length, | |||
266 | LOGI("whole-file signature verified against RSA key %zu\n", i); | 266 | LOGI("whole-file signature verified against RSA key %zu\n", i); |
267 | free(sig_der); | 267 | free(sig_der); |
268 | return VERIFY_SUCCESS; | 268 | return VERIFY_SUCCESS; |
269 | } else if (pKeys[i].key_type == Certificate::EC | 269 | } else if (key.key_type == Certificate::EC |
270 | && pKeys[i].hash_len == SHA256_DIGEST_SIZE) { | 270 | && key.hash_len == SHA256_DIGEST_SIZE) { |
271 | p256_int r, s; | 271 | p256_int r, s; |
272 | if (!dsa_sig_unpack(sig_der, sig_der_length, &r, &s)) { | 272 | if (!dsa_sig_unpack(sig_der, sig_der_length, &r, &s)) { |
273 | LOGI("Not a DSA signature block for EC key %zu\n", i); | 273 | LOGI("Not a DSA signature block for EC key %zu\n", i); |
@@ -276,7 +276,7 @@ int verify_file(unsigned char* addr, size_t length, | |||
276 | 276 | ||
277 | p256_int p256_hash; | 277 | p256_int p256_hash; |
278 | p256_from_bin(hash, &p256_hash); | 278 | p256_from_bin(hash, &p256_hash); |
279 | if (!p256_ecdsa_verify(&(pKeys[i].ec->x), &(pKeys[i].ec->y), | 279 | if (!p256_ecdsa_verify(&(key.ec->x), &(key.ec->y), |
280 | &p256_hash, &r, &s)) { | 280 | &p256_hash, &r, &s)) { |
281 | LOGI("failed to verify against EC key %zu\n", i); | 281 | LOGI("failed to verify against EC key %zu\n", i); |
282 | continue; | 282 | continue; |
@@ -286,8 +286,9 @@ int verify_file(unsigned char* addr, size_t length, | |||
286 | free(sig_der); | 286 | free(sig_der); |
287 | return VERIFY_SUCCESS; | 287 | return VERIFY_SUCCESS; |
288 | } else { | 288 | } else { |
289 | LOGI("Unknown key type %d\n", pKeys[i].key_type); | 289 | LOGI("Unknown key type %d\n", key.key_type); |
290 | } | 290 | } |
291 | i++; | ||
291 | } | 292 | } |
292 | free(sig_der); | 293 | free(sig_der); |
293 | LOGE("failed to verify whole-file signature\n"); | 294 | LOGE("failed to verify whole-file signature\n"); |
@@ -323,140 +324,122 @@ int verify_file(unsigned char* addr, size_t length, | |||
323 | // 4: 2048-bit RSA key with e=65537 and SHA-256 hash | 324 | // 4: 2048-bit RSA key with e=65537 and SHA-256 hash |
324 | // 5: 256-bit EC key using the NIST P-256 curve parameters and SHA-256 hash | 325 | // 5: 256-bit EC key using the NIST P-256 curve parameters and SHA-256 hash |
325 | // | 326 | // |
326 | // Returns NULL if the file failed to parse, or if it contain zero keys. | 327 | // Returns true on success, and appends the found keys (at least one) to certs. |
327 | Certificate* | 328 | // Otherwise returns false if the file failed to parse, or if it contains zero |
328 | load_keys(const char* filename, int* numKeys) { | 329 | // keys. The contents in certs would be unspecified on failure. |
329 | Certificate* out = NULL; | 330 | bool load_keys(const char* filename, std::vector<Certificate>& certs) { |
330 | *numKeys = 0; | 331 | std::unique_ptr<FILE, decltype(&fclose)> f(fopen(filename, "r"), fclose); |
331 | 332 | if (!f) { | |
332 | FILE* f = fopen(filename, "r"); | ||
333 | if (f == NULL) { | ||
334 | LOGE("opening %s: %s\n", filename, strerror(errno)); | 333 | LOGE("opening %s: %s\n", filename, strerror(errno)); |
335 | goto exit; | 334 | return false; |
336 | } | 335 | } |
337 | 336 | ||
338 | { | 337 | while (true) { |
339 | int i; | 338 | certs.emplace_back(0, Certificate::RSA, nullptr, nullptr); |
340 | bool done = false; | 339 | Certificate& cert = certs.back(); |
341 | while (!done) { | 340 | |
342 | ++*numKeys; | 341 | char start_char; |
343 | out = (Certificate*)realloc(out, *numKeys * sizeof(Certificate)); | 342 | if (fscanf(f.get(), " %c", &start_char) != 1) return false; |
344 | Certificate* cert = out + (*numKeys - 1); | 343 | if (start_char == '{') { |
345 | memset(cert, '\0', sizeof(Certificate)); | 344 | // a version 1 key has no version specifier. |
346 | 345 | cert.key_type = Certificate::RSA; | |
347 | char start_char; | 346 | cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey); |
348 | if (fscanf(f, " %c", &start_char) != 1) goto exit; | 347 | cert.rsa->exponent = 3; |
349 | if (start_char == '{') { | 348 | cert.hash_len = SHA_DIGEST_SIZE; |
350 | // a version 1 key has no version specifier. | 349 | } else if (start_char == 'v') { |
351 | cert->key_type = Certificate::RSA; | 350 | int version; |
352 | cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey)); | 351 | if (fscanf(f.get(), "%d {", &version) != 1) return false; |
353 | cert->rsa->exponent = 3; | 352 | switch (version) { |
354 | cert->hash_len = SHA_DIGEST_SIZE; | 353 | case 2: |
355 | } else if (start_char == 'v') { | 354 | cert.key_type = Certificate::RSA; |
356 | int version; | 355 | cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey); |
357 | if (fscanf(f, "%d {", &version) != 1) goto exit; | 356 | cert.rsa->exponent = 65537; |
358 | switch (version) { | 357 | cert.hash_len = SHA_DIGEST_SIZE; |
359 | case 2: | 358 | break; |
360 | cert->key_type = Certificate::RSA; | 359 | case 3: |
361 | cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey)); | 360 | cert.key_type = Certificate::RSA; |
362 | cert->rsa->exponent = 65537; | 361 | cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey); |
363 | cert->hash_len = SHA_DIGEST_SIZE; | 362 | cert.rsa->exponent = 3; |
364 | break; | 363 | cert.hash_len = SHA256_DIGEST_SIZE; |
365 | case 3: | 364 | break; |
366 | cert->key_type = Certificate::RSA; | 365 | case 4: |
367 | cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey)); | 366 | cert.key_type = Certificate::RSA; |
368 | cert->rsa->exponent = 3; | 367 | cert.rsa = std::unique_ptr<RSAPublicKey>(new RSAPublicKey); |
369 | cert->hash_len = SHA256_DIGEST_SIZE; | 368 | cert.rsa->exponent = 65537; |
370 | break; | 369 | cert.hash_len = SHA256_DIGEST_SIZE; |
371 | case 4: | 370 | break; |
372 | cert->key_type = Certificate::RSA; | 371 | case 5: |
373 | cert->rsa = (RSAPublicKey*)malloc(sizeof(RSAPublicKey)); | 372 | cert.key_type = Certificate::EC; |
374 | cert->rsa->exponent = 65537; | 373 | cert.ec = std::unique_ptr<ECPublicKey>(new ECPublicKey); |
375 | cert->hash_len = SHA256_DIGEST_SIZE; | 374 | cert.hash_len = SHA256_DIGEST_SIZE; |
376 | break; | 375 | break; |
377 | case 5: | 376 | default: |
378 | cert->key_type = Certificate::EC; | 377 | return false; |
379 | cert->ec = (ECPublicKey*)calloc(1, sizeof(ECPublicKey)); | ||
380 | cert->hash_len = SHA256_DIGEST_SIZE; | ||
381 | break; | ||
382 | default: | ||
383 | goto exit; | ||
384 | } | ||
385 | } | 378 | } |
379 | } | ||
386 | 380 | ||
387 | if (cert->key_type == Certificate::RSA) { | 381 | if (cert.key_type == Certificate::RSA) { |
388 | RSAPublicKey* key = cert->rsa; | 382 | RSAPublicKey* key = cert.rsa.get(); |
389 | if (fscanf(f, " %i , 0x%x , { %u", | 383 | if (fscanf(f.get(), " %i , 0x%x , { %u", &(key->len), &(key->n0inv), |
390 | &(key->len), &(key->n0inv), &(key->n[0])) != 3) { | 384 | &(key->n[0])) != 3) { |
391 | goto exit; | 385 | return false; |
392 | } | ||
393 | if (key->len != RSANUMWORDS) { | ||
394 | LOGE("key length (%d) does not match expected size\n", key->len); | ||
395 | goto exit; | ||
396 | } | ||
397 | for (i = 1; i < key->len; ++i) { | ||
398 | if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit; | ||
399 | } | ||
400 | if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit; | ||
401 | for (i = 1; i < key->len; ++i) { | ||
402 | if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit; | ||
403 | } | ||
404 | fscanf(f, " } } "); | ||
405 | |||
406 | LOGI("read key e=%d hash=%d\n", key->exponent, cert->hash_len); | ||
407 | } else if (cert->key_type == Certificate::EC) { | ||
408 | ECPublicKey* key = cert->ec; | ||
409 | int key_len; | ||
410 | unsigned int byte; | ||
411 | uint8_t x_bytes[P256_NBYTES]; | ||
412 | uint8_t y_bytes[P256_NBYTES]; | ||
413 | if (fscanf(f, " %i , { %u", &key_len, &byte) != 2) goto exit; | ||
414 | if (key_len != P256_NBYTES) { | ||
415 | LOGE("Key length (%d) does not match expected size %d\n", key_len, P256_NBYTES); | ||
416 | goto exit; | ||
417 | } | ||
418 | x_bytes[P256_NBYTES - 1] = byte; | ||
419 | for (i = P256_NBYTES - 2; i >= 0; --i) { | ||
420 | if (fscanf(f, " , %u", &byte) != 1) goto exit; | ||
421 | x_bytes[i] = byte; | ||
422 | } | ||
423 | if (fscanf(f, " } , { %u", &byte) != 1) goto exit; | ||
424 | y_bytes[P256_NBYTES - 1] = byte; | ||
425 | for (i = P256_NBYTES - 2; i >= 0; --i) { | ||
426 | if (fscanf(f, " , %u", &byte) != 1) goto exit; | ||
427 | y_bytes[i] = byte; | ||
428 | } | ||
429 | fscanf(f, " } } "); | ||
430 | p256_from_bin(x_bytes, &key->x); | ||
431 | p256_from_bin(y_bytes, &key->y); | ||
432 | } else { | ||
433 | LOGE("Unknown key type %d\n", cert->key_type); | ||
434 | goto exit; | ||
435 | } | 386 | } |
436 | 387 | if (key->len != RSANUMWORDS) { | |
437 | // if the line ends in a comma, this file has more keys. | 388 | LOGE("key length (%d) does not match expected size\n", key->len); |
438 | switch (fgetc(f)) { | 389 | return false; |
439 | case ',': | 390 | } |
440 | // more keys to come. | 391 | for (int i = 1; i < key->len; ++i) { |
441 | break; | 392 | if (fscanf(f.get(), " , %u", &(key->n[i])) != 1) return false; |
442 | 393 | } | |
443 | case EOF: | 394 | if (fscanf(f.get(), " } , { %u", &(key->rr[0])) != 1) return false; |
444 | done = true; | 395 | for (int i = 1; i < key->len; ++i) { |
445 | break; | 396 | if (fscanf(f.get(), " , %u", &(key->rr[i])) != 1) return false; |
446 | 397 | } | |
447 | default: | 398 | fscanf(f.get(), " } } "); |
448 | LOGE("unexpected character between keys\n"); | 399 | |
449 | goto exit; | 400 | LOGI("read key e=%d hash=%d\n", key->exponent, cert.hash_len); |
401 | } else if (cert.key_type == Certificate::EC) { | ||
402 | ECPublicKey* key = cert.ec.get(); | ||
403 | int key_len; | ||
404 | unsigned int byte; | ||
405 | uint8_t x_bytes[P256_NBYTES]; | ||
406 | uint8_t y_bytes[P256_NBYTES]; | ||
407 | if (fscanf(f.get(), " %i , { %u", &key_len, &byte) != 2) return false; | ||
408 | if (key_len != P256_NBYTES) { | ||
409 | LOGE("Key length (%d) does not match expected size %d\n", key_len, P256_NBYTES); | ||
410 | return false; | ||
411 | } | ||
412 | x_bytes[P256_NBYTES - 1] = byte; | ||
413 | for (int i = P256_NBYTES - 2; i >= 0; --i) { | ||
414 | if (fscanf(f.get(), " , %u", &byte) != 1) return false; | ||
415 | x_bytes[i] = byte; | ||
416 | } | ||
417 | if (fscanf(f.get(), " } , { %u", &byte) != 1) return false; | ||
418 | y_bytes[P256_NBYTES - 1] = byte; | ||
419 | for (int i = P256_NBYTES - 2; i >= 0; --i) { | ||
420 | if (fscanf(f.get(), " , %u", &byte) != 1) return false; | ||
421 | y_bytes[i] = byte; | ||
450 | } | 422 | } |
423 | fscanf(f.get(), " } } "); | ||
424 | p256_from_bin(x_bytes, &key->x); | ||
425 | p256_from_bin(y_bytes, &key->y); | ||
426 | } else { | ||
427 | LOGE("Unknown key type %d\n", cert.key_type); | ||
428 | return false; | ||
451 | } | 429 | } |
452 | } | ||
453 | 430 | ||
454 | fclose(f); | 431 | // if the line ends in a comma, this file has more keys. |
455 | return out; | 432 | int ch = fgetc(f.get()); |
433 | if (ch == ',') { | ||
434 | // more keys to come. | ||
435 | continue; | ||
436 | } else if (ch == EOF) { | ||
437 | break; | ||
438 | } else { | ||
439 | LOGE("unexpected character between keys\n"); | ||
440 | return false; | ||
441 | } | ||
442 | } | ||
456 | 443 | ||
457 | exit: | 444 | return true; |
458 | if (f) fclose(f); | ||
459 | free(out); | ||
460 | *numKeys = 0; | ||
461 | return NULL; | ||
462 | } | 445 | } |