blob: 6e158127245be3903c0942d847d82c04b598aa77 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2008 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
Doug Zongker54e2e862009-08-17 13:21:04 -070017#include <errno.h>
Elliott Hughes26dbad22015-01-28 12:09:05 -080018#include <malloc.h>
19#include <stdio.h>
20#include <string.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080021
Mattias Nissler452df6d2016-04-04 16:17:01 +020022#include <algorithm>
23#include <memory>
24
25#include <openssl/ecdsa.h>
26#include <openssl/obj_mac.h>
27
28#include "asn1_decoder.h"
29#include "common.h"
30#include "ui.h"
31#include "verifier.h"
32
Doug Zongker211aebc2011-10-28 15:13:10 -070033extern RecoveryUI* ui;
34
Kenny Root7a4adb52013-10-09 10:14:35 -070035/*
36 * Simple version of PKCS#7 SignedData extraction. This extracts the
37 * signature OCTET STRING to be used for signature verification.
38 *
39 * For full details, see http://www.ietf.org/rfc/rfc3852.txt
40 *
41 * The PKCS#7 structure looks like:
42 *
43 * SEQUENCE (ContentInfo)
44 * OID (ContentType)
45 * [0] (content)
46 * SEQUENCE (SignedData)
47 * INTEGER (version CMSVersion)
48 * SET (DigestAlgorithmIdentifiers)
49 * SEQUENCE (EncapsulatedContentInfo)
50 * [0] (CertificateSet OPTIONAL)
51 * [1] (RevocationInfoChoices OPTIONAL)
52 * SET (SignerInfos)
53 * SEQUENCE (SignerInfo)
54 * INTEGER (CMSVersion)
55 * SEQUENCE (SignerIdentifier)
56 * SEQUENCE (DigestAlgorithmIdentifier)
57 * SEQUENCE (SignatureAlgorithmIdentifier)
58 * OCTET STRING (SignatureValue)
59 */
60static bool read_pkcs7(uint8_t* pkcs7_der, size_t pkcs7_der_len, uint8_t** sig_der,
61 size_t* sig_der_length) {
62 asn1_context_t* ctx = asn1_context_new(pkcs7_der, pkcs7_der_len);
63 if (ctx == NULL) {
64 return false;
65 }
66
67 asn1_context_t* pkcs7_seq = asn1_sequence_get(ctx);
68 if (pkcs7_seq != NULL && asn1_sequence_next(pkcs7_seq)) {
69 asn1_context_t *signed_data_app = asn1_constructed_get(pkcs7_seq);
70 if (signed_data_app != NULL) {
71 asn1_context_t* signed_data_seq = asn1_sequence_get(signed_data_app);
72 if (signed_data_seq != NULL
73 && asn1_sequence_next(signed_data_seq)
74 && asn1_sequence_next(signed_data_seq)
75 && asn1_sequence_next(signed_data_seq)
76 && asn1_constructed_skip_all(signed_data_seq)) {
77 asn1_context_t *sig_set = asn1_set_get(signed_data_seq);
78 if (sig_set != NULL) {
79 asn1_context_t* sig_seq = asn1_sequence_get(sig_set);
80 if (sig_seq != NULL
81 && asn1_sequence_next(sig_seq)
82 && asn1_sequence_next(sig_seq)
83 && asn1_sequence_next(sig_seq)
84 && asn1_sequence_next(sig_seq)) {
85 uint8_t* sig_der_ptr;
86 if (asn1_octet_string_get(sig_seq, &sig_der_ptr, sig_der_length)) {
87 *sig_der = (uint8_t*) malloc(*sig_der_length);
88 if (*sig_der != NULL) {
89 memcpy(*sig_der, sig_der_ptr, *sig_der_length);
90 }
91 }
92 asn1_context_free(sig_seq);
93 }
94 asn1_context_free(sig_set);
95 }
96 asn1_context_free(signed_data_seq);
97 }
98 asn1_context_free(signed_data_app);
99 }
100 asn1_context_free(pkcs7_seq);
101 }
102 asn1_context_free(ctx);
103
104 return *sig_der != NULL;
105}
106
Doug Zongker54e2e862009-08-17 13:21:04 -0700107// Look for an RSA signature embedded in the .ZIP file comment given
108// the path to the zip. Verify it matches one of the given public
109// keys.
110//
111// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered
112// or no key matches the signature).
113
Doug Zongker99916f02014-01-13 14:16:58 -0800114int verify_file(unsigned char* addr, size_t length,
Tao Bao71e3e092016-02-02 14:02:27 -0800115 const std::vector<Certificate>& keys) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700116 ui->SetProgress(0.0);
Doug Zongker54e2e862009-08-17 13:21:04 -0700117
Doug Zongker54e2e862009-08-17 13:21:04 -0700118 // An archive with a whole-file signature will end in six bytes:
119 //
Doug Zongker73ae31c2009-12-09 17:01:45 -0800120 // (2-byte signature start) $ff $ff (2-byte comment size)
Doug Zongker54e2e862009-08-17 13:21:04 -0700121 //
122 // (As far as the ZIP format is concerned, these are part of the
123 // archive comment.) We start by reading this footer, this tells
124 // us how far back from the end we have to start reading to find
125 // the whole comment.
126
127#define FOOTER_SIZE 6
128
Doug Zongker99916f02014-01-13 14:16:58 -0800129 if (length < FOOTER_SIZE) {
130 LOGE("not big enough to contain footer\n");
Doug Zongker54e2e862009-08-17 13:21:04 -0700131 return VERIFY_FAILURE;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800132 }
133
Doug Zongker99916f02014-01-13 14:16:58 -0800134 unsigned char* footer = addr + length - FOOTER_SIZE;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800135
Doug Zongker54e2e862009-08-17 13:21:04 -0700136 if (footer[2] != 0xff || footer[3] != 0xff) {
Doug Zongker30362a62013-04-10 11:32:17 -0700137 LOGE("footer is wrong\n");
Doug Zongker54e2e862009-08-17 13:21:04 -0700138 return VERIFY_FAILURE;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800139 }
140
Doug Zongker28ce47c2011-10-28 10:33:05 -0700141 size_t comment_size = footer[4] + (footer[5] << 8);
142 size_t signature_start = footer[0] + (footer[1] << 8);
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700143 LOGI("comment is %zu bytes; signature %zu bytes from end\n",
Doug Zongker54e2e862009-08-17 13:21:04 -0700144 comment_size, signature_start);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800145
Kenny Root7a4adb52013-10-09 10:14:35 -0700146 if (signature_start <= FOOTER_SIZE) {
147 LOGE("Signature start is in the footer");
Doug Zongker54e2e862009-08-17 13:21:04 -0700148 return VERIFY_FAILURE;
149 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800150
Doug Zongker54e2e862009-08-17 13:21:04 -0700151#define EOCD_HEADER_SIZE 22
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800152
Doug Zongker54e2e862009-08-17 13:21:04 -0700153 // The end-of-central-directory record is 22 bytes plus any
154 // comment length.
155 size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800156
Doug Zongker99916f02014-01-13 14:16:58 -0800157 if (length < eocd_size) {
158 LOGE("not big enough to contain EOCD\n");
Doug Zongker54e2e862009-08-17 13:21:04 -0700159 return VERIFY_FAILURE;
160 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800161
Doug Zongker54e2e862009-08-17 13:21:04 -0700162 // Determine how much of the file is covered by the signature.
163 // This is everything except the signature data and length, which
164 // includes all of the EOCD except for the comment length field (2
165 // bytes) and the comment data.
Doug Zongker99916f02014-01-13 14:16:58 -0800166 size_t signed_len = length - eocd_size + EOCD_HEADER_SIZE - 2;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800167
Doug Zongker99916f02014-01-13 14:16:58 -0800168 unsigned char* eocd = addr + length - eocd_size;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800169
Doug Zongker54e2e862009-08-17 13:21:04 -0700170 // If this is really is the EOCD record, it will begin with the
171 // magic number $50 $4b $05 $06.
172 if (eocd[0] != 0x50 || eocd[1] != 0x4b ||
173 eocd[2] != 0x05 || eocd[3] != 0x06) {
174 LOGE("signature length doesn't match EOCD marker\n");
Doug Zongker54e2e862009-08-17 13:21:04 -0700175 return VERIFY_FAILURE;
176 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800177
Tao Bao71e3e092016-02-02 14:02:27 -0800178 for (size_t i = 4; i < eocd_size-3; ++i) {
Doug Zongker54e2e862009-08-17 13:21:04 -0700179 if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
Doug Zongkerc652e412009-12-08 15:30:09 -0800180 eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
Doug Zongker54e2e862009-08-17 13:21:04 -0700181 // if the sequence $50 $4b $05 $06 appears anywhere after
182 // the real one, minzip will find the later (wrong) one,
183 // which could be exploitable. Fail verification if
184 // this sequence occurs anywhere after the real one.
185 LOGE("EOCD marker occurs after start of EOCD\n");
Doug Zongker54e2e862009-08-17 13:21:04 -0700186 return VERIFY_FAILURE;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800187 }
188 }
189
Doug Zongker54e2e862009-08-17 13:21:04 -0700190#define BUFFER_SIZE 4096
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800191
Doug Zongker30362a62013-04-10 11:32:17 -0700192 bool need_sha1 = false;
193 bool need_sha256 = false;
Tao Bao71e3e092016-02-02 14:02:27 -0800194 for (const auto& key : keys) {
195 switch (key.hash_len) {
Mattias Nissler452df6d2016-04-04 16:17:01 +0200196 case SHA_DIGEST_LENGTH: need_sha1 = true; break;
197 case SHA256_DIGEST_LENGTH: need_sha256 = true; break;
Doug Zongker30362a62013-04-10 11:32:17 -0700198 }
199 }
200
201 SHA_CTX sha1_ctx;
202 SHA256_CTX sha256_ctx;
Mattias Nissler452df6d2016-04-04 16:17:01 +0200203 SHA1_Init(&sha1_ctx);
204 SHA256_Init(&sha256_ctx);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800205
Doug Zongker54e2e862009-08-17 13:21:04 -0700206 double frac = -1.0;
207 size_t so_far = 0;
Doug Zongker54e2e862009-08-17 13:21:04 -0700208 while (so_far < signed_len) {
Doug Zongker99916f02014-01-13 14:16:58 -0800209 size_t size = signed_len - so_far;
210 if (size > BUFFER_SIZE) size = BUFFER_SIZE;
211
Mattias Nissler452df6d2016-04-04 16:17:01 +0200212 if (need_sha1) SHA1_Update(&sha1_ctx, addr + so_far, size);
213 if (need_sha256) SHA256_Update(&sha256_ctx, addr + so_far, size);
Doug Zongker54e2e862009-08-17 13:21:04 -0700214 so_far += size;
Doug Zongker99916f02014-01-13 14:16:58 -0800215
Doug Zongker54e2e862009-08-17 13:21:04 -0700216 double f = so_far / (double)signed_len;
217 if (f > frac + 0.02 || size == so_far) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700218 ui->SetProgress(f);
Doug Zongker54e2e862009-08-17 13:21:04 -0700219 frac = f;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800220 }
221 }
222
Mattias Nissler452df6d2016-04-04 16:17:01 +0200223 uint8_t sha1[SHA_DIGEST_LENGTH];
224 SHA1_Final(sha1, &sha1_ctx);
225 uint8_t sha256[SHA256_DIGEST_LENGTH];
226 SHA256_Final(sha256, &sha256_ctx);
Doug Zongker30362a62013-04-10 11:32:17 -0700227
Tao Bao71e3e092016-02-02 14:02:27 -0800228 uint8_t* sig_der = nullptr;
Kenny Root7a4adb52013-10-09 10:14:35 -0700229 size_t sig_der_length = 0;
230
231 size_t signature_size = signature_start - FOOTER_SIZE;
232 if (!read_pkcs7(eocd + eocd_size - signature_start, signature_size, &sig_der,
233 &sig_der_length)) {
234 LOGE("Could not find signature DER block\n");
Kenny Root7a4adb52013-10-09 10:14:35 -0700235 return VERIFY_FAILURE;
236 }
Kenny Root7a4adb52013-10-09 10:14:35 -0700237
238 /*
239 * Check to make sure at least one of the keys matches the signature. Since
240 * any key can match, we need to try each before determining a verification
241 * failure has happened.
242 */
Tao Bao71e3e092016-02-02 14:02:27 -0800243 size_t i = 0;
244 for (const auto& key : keys) {
Doug Zongker30362a62013-04-10 11:32:17 -0700245 const uint8_t* hash;
Mattias Nissler452df6d2016-04-04 16:17:01 +0200246 int hash_nid;
Tao Bao71e3e092016-02-02 14:02:27 -0800247 switch (key.hash_len) {
Mattias Nissler452df6d2016-04-04 16:17:01 +0200248 case SHA_DIGEST_LENGTH:
249 hash = sha1;
250 hash_nid = NID_sha1;
251 break;
252 case SHA256_DIGEST_LENGTH:
253 hash = sha256;
254 hash_nid = NID_sha256;
255 break;
256 default:
257 continue;
Doug Zongker30362a62013-04-10 11:32:17 -0700258 }
259
Doug Zongker73ae31c2009-12-09 17:01:45 -0800260 // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
Doug Zongker54e2e862009-08-17 13:21:04 -0700261 // the signing tool appends after the signature itself.
Mattias Nissler452df6d2016-04-04 16:17:01 +0200262 if (key.key_type == Certificate::KEY_TYPE_RSA) {
263 if (!RSA_verify(hash_nid, hash, key.hash_len, sig_der,
264 sig_der_length, key.rsa.get())) {
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700265 LOGI("failed to verify against RSA key %zu\n", i);
Kenny Root7a4adb52013-10-09 10:14:35 -0700266 continue;
267 }
268
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700269 LOGI("whole-file signature verified against RSA key %zu\n", i);
Kenny Root7a4adb52013-10-09 10:14:35 -0700270 free(sig_der);
271 return VERIFY_SUCCESS;
Mattias Nissler452df6d2016-04-04 16:17:01 +0200272 } else if (key.key_type == Certificate::KEY_TYPE_EC
273 && key.hash_len == SHA256_DIGEST_LENGTH) {
274 if (!ECDSA_verify(0, hash, key.hash_len, sig_der,
275 sig_der_length, key.ec.get())) {
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700276 LOGI("failed to verify against EC key %zu\n", i);
Kenny Root7a4adb52013-10-09 10:14:35 -0700277 continue;
278 }
279
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700280 LOGI("whole-file signature verified against EC key %zu\n", i);
Kenny Root7a4adb52013-10-09 10:14:35 -0700281 free(sig_der);
Doug Zongker54e2e862009-08-17 13:21:04 -0700282 return VERIFY_SUCCESS;
Doug Zongker6c249f72012-11-02 15:04:05 -0700283 } else {
Tao Bao71e3e092016-02-02 14:02:27 -0800284 LOGI("Unknown key type %d\n", key.key_type);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800285 }
Tao Bao71e3e092016-02-02 14:02:27 -0800286 i++;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800287 }
Kenny Root7a4adb52013-10-09 10:14:35 -0700288 free(sig_der);
Doug Zongker54e2e862009-08-17 13:21:04 -0700289 LOGE("failed to verify whole-file signature\n");
290 return VERIFY_FAILURE;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800291}
Doug Zongker6c249f72012-11-02 15:04:05 -0700292
Mattias Nissler452df6d2016-04-04 16:17:01 +0200293std::unique_ptr<RSA, RSADeleter> parse_rsa_key(FILE* file, uint32_t exponent) {
294 // Read key length in words and n0inv. n0inv is a precomputed montgomery
295 // parameter derived from the modulus and can be used to speed up
296 // verification. n0inv is 32 bits wide here, assuming the verification logic
297 // uses 32 bit arithmetic. However, BoringSSL may use a word size of 64 bits
298 // internally, in which case we don't have a valid n0inv. Thus, we just
299 // ignore the montgomery parameters and have BoringSSL recompute them
300 // internally. If/When the speedup from using the montgomery parameters
301 // becomes relevant, we can add more sophisticated code here to obtain a
302 // 64-bit n0inv and initialize the montgomery parameters in the key object.
303 uint32_t key_len_words = 0;
304 uint32_t n0inv = 0;
305 if (fscanf(file, " %i , 0x%x", &key_len_words, &n0inv) != 2) {
306 return nullptr;
307 }
308
309 if (key_len_words > 8192 / 32) {
310 LOGE("key length (%d) too large\n", key_len_words);
311 return nullptr;
312 }
313
314 // Read the modulus.
315 std::unique_ptr<uint32_t[]> modulus(new uint32_t[key_len_words]);
316 if (fscanf(file, " , { %u", &modulus[0]) != 1) {
317 return nullptr;
318 }
319 for (uint32_t i = 1; i < key_len_words; ++i) {
320 if (fscanf(file, " , %u", &modulus[i]) != 1) {
321 return nullptr;
322 }
323 }
324
325 // Cconvert from little-endian array of little-endian words to big-endian
326 // byte array suitable as input for BN_bin2bn.
327 std::reverse((uint8_t*)modulus.get(),
328 (uint8_t*)(modulus.get() + key_len_words));
329
330 // The next sequence of values is the montgomery parameter R^2. Since we
331 // generally don't have a valid |n0inv|, we ignore this (see comment above).
332 uint32_t rr_value;
333 if (fscanf(file, " } , { %u", &rr_value) != 1) {
334 return nullptr;
335 }
336 for (uint32_t i = 1; i < key_len_words; ++i) {
337 if (fscanf(file, " , %u", &rr_value) != 1) {
338 return nullptr;
339 }
340 }
341 if (fscanf(file, " } } ") != 0) {
342 return nullptr;
343 }
344
345 // Initialize the key.
346 std::unique_ptr<RSA, RSADeleter> key(RSA_new());
347 if (!key) {
348 return nullptr;
349 }
350
351 key->n = BN_bin2bn((uint8_t*)modulus.get(),
352 key_len_words * sizeof(uint32_t), NULL);
353 if (!key->n) {
354 return nullptr;
355 }
356
357 key->e = BN_new();
358 if (!key->e || !BN_set_word(key->e, exponent)) {
359 return nullptr;
360 }
361
362 return key;
363}
364
365struct BNDeleter {
366 void operator()(BIGNUM* bn) {
367 BN_free(bn);
368 }
369};
370
371std::unique_ptr<EC_KEY, ECKEYDeleter> parse_ec_key(FILE* file) {
372 uint32_t key_len_bytes = 0;
373 if (fscanf(file, " %i", &key_len_bytes) != 1) {
374 return nullptr;
375 }
376
377 std::unique_ptr<EC_GROUP, void (*)(EC_GROUP*)> group(
378 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1), EC_GROUP_free);
379 if (!group) {
380 return nullptr;
381 }
382
383 // Verify that |key_len| matches the group order.
384 if (key_len_bytes != BN_num_bytes(EC_GROUP_get0_order(group.get()))) {
385 return nullptr;
386 }
387
388 // Read the public key coordinates. Note that the byte order in the file is
389 // little-endian, so we convert to big-endian here.
390 std::unique_ptr<uint8_t[]> bytes(new uint8_t[key_len_bytes]);
391 std::unique_ptr<BIGNUM, BNDeleter> point[2];
392 for (int i = 0; i < 2; ++i) {
393 unsigned int byte = 0;
394 if (fscanf(file, " , { %u", &byte) != 1) {
395 return nullptr;
396 }
397 bytes[key_len_bytes - 1] = byte;
398
399 for (size_t i = 1; i < key_len_bytes; ++i) {
400 if (fscanf(file, " , %u", &byte) != 1) {
401 return nullptr;
402 }
403 bytes[key_len_bytes - i - 1] = byte;
404 }
405
406 point[i].reset(BN_bin2bn(bytes.get(), key_len_bytes, nullptr));
407 if (!point[i]) {
408 return nullptr;
409 }
410
411 if (fscanf(file, " }") != 0) {
412 return nullptr;
413 }
414 }
415
416 if (fscanf(file, " } ") != 0) {
417 return nullptr;
418 }
419
420 // Create and initialize the key.
421 std::unique_ptr<EC_KEY, ECKEYDeleter> key(EC_KEY_new());
422 if (!key || !EC_KEY_set_group(key.get(), group.get()) ||
423 !EC_KEY_set_public_key_affine_coordinates(key.get(), point[0].get(),
424 point[1].get())) {
425 return nullptr;
426 }
427
428 return key;
429}
430
Doug Zongker6c249f72012-11-02 15:04:05 -0700431// Reads a file containing one or more public keys as produced by
432// DumpPublicKey: this is an RSAPublicKey struct as it would appear
433// as a C source literal, eg:
434//
435// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
436//
437// For key versions newer than the original 2048-bit e=3 keys
438// supported by Android, the string is preceded by a version
439// identifier, eg:
440//
441// "v2 {64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
442//
443// (Note that the braces and commas in this example are actual
444// characters the parser expects to find in the file; the ellipses
445// indicate more numbers omitted from this example.)
446//
447// The file may contain multiple keys in this format, separated by
448// commas. The last key must not be followed by a comma.
449//
Doug Zongker30362a62013-04-10 11:32:17 -0700450// A Certificate is a pair of an RSAPublicKey and a particular hash
451// (we support SHA-1 and SHA-256; we store the hash length to signify
452// which is being used). The hash used is implied by the version number.
453//
454// 1: 2048-bit RSA key with e=3 and SHA-1 hash
455// 2: 2048-bit RSA key with e=65537 and SHA-1 hash
456// 3: 2048-bit RSA key with e=3 and SHA-256 hash
457// 4: 2048-bit RSA key with e=65537 and SHA-256 hash
Kenny Root7a4adb52013-10-09 10:14:35 -0700458// 5: 256-bit EC key using the NIST P-256 curve parameters and SHA-256 hash
Doug Zongker30362a62013-04-10 11:32:17 -0700459//
Tao Bao71e3e092016-02-02 14:02:27 -0800460// Returns true on success, and appends the found keys (at least one) to certs.
461// Otherwise returns false if the file failed to parse, or if it contains zero
462// keys. The contents in certs would be unspecified on failure.
463bool load_keys(const char* filename, std::vector<Certificate>& certs) {
464 std::unique_ptr<FILE, decltype(&fclose)> f(fopen(filename, "r"), fclose);
465 if (!f) {
Doug Zongker6c249f72012-11-02 15:04:05 -0700466 LOGE("opening %s: %s\n", filename, strerror(errno));
Tao Bao71e3e092016-02-02 14:02:27 -0800467 return false;
Doug Zongker6c249f72012-11-02 15:04:05 -0700468 }
469
Tao Bao71e3e092016-02-02 14:02:27 -0800470 while (true) {
Mattias Nissler452df6d2016-04-04 16:17:01 +0200471 certs.emplace_back(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
Tao Bao71e3e092016-02-02 14:02:27 -0800472 Certificate& cert = certs.back();
Mattias Nissler452df6d2016-04-04 16:17:01 +0200473 uint32_t exponent = 0;
Doug Zongker6c249f72012-11-02 15:04:05 -0700474
Tao Bao71e3e092016-02-02 14:02:27 -0800475 char start_char;
476 if (fscanf(f.get(), " %c", &start_char) != 1) return false;
477 if (start_char == '{') {
478 // a version 1 key has no version specifier.
Mattias Nissler452df6d2016-04-04 16:17:01 +0200479 cert.key_type = Certificate::KEY_TYPE_RSA;
480 exponent = 3;
481 cert.hash_len = SHA_DIGEST_LENGTH;
Tao Bao71e3e092016-02-02 14:02:27 -0800482 } else if (start_char == 'v') {
483 int version;
484 if (fscanf(f.get(), "%d {", &version) != 1) return false;
485 switch (version) {
486 case 2:
Mattias Nissler452df6d2016-04-04 16:17:01 +0200487 cert.key_type = Certificate::KEY_TYPE_RSA;
488 exponent = 65537;
489 cert.hash_len = SHA_DIGEST_LENGTH;
Tao Bao71e3e092016-02-02 14:02:27 -0800490 break;
491 case 3:
Mattias Nissler452df6d2016-04-04 16:17:01 +0200492 cert.key_type = Certificate::KEY_TYPE_RSA;
493 exponent = 3;
494 cert.hash_len = SHA256_DIGEST_LENGTH;
Tao Bao71e3e092016-02-02 14:02:27 -0800495 break;
496 case 4:
Mattias Nissler452df6d2016-04-04 16:17:01 +0200497 cert.key_type = Certificate::KEY_TYPE_RSA;
498 exponent = 65537;
499 cert.hash_len = SHA256_DIGEST_LENGTH;
Tao Bao71e3e092016-02-02 14:02:27 -0800500 break;
501 case 5:
Mattias Nissler452df6d2016-04-04 16:17:01 +0200502 cert.key_type = Certificate::KEY_TYPE_EC;
503 cert.hash_len = SHA256_DIGEST_LENGTH;
Tao Bao71e3e092016-02-02 14:02:27 -0800504 break;
505 default:
506 return false;
Doug Zongker6c249f72012-11-02 15:04:05 -0700507 }
Tao Bao71e3e092016-02-02 14:02:27 -0800508 }
Doug Zongker6c249f72012-11-02 15:04:05 -0700509
Mattias Nissler452df6d2016-04-04 16:17:01 +0200510 if (cert.key_type == Certificate::KEY_TYPE_RSA) {
511 cert.rsa = parse_rsa_key(f.get(), exponent);
512 if (!cert.rsa) {
513 return false;
Doug Zongker6c249f72012-11-02 15:04:05 -0700514 }
Tao Bao71e3e092016-02-02 14:02:27 -0800515
Mattias Nissler452df6d2016-04-04 16:17:01 +0200516 LOGI("read key e=%d hash=%d\n", exponent, cert.hash_len);
517 } else if (cert.key_type == Certificate::KEY_TYPE_EC) {
518 cert.ec = parse_ec_key(f.get());
519 if (!cert.ec) {
520 return false;
Tao Bao71e3e092016-02-02 14:02:27 -0800521 }
Tao Bao71e3e092016-02-02 14:02:27 -0800522 } else {
523 LOGE("Unknown key type %d\n", cert.key_type);
524 return false;
525 }
526
527 // if the line ends in a comma, this file has more keys.
528 int ch = fgetc(f.get());
529 if (ch == ',') {
530 // more keys to come.
531 continue;
532 } else if (ch == EOF) {
533 break;
534 } else {
535 LOGE("unexpected character between keys\n");
536 return false;
Doug Zongker6c249f72012-11-02 15:04:05 -0700537 }
538 }
539
Tao Bao71e3e092016-02-02 14:02:27 -0800540 return true;
Doug Zongker6c249f72012-11-02 15:04:05 -0700541}