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 <errno.h>
18#include <stdio.h>
19#include <stdlib.h>
20
21#include <memory>
22#include <string>
23
24#include <android-base/file.h>
25#include <android-base/test_utils.h>
26#include <android-base/unique_fd.h>
27#include <fec/io.h>
28#include <mincrypt/rsa.h>
29#include <mincrypt/sha.h>
30#include <mincrypt/sha256.h>
31#include <sparse/sparse.h>
32
33static RSAPublicKey* load_key(const char* path) {
34  std::string content;
35  if (!android::base::ReadFileToString(path, &content)) {
36    fprintf(stderr, "Failed to load key from %s\n", path);
37    return nullptr;
38  }
39
40  std::unique_ptr<RSAPublicKey> key(new RSAPublicKey);
41  if (!key) {
42    fprintf(stderr, "Failed to malloc key\n");
43    return nullptr;
44  }
45
46  memcpy(key.get(), content.data(), sizeof(RSAPublicKey));
47
48  if (key->len != RSANUMWORDS) {
49    fprintf(stderr, "Invalid key length %d\n", key->len);
50    return nullptr;
51  }
52
53  return key.release();
54}
55
56static int verify_table(const char* key_path, const uint8_t* signature,
57                        const char* table, uint32_t table_length) {
58  // Hash the table
59  uint8_t hash_buf[SHA256_DIGEST_LENGTH];
60  SHA256_hash(reinterpret_cast<const void*>(table), table_length, hash_buf);
61
62  // Now get the public key from the keyfile
63  std::unique_ptr<RSAPublicKey> key(load_key(key_path));
64  if (!key) {
65    fprintf(stderr, "Couldn't load verity keys\n");
66    return -1;
67  }
68
69  // Verify the result
70  if (!RSA_verify(key.get(), signature, RSANUMBYTES, hash_buf, SHA256_DIGEST_SIZE)) {
71    fprintf(stderr, "Couldn't verify table\n");
72    return -1;
73  }
74
75  return 0;
76}
77
78int main(int argc, char* argv[]) {
79  if (argc != 4 || strcmp(argv[2], "-mincrypt") != 0) {
80    printf("Usage: %s <image> -mincrypt <verity_key>\n"
81           "  image       the image file (raw or sparse image) to be verified\n"
82           "  verity_key  the verity key in mincrypt format (/verity_key on device)\n", argv[0]);
83    return 2;
84  }
85
86  // Get the raw image.
87  android::base::unique_fd fd(open(argv[1], O_RDONLY));
88  if (!fd) {
89    fprintf(stderr, "failed to open %s: %s\n", argv[1], strerror(errno));
90    return 1;
91  }
92
93  struct sparse_file* file = sparse_file_import_auto(fd, false, false);
94  if (file == nullptr) {
95    fprintf(stderr, "failed to read file %s\n", argv[1]);
96    return 1;
97  }
98
99  TemporaryFile tf;
100  if (sparse_file_write(file, tf.fd, false, false, false) < 0) {
101    fprintf(stderr, "failed to write output file\n");
102    return 1;
103  }
104  sparse_file_destroy(file);
105
106  // Verify.
107  fec::io input(tf.path);
108  if (!input) {
109    return 1;
110  }
111
112  fec_verity_metadata verity;
113  if (!input.get_verity_metadata(verity)) {
114    fprintf(stderr, "failed to get verity metadata\n");
115    return 1;
116  }
117
118  int ret = verify_table(argv[3], verity.signature, verity.table, verity.table_length);
119  printf("%s\n", ret == 0 ? "VERIFIED" : "FAILED");
120  return ret;
121}
122