OSDN Git Service

am d74629e0: Separate the reflect and accept tests.
[android-x86/system-extras.git] / verity / verify_boot_signature.c
1 /*
2  * Copyright (C) 2014 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 #define _LARGEFILE64_SOURCE
18
19 #include <endian.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27
28 #include <openssl/asn1.h>
29 #include <openssl/asn1t.h>
30 #include <openssl/err.h>
31 #include <openssl/evp.h>
32 #include <openssl/rsa.h>
33 #include <openssl/x509.h>
34
35 #include "bootimg.h"
36
37 #define FORMAT_VERSION 1
38 #define BUFFER_SIZE (1024 * 1024)
39
40 typedef struct {
41     ASN1_STRING *target;
42     ASN1_INTEGER *length;
43 } AuthAttrs;
44
45 ASN1_SEQUENCE(AuthAttrs) = {
46     ASN1_SIMPLE(AuthAttrs, target, ASN1_PRINTABLE),
47     ASN1_SIMPLE(AuthAttrs, length, ASN1_INTEGER)
48 } ASN1_SEQUENCE_END(AuthAttrs)
49
50 IMPLEMENT_ASN1_FUNCTIONS(AuthAttrs)
51
52 typedef struct {
53     ASN1_INTEGER *formatVersion;
54     X509 *certificate;
55     X509_ALGOR *algorithmIdentifier;
56     AuthAttrs *authenticatedAttributes;
57     ASN1_OCTET_STRING *signature;
58 } BootSignature;
59
60 ASN1_SEQUENCE(BootSignature) = {
61     ASN1_SIMPLE(BootSignature, formatVersion, ASN1_INTEGER),
62     ASN1_SIMPLE(BootSignature, certificate, X509),
63     ASN1_SIMPLE(BootSignature, algorithmIdentifier, X509_ALGOR),
64     ASN1_SIMPLE(BootSignature, authenticatedAttributes, AuthAttrs),
65     ASN1_SIMPLE(BootSignature, signature, ASN1_OCTET_STRING)
66 } ASN1_SEQUENCE_END(BootSignature)
67
68 IMPLEMENT_ASN1_FUNCTIONS(BootSignature)
69
70 static BIO *g_error = NULL;
71
72 /**
73  * Rounds n up to the nearest multiple of page_size
74  * @param n The value to round
75  * @param page_size Page size
76  */
77 static uint64_t page_align(uint64_t n, uint64_t page_size)
78 {
79     return (((n + page_size - 1) / page_size) * page_size);
80 }
81
82 /**
83  * Calculates the offset to the beginning of the BootSignature block
84  * based on the boot image header. The signature will start after the
85  * the boot image contents.
86  * @param fd File descriptor to the boot image
87  * @param offset Receives the offset in bytes
88  */
89 static int get_signature_offset(int fd, off64_t *offset)
90 {
91     int i;
92     struct boot_img_hdr hdr;
93
94     if (!offset) {
95         return -1;
96     }
97
98     if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
99         return -1;
100     }
101
102     if (memcmp(BOOT_MAGIC, hdr.magic, BOOT_MAGIC_SIZE) != 0) {
103         printf("Invalid boot image: missing magic\n");
104         return -1;
105     }
106
107     if (!hdr.page_size) {
108         printf("Invalid boot image: page size must be non-zero\n");
109         return -1;
110     }
111
112     *offset = page_align(hdr.page_size
113                     + page_align(hdr.kernel_size,  hdr.page_size)
114                     + page_align(hdr.ramdisk_size, hdr.page_size)
115                     + page_align(hdr.second_size,  hdr.page_size),
116                 hdr.page_size);
117
118     return 0;
119 }
120
121 /**
122  * Reads and parses the ASN.1 BootSignature block from the given offset
123  * @param fd File descriptor to the boot image
124  * @param offset Offset from the beginning of file to the signature
125  * @param bs Pointer to receive the BootImage structure
126  */
127 static int read_signature(int fd, off64_t offset, BootSignature **bs)
128 {
129     BIO *in = NULL;
130
131     if (!bs) {
132         return -1;
133     }
134
135     if (lseek64(fd, offset, SEEK_SET) == -1) {
136         return -1;
137     }
138
139     if ((in = BIO_new_fd(fd, BIO_NOCLOSE)) == NULL) {
140         ERR_print_errors(g_error);
141         return -1;
142     }
143
144     if ((*bs = ASN1_item_d2i_bio(ASN1_ITEM_rptr(BootSignature), in, bs)) == NULL) {
145         ERR_print_errors(g_error);
146         BIO_free(in);
147         return -1;
148     }
149
150     BIO_free(in);
151     return 0;
152 }
153
154 /**
155  * Validates the format of the boot signature block, and checks that
156  * the length in authenticated attributes matches the actual length of
157  * the image.
158  * @param bs The boot signature block to validate
159  * @param length The actual length of the boot image without the signature
160  */
161 static int validate_signature_block(const BootSignature *bs, uint64_t length)
162 {
163     BIGNUM expected;
164     BIGNUM value;
165     int rc = -1;
166
167     if (!bs) {
168         return -1;
169     }
170
171     BN_init(&expected);
172     BN_init(&value);
173
174     /* Confirm that formatVersion matches our supported version */
175     if (!BN_set_word(&expected, FORMAT_VERSION)) {
176         ERR_print_errors(g_error);
177         goto vsb_done;
178     }
179
180     ASN1_INTEGER_to_BN(bs->formatVersion, &value);
181
182     if (BN_cmp(&expected, &value) != 0) {
183         printf("Unsupported signature version\n");
184         goto vsb_done;
185     }
186
187     BN_clear(&expected);
188     BN_clear(&value);
189
190     /* Confirm that the length of the image matches with the length in
191         the authenticated attributes */
192     length = htobe64(length);
193     BN_bin2bn((const unsigned char *) &length, sizeof(length), &expected);
194
195     ASN1_INTEGER_to_BN(bs->authenticatedAttributes->length, &value);
196
197     if (BN_cmp(&expected, &value) != 0) {
198         printf("Image length doesn't match signature attributes\n");
199         goto vsb_done;
200     }
201
202     rc = 0;
203
204 vsb_done:
205     BN_free(&expected);
206     BN_free(&value);
207
208     return rc;
209 }
210
211 /**
212  * Creates a SHA-256 hash from the boot image contents and the encoded
213  * authenticated attributes.
214  * @param fd File descriptor to the boot image
215  * @param length Length of the boot image without the signature block
216  * @param aa Pointer to AuthAttrs
217  * @param digest Pointer to a buffer where the hash is written
218  */
219 static int hash_image(int fd, uint64_t length, const AuthAttrs *aa,
220         unsigned char *digest)
221 {
222     EVP_MD_CTX *ctx = NULL;
223     int rc = -1;
224
225     ssize_t bytes = 0;
226     unsigned char *attrs = NULL;
227     unsigned char *buffer = NULL;
228     unsigned char *p = NULL;
229     uint64_t total = 0;
230
231     if (!aa || !digest) {
232         goto hi_done;
233     }
234
235     if ((buffer = malloc(BUFFER_SIZE)) == NULL) {
236         goto hi_done;
237     }
238
239     if (lseek64(fd, 0, SEEK_SET) != 0) {
240         goto hi_done;
241     }
242
243     if ((ctx = EVP_MD_CTX_create()) == NULL) {
244         ERR_print_errors(g_error);
245         goto hi_done;
246     }
247
248     EVP_DigestInit(ctx, EVP_sha256());
249
250     do {
251         bytes = BUFFER_SIZE;
252
253         if ((length - total) < BUFFER_SIZE) {
254             bytes = length - total;
255         }
256
257         if ((bytes = read(fd, buffer, bytes)) == -1) {
258             printf("%s\n", strerror(errno));
259             goto hi_done;
260         }
261
262         EVP_DigestUpdate(ctx, buffer, bytes);
263         total += bytes;
264     } while (total < length);
265
266     if ((bytes = i2d_AuthAttrs((AuthAttrs *) aa, NULL)) < 0) {
267         ERR_print_errors(g_error);
268         goto hi_done;
269     }
270
271     if ((attrs = OPENSSL_malloc(bytes)) == NULL) {
272         ERR_print_errors(g_error);
273         goto hi_done;
274     }
275
276     p = attrs;
277
278     if (i2d_AuthAttrs((AuthAttrs *) aa, &p) < 0) {
279         ERR_print_errors(g_error);
280         goto hi_done;
281     }
282
283     EVP_DigestUpdate(ctx, attrs, bytes);
284     EVP_DigestFinal(ctx, digest, NULL);
285
286     rc = 0;
287
288 hi_done:
289     if (buffer) {
290         free(buffer);
291     }
292
293     if (ctx) {
294         EVP_MD_CTX_destroy(ctx);
295     }
296
297     if (attrs) {
298         OPENSSL_free(attrs);
299     }
300
301     return rc;
302 }
303
304 /**
305  * Verifies the RSA signature
306  * @param fd File descriptor to the boot image
307  * @param length Length of the boot image without the signature block
308  * @param bs The boot signature block
309  */
310 static int verify_signature(int fd, uint64_t length, const BootSignature *bs)
311 {
312     int rc = -1;
313     EVP_PKEY *pkey = NULL;
314     RSA *rsa = NULL;
315     unsigned char digest[SHA256_DIGEST_LENGTH];
316
317     if (!bs) {
318         goto vs_done;
319     }
320
321     if (hash_image(fd, length, bs->authenticatedAttributes, digest) == -1) {
322         goto vs_done;
323     }
324
325     if ((pkey = X509_get_pubkey(bs->certificate)) == NULL) {
326         ERR_print_errors(g_error);
327         goto vs_done;
328     }
329
330     if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
331         ERR_print_errors(g_error);
332         goto vs_done;
333     }
334
335     if (!RSA_verify(NID_sha256, digest, SHA256_DIGEST_LENGTH,
336                 bs->signature->data, bs->signature->length, rsa)) {
337         ERR_print_errors(g_error);
338         goto vs_done;
339     }
340
341     rc = 0;
342
343 vs_done:
344     if (pkey) {
345         EVP_PKEY_free(pkey);
346     }
347
348     if (rsa) {
349         RSA_free(rsa);
350     }
351
352     return rc;
353 }
354
355 /**
356  * Given the file name of a signed boot image, verifies the signature
357  * @param image_file Name of the boot image file
358  */
359 static int verify(const char *image_file)
360 {
361     BootSignature *bs = NULL;
362     int fd = -1;
363     int rc = 1;
364     off64_t offset = 0;
365
366     if (!image_file) {
367         return rc;
368     }
369
370     if ((fd = open(image_file, O_RDONLY | O_LARGEFILE)) == -1) {
371         return rc;
372     }
373
374     if (get_signature_offset(fd, &offset) == -1) {
375         goto out;
376     }
377
378     if (read_signature(fd, offset, &bs) == -1) {
379         goto out;
380     }
381
382     if (validate_signature_block(bs, offset) == -1) {
383         goto out;
384     }
385
386     if (verify_signature(fd, offset, bs) == -1) {
387         goto out;
388     }
389
390     printf("Signature is VALID\n");
391     rc = 0;
392
393 out:
394     if (bs) {
395         BootSignature_free(bs);
396     }
397
398     if (fd != -1) {
399         close(fd);
400     }
401
402     return rc;
403 }
404
405 static void usage()
406 {
407     printf("Usage: verify_boot_signature <path-to-boot-image>\n");
408 }
409
410 int main(int argc, char *argv[])
411 {
412     if (argc != 2) {
413         usage();
414         return 1;
415     }
416
417     /* BIO descriptor for logging OpenSSL errors to stderr */
418     if ((g_error = BIO_new_fd(STDERR_FILENO, BIO_NOCLOSE)) == NULL) {
419         printf("Failed to allocate a BIO handle for error output\n");
420         return 1;
421     }
422
423     ERR_load_crypto_strings();
424
425     return verify(argv[1]);
426 }