OSDN Git Service

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