summaryrefslogtreecommitdiffstats
path: root/verifier.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'verifier.cpp')
-rw-r--r--verifier.cpp90
1 files changed, 28 insertions, 62 deletions
diff --git a/verifier.cpp b/verifier.cpp
index 0930fbd15..3d4f603a2 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -111,15 +111,10 @@ static bool read_pkcs7(uint8_t* pkcs7_der, size_t pkcs7_der_len, uint8_t** sig_d
// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered
// or no key matches the signature).
-int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys) {
+int verify_file(unsigned char* addr, size_t length,
+ const Certificate* pKeys, unsigned int numKeys) {
ui->SetProgress(0.0);
- FILE* f = fopen(path, "rb");
- if (f == NULL) {
- LOGE("failed to open %s (%s)\n", path, strerror(errno));
- return VERIFY_FAILURE;
- }
-
// An archive with a whole-file signature will end in six bytes:
//
// (2-byte signature start) $ff $ff (2-byte comment size)
@@ -131,33 +126,31 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
#define FOOTER_SIZE 6
- if (fseek(f, -FOOTER_SIZE, SEEK_END) != 0) {
- LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
- fclose(f);
+ if (length < FOOTER_SIZE) {
+ LOGE("not big enough to contain footer\n");
return VERIFY_FAILURE;
}
- unsigned char footer[FOOTER_SIZE];
- if (fread(footer, 1, FOOTER_SIZE, f) != FOOTER_SIZE) {
- LOGE("failed to read footer from %s (%s)\n", path, strerror(errno));
- fclose(f);
- return VERIFY_FAILURE;
- }
+ unsigned char* footer = addr + length - FOOTER_SIZE;
if (footer[2] != 0xff || footer[3] != 0xff) {
LOGE("footer is wrong\n");
- fclose(f);
return VERIFY_FAILURE;
}
size_t comment_size = footer[4] + (footer[5] << 8);
size_t signature_start = footer[0] + (footer[1] << 8);
- LOGI("comment is %d bytes; signature %d bytes from end\n",
+ LOGI("comment is %zu bytes; signature %zu bytes from end\n",
comment_size, signature_start);
+ if (signature_start > comment_size) {
+ LOGE("signature start: %zu is larger than comment size: %zu\n", signature_start,
+ comment_size);
+ return VERIFY_FAILURE;
+ }
+
if (signature_start <= FOOTER_SIZE) {
LOGE("Signature start is in the footer");
- fclose(f);
return VERIFY_FAILURE;
}
@@ -167,9 +160,8 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
// comment length.
size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
- if (fseek(f, -eocd_size, SEEK_END) != 0) {
- LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
- fclose(f);
+ if (length < eocd_size) {
+ LOGE("not big enough to contain EOCD\n");
return VERIFY_FAILURE;
}
@@ -177,26 +169,15 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
// This is everything except the signature data and length, which
// includes all of the EOCD except for the comment length field (2
// bytes) and the comment data.
- size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2;
+ size_t signed_len = length - eocd_size + EOCD_HEADER_SIZE - 2;
- unsigned char* eocd = (unsigned char*)malloc(eocd_size);
- if (eocd == NULL) {
- LOGE("malloc for EOCD record failed\n");
- fclose(f);
- return VERIFY_FAILURE;
- }
- if (fread(eocd, 1, eocd_size, f) != eocd_size) {
- LOGE("failed to read eocd from %s (%s)\n", path, strerror(errno));
- fclose(f);
- return VERIFY_FAILURE;
- }
+ unsigned char* eocd = addr + length - eocd_size;
// If this is really is the EOCD record, it will begin with the
// magic number $50 $4b $05 $06.
if (eocd[0] != 0x50 || eocd[1] != 0x4b ||
eocd[2] != 0x05 || eocd[3] != 0x06) {
LOGE("signature length doesn't match EOCD marker\n");
- fclose(f);
return VERIFY_FAILURE;
}
@@ -209,7 +190,6 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
// which could be exploitable. Fail verification if
// this sequence occurs anywhere after the real one.
LOGE("EOCD marker occurs after start of EOCD\n");
- fclose(f);
return VERIFY_FAILURE;
}
}
@@ -229,35 +209,23 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
SHA256_CTX sha256_ctx;
SHA_init(&sha1_ctx);
SHA256_init(&sha256_ctx);
- unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
- if (buffer == NULL) {
- LOGE("failed to alloc memory for sha1 buffer\n");
- fclose(f);
- return VERIFY_FAILURE;
- }
double frac = -1.0;
size_t so_far = 0;
- fseek(f, 0, SEEK_SET);
while (so_far < signed_len) {
- size_t size = BUFFER_SIZE;
- if (signed_len - so_far < size) size = signed_len - so_far;
- if (fread(buffer, 1, size, f) != size) {
- LOGE("failed to read data from %s (%s)\n", path, strerror(errno));
- fclose(f);
- return VERIFY_FAILURE;
- }
- if (need_sha1) SHA_update(&sha1_ctx, buffer, size);
- if (need_sha256) SHA256_update(&sha256_ctx, buffer, size);
+ size_t size = signed_len - so_far;
+ if (size > BUFFER_SIZE) size = BUFFER_SIZE;
+
+ if (need_sha1) SHA_update(&sha1_ctx, addr + so_far, size);
+ if (need_sha256) SHA256_update(&sha256_ctx, addr + so_far, size);
so_far += size;
+
double f = so_far / (double)signed_len;
if (f > frac + 0.02 || size == so_far) {
ui->SetProgress(f);
frac = f;
}
}
- fclose(f);
- free(buffer);
const uint8_t* sha1 = SHA_final(&sha1_ctx);
const uint8_t* sha256 = SHA256_final(&sha256_ctx);
@@ -269,10 +237,8 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
if (!read_pkcs7(eocd + eocd_size - signature_start, signature_size, &sig_der,
&sig_der_length)) {
LOGE("Could not find signature DER block\n");
- free(eocd);
return VERIFY_FAILURE;
}
- free(eocd);
/*
* Check to make sure at least one of the keys matches the signature. Since
@@ -292,24 +258,24 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
if (pKeys[i].key_type == Certificate::RSA) {
if (sig_der_length < RSANUMBYTES) {
// "signature" block isn't big enough to contain an RSA block.
- LOGI("signature is too short for RSA key %d\n", i);
+ LOGI("signature is too short for RSA key %zu\n", i);
continue;
}
if (!RSA_verify(pKeys[i].rsa, sig_der, RSANUMBYTES,
hash, pKeys[i].hash_len)) {
- LOGI("failed to verify against RSA key %d\n", i);
+ LOGI("failed to verify against RSA key %zu\n", i);
continue;
}
- LOGI("whole-file signature verified against RSA key %d\n", i);
+ LOGI("whole-file signature verified against RSA key %zu\n", i);
free(sig_der);
return VERIFY_SUCCESS;
} else if (pKeys[i].key_type == Certificate::EC
&& pKeys[i].hash_len == SHA256_DIGEST_SIZE) {
p256_int r, s;
if (!dsa_sig_unpack(sig_der, sig_der_length, &r, &s)) {
- LOGI("Not a DSA signature block for EC key %d\n", i);
+ LOGI("Not a DSA signature block for EC key %zu\n", i);
continue;
}
@@ -317,11 +283,11 @@ int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys
p256_from_bin(hash, &p256_hash);
if (!p256_ecdsa_verify(&(pKeys[i].ec->x), &(pKeys[i].ec->y),
&p256_hash, &r, &s)) {
- LOGI("failed to verify against EC key %d\n", i);
+ LOGI("failed to verify against EC key %zu\n", i);
continue;
}
- LOGI("whole-file signature verified against EC key %d\n", i);
+ LOGI("whole-file signature verified against EC key %zu\n", i);
free(sig_der);
return VERIFY_SUCCESS;
} else {