aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'verifier.cpp')
-rw-r--r--verifier.cpp80
1 files changed, 63 insertions, 17 deletions
diff --git a/verifier.cpp b/verifier.cpp
index 5f4c981e..782a8386 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -20,6 +20,7 @@
20 20
21#include "mincrypt/rsa.h" 21#include "mincrypt/rsa.h"
22#include "mincrypt/sha.h" 22#include "mincrypt/sha.h"
23#include "mincrypt/sha256.h"
23 24
24#include <string.h> 25#include <string.h>
25#include <stdio.h> 26#include <stdio.h>
@@ -34,7 +35,7 @@ extern RecoveryUI* ui;
34// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered 35// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered
35// or no key matches the signature). 36// or no key matches the signature).
36 37
37int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) { 38int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys) {
38 ui->SetProgress(0.0); 39 ui->SetProgress(0.0);
39 40
40 FILE* f = fopen(path, "rb"); 41 FILE* f = fopen(path, "rb");
@@ -68,6 +69,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
68 } 69 }
69 70
70 if (footer[2] != 0xff || footer[3] != 0xff) { 71 if (footer[2] != 0xff || footer[3] != 0xff) {
72 LOGE("footer is wrong\n");
71 fclose(f); 73 fclose(f);
72 return VERIFY_FAILURE; 74 return VERIFY_FAILURE;
73 } 75 }
@@ -139,8 +141,19 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
139 141
140#define BUFFER_SIZE 4096 142#define BUFFER_SIZE 4096
141 143
142 SHA_CTX ctx; 144 bool need_sha1 = false;
143 SHA_init(&ctx); 145 bool need_sha256 = false;
146 for (i = 0; i < numKeys; ++i) {
147 switch (pKeys[i].hash_len) {
148 case SHA_DIGEST_SIZE: need_sha1 = true; break;
149 case SHA256_DIGEST_SIZE: need_sha256 = true; break;
150 }
151 }
152
153 SHA_CTX sha1_ctx;
154 SHA256_CTX sha256_ctx;
155 SHA_init(&sha1_ctx);
156 SHA256_init(&sha256_ctx);
144 unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE); 157 unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
145 if (buffer == NULL) { 158 if (buffer == NULL) {
146 LOGE("failed to alloc memory for sha1 buffer\n"); 159 LOGE("failed to alloc memory for sha1 buffer\n");
@@ -159,7 +172,8 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
159 fclose(f); 172 fclose(f);
160 return VERIFY_FAILURE; 173 return VERIFY_FAILURE;
161 } 174 }
162 SHA_update(&ctx, buffer, size); 175 if (need_sha1) SHA_update(&sha1_ctx, buffer, size);
176 if (need_sha256) SHA256_update(&sha256_ctx, buffer, size);
163 so_far += size; 177 so_far += size;
164 double f = so_far / (double)signed_len; 178 double f = so_far / (double)signed_len;
165 if (f > frac + 0.02 || size == so_far) { 179 if (f > frac + 0.02 || size == so_far) {
@@ -170,12 +184,21 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
170 fclose(f); 184 fclose(f);
171 free(buffer); 185 free(buffer);
172 186
173 const uint8_t* sha1 = SHA_final(&ctx); 187 const uint8_t* sha1 = SHA_final(&sha1_ctx);
188 const uint8_t* sha256 = SHA256_final(&sha256_ctx);
189
174 for (i = 0; i < numKeys; ++i) { 190 for (i = 0; i < numKeys; ++i) {
191 const uint8_t* hash;
192 switch (pKeys[i].hash_len) {
193 case SHA_DIGEST_SIZE: hash = sha1; break;
194 case SHA256_DIGEST_SIZE: hash = sha256; break;
195 default: continue;
196 }
197
175 // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that 198 // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
176 // the signing tool appends after the signature itself. 199 // the signing tool appends after the signature itself.
177 if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES, 200 if (RSA_verify(pKeys[i].public_key, eocd + eocd_size - 6 - RSANUMBYTES,
178 RSANUMBYTES, sha1)) { 201 RSANUMBYTES, hash, pKeys[i].hash_len)) {
179 LOGI("whole-file signature verified against key %d\n", i); 202 LOGI("whole-file signature verified against key %d\n", i);
180 free(eocd); 203 free(eocd);
181 return VERIFY_SUCCESS; 204 return VERIFY_SUCCESS;
@@ -207,10 +230,19 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
207// The file may contain multiple keys in this format, separated by 230// The file may contain multiple keys in this format, separated by
208// commas. The last key must not be followed by a comma. 231// commas. The last key must not be followed by a comma.
209// 232//
233// A Certificate is a pair of an RSAPublicKey and a particular hash
234// (we support SHA-1 and SHA-256; we store the hash length to signify
235// which is being used). The hash used is implied by the version number.
236//
237// 1: 2048-bit RSA key with e=3 and SHA-1 hash
238// 2: 2048-bit RSA key with e=65537 and SHA-1 hash
239// 3: 2048-bit RSA key with e=3 and SHA-256 hash
240// 4: 2048-bit RSA key with e=65537 and SHA-256 hash
241//
210// Returns NULL if the file failed to parse, or if it contain zero keys. 242// Returns NULL if the file failed to parse, or if it contain zero keys.
211RSAPublicKey* 243Certificate*
212load_keys(const char* filename, int* numKeys) { 244load_keys(const char* filename, int* numKeys) {
213 RSAPublicKey* out = NULL; 245 Certificate* out = NULL;
214 *numKeys = 0; 246 *numKeys = 0;
215 247
216 FILE* f = fopen(filename, "r"); 248 FILE* f = fopen(filename, "r");
@@ -224,24 +256,38 @@ load_keys(const char* filename, int* numKeys) {
224 bool done = false; 256 bool done = false;
225 while (!done) { 257 while (!done) {
226 ++*numKeys; 258 ++*numKeys;
227 out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey)); 259 out = (Certificate*)realloc(out, *numKeys * sizeof(Certificate));
228 RSAPublicKey* key = out + (*numKeys - 1); 260 Certificate* cert = out + (*numKeys - 1);
261 cert->public_key = (RSAPublicKey*)malloc(sizeof(RSAPublicKey));
229 262
230 char start_char; 263 char start_char;
231 if (fscanf(f, " %c", &start_char) != 1) goto exit; 264 if (fscanf(f, " %c", &start_char) != 1) goto exit;
232 if (start_char == '{') { 265 if (start_char == '{') {
233 // a version 1 key has no version specifier. 266 // a version 1 key has no version specifier.
234 key->exponent = 3; 267 cert->public_key->exponent = 3;
268 cert->hash_len = SHA_DIGEST_SIZE;
235 } else if (start_char == 'v') { 269 } else if (start_char == 'v') {
236 int version; 270 int version;
237 if (fscanf(f, "%d {", &version) != 1) goto exit; 271 if (fscanf(f, "%d {", &version) != 1) goto exit;
238 if (version == 2) { 272 switch (version) {
239 key->exponent = 65537; 273 case 2:
240 } else { 274 cert->public_key->exponent = 65537;
241 goto exit; 275 cert->hash_len = SHA_DIGEST_SIZE;
276 break;
277 case 3:
278 cert->public_key->exponent = 3;
279 cert->hash_len = SHA256_DIGEST_SIZE;
280 break;
281 case 4:
282 cert->public_key->exponent = 65537;
283 cert->hash_len = SHA256_DIGEST_SIZE;
284 break;
285 default:
286 goto exit;
242 } 287 }
243 } 288 }
244 289
290 RSAPublicKey* key = cert->public_key;
245 if (fscanf(f, " %i , 0x%x , { %u", 291 if (fscanf(f, " %i , 0x%x , { %u",
246 &(key->len), &(key->n0inv), &(key->n[0])) != 3) { 292 &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
247 goto exit; 293 goto exit;
@@ -274,7 +320,7 @@ load_keys(const char* filename, int* numKeys) {
274 goto exit; 320 goto exit;
275 } 321 }
276 322
277 LOGI("read key e=%d\n", key->exponent); 323 LOGI("read key e=%d hash=%d\n", key->exponent, cert->hash_len);
278 } 324 }
279 } 325 }
280 326