Home | History | Annotate | Download | only in verity
      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 }
    427