123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- /* Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Host functions for signing
- */
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include "bdb.h"
- #include "host.h"
- char *strzcpy(char *dest, const char *src, size_t size)
- {
- strncpy(dest, src, size);
- dest[size - 1] = 0;
- return dest;
- }
- uint8_t *read_file(const char *filename, uint32_t *size_ptr)
- {
- FILE *f;
- uint8_t *buf;
- long size;
- *size_ptr = 0;
- f = fopen(filename, "rb");
- if (!f) {
- fprintf(stderr, "Unable to open file %s\n", filename);
- return NULL;
- }
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- rewind(f);
- if (size < 0 || size > UINT32_MAX) {
- fclose(f);
- return NULL;
- }
- buf = malloc(size);
- if (!buf) {
- fclose(f);
- return NULL;
- }
- if (1 != fread(buf, size, 1, f)) {
- fprintf(stderr, "Unable to read file %s\n", filename);
- fclose(f);
- free(buf);
- return NULL;
- }
- fclose(f);
- *size_ptr = size;
- return buf;
- }
- int write_file(const char *filename, const void *buf, uint32_t size)
- {
- FILE *f = fopen(filename, "wb");
- if (!f) {
- fprintf(stderr, "Unable to open file %s\n", filename);
- return 1;
- }
- if (1 != fwrite(buf, size, 1, f)) {
- fprintf(stderr, "Unable to write to file %s\n", filename);
- fclose(f);
- unlink(filename); /* Delete any partial file */
- return 1;
- }
- fclose(f);
- return 0;
- }
- struct rsa_st *read_pem(const char *filename)
- {
- struct rsa_st *pem;
- FILE *f;
- /* Read private key */
- f = fopen(filename, "rb");
- if (!f) {
- fprintf(stderr, "%s: unable to read key from %s\n",
- __func__, filename);
- return NULL;
- }
- pem = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
- fclose(f);
- return pem;
- }
- struct bdb_key *bdb_create_key(const char *filename,
- uint32_t key_version,
- const char *desc)
- {
- uint32_t sig_alg;
- size_t key_size = sizeof(struct bdb_key);
- struct bdb_key *k;
- uint8_t *kdata;
- uint32_t kdata_size = 0;
- /*
- * Read key data. Somewhat lame assumption that we can determine the
- * signature algorithm from the key size, but it's true right now.
- */
- kdata = read_file(filename, &kdata_size);
- if (kdata_size == BDB_RSA4096_KEY_DATA_SIZE) {
- sig_alg = BDB_SIG_ALG_RSA4096;
- } else if (kdata_size == BDB_RSA3072B_KEY_DATA_SIZE) {
- sig_alg = BDB_SIG_ALG_RSA3072B;
- } else {
- fprintf(stderr, "%s: bad key size from %s\n",
- __func__, filename);
- return NULL;
- }
- key_size += kdata_size;
- /* Allocate buffer */
- k = (struct bdb_key *)calloc(key_size, 1);
- if (!k) {
- free(kdata);
- return NULL;
- }
- k->struct_magic = BDB_KEY_MAGIC;
- k->struct_major_version = BDB_KEY_VERSION_MAJOR;
- k->struct_minor_version = BDB_KEY_VERSION_MINOR;
- k->struct_size = key_size;
- k->hash_alg = BDB_HASH_ALG_SHA256;
- k->sig_alg = sig_alg;
- k->key_version = key_version;
- /* Copy description, if any */
- if (desc)
- strzcpy(k->description, desc, sizeof(k->description));
- /* Copy key data */
- memcpy(k->key_data, kdata, kdata_size);
- free(kdata);
- return k;
- }
- struct bdb_sig *bdb_create_sig(const void *data,
- size_t size,
- struct rsa_st *key,
- uint32_t sig_alg,
- const char *desc)
- {
- static const uint8_t info[] = {
- 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
- 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
- 0x00, 0x04, 0x20
- };
- size_t sig_size = sizeof(struct bdb_sig);
- uint8_t digest[sizeof(info) + BDB_SHA256_DIGEST_SIZE];
- struct bdb_sig *sig;
- if (size >= UINT32_MAX)
- return NULL;
- switch(sig_alg) {
- case BDB_SIG_ALG_RSA4096:
- sig_size += BDB_RSA4096_SIG_SIZE;
- break;
- case BDB_SIG_ALG_RSA3072B:
- sig_size += BDB_RSA3072B_SIG_SIZE;
- break;
- default:
- fprintf(stderr, "%s: bad signature algorithm %d\n",
- __func__, sig_alg);
- return NULL;
- }
- /* Allocate buffer */
- sig = (struct bdb_sig *)calloc(sig_size, 1);
- if (!sig)
- return NULL;
- sig->struct_magic = BDB_SIG_MAGIC;
- sig->struct_major_version = BDB_SIG_VERSION_MAJOR;
- sig->struct_minor_version = BDB_SIG_VERSION_MINOR;
- sig->struct_size = sig_size;
- sig->hash_alg = BDB_HASH_ALG_SHA256;
- sig->sig_alg = sig_alg;
- sig->signed_size = size;
- /* Copy description, if any */
- if (desc)
- strzcpy(sig->description, desc, sizeof(sig->description));
- /* Calculate info-padded digest */
- memcpy(digest, info, sizeof(info));
- if (bdb_sha256(digest + sizeof(info), data, size)) {
- free(sig);
- return NULL;
- }
- /* RSA-encrypt the signature */
- if (RSA_private_encrypt(sizeof(digest),
- digest,
- sig->sig_data,
- key,
- RSA_PKCS1_PADDING) == -1) {
- free(sig);
- return NULL;
- }
- return sig;
- }
- struct bdb_header *bdb_create(struct bdb_create_params *p)
- {
- size_t bdb_size = 0;
- size_t sig_size = sizeof(struct bdb_sig) + BDB_RSA4096_SIG_SIZE;
- size_t hashes_size = sizeof(struct bdb_hash) * p->num_hashes;
- uint8_t *buf, *bnext;
- struct bdb_header *h;
- struct bdb_sig *sig;
- struct bdb_data *data;
- const void *oem;
- /* We can do some checks before we even allocate the buffer */
- /* Make sure OEM sizes are aligned */
- if ((p->oem_area_0_size & 3) || (p->oem_area_1_size & 3)) {
- fprintf(stderr, "%s: OEM areas not 32-bit aligned\n",
- __func__);
- return NULL;
- }
- /* Hash count must fit in uint8_t */
- if (p->num_hashes > 255) {
- fprintf(stderr, "%s: too many hashes\n", __func__);
- return NULL;
- }
- /* Calculate BDB size */
- bdb_size = sizeof(struct bdb_header);
- bdb_size += p->bdbkey->struct_size;
- bdb_size += p->oem_area_0_size;
- bdb_size += p->subkey->struct_size;
- bdb_size += sig_size;
- bdb_size += sizeof(struct bdb_data);
- bdb_size += p->oem_area_1_size;
- bdb_size += sizeof(struct bdb_hash) * p->num_hashes;
- bdb_size += sig_size;
- /* Make sure it fits */
- if (bdb_size > UINT32_MAX) {
- fprintf(stderr, "%s: BDB size > UINT32_MAX\n", __func__);
- return NULL;
- }
- /* Allocate a buffer */
- bnext = buf = calloc(bdb_size, 1);
- if (!buf) {
- fprintf(stderr, "%s: can't allocate buffer\n", __func__);
- return NULL;
- }
- /* Fill in the header */
- h = (struct bdb_header *)bnext;
- h->struct_magic = BDB_HEADER_MAGIC;
- h->struct_major_version = BDB_HEADER_VERSION_MAJOR;
- h->struct_minor_version = BDB_HEADER_VERSION_MINOR;
- h->struct_size = sizeof(*h);
- h->bdb_load_address = p->bdb_load_address;
- h->bdb_size = bdb_size;
- h->signed_size = p->oem_area_0_size + p->subkey->struct_size;
- h->oem_area_0_size = p->oem_area_0_size;
- bnext += h->struct_size;
- /* Copy BDB key */
- memcpy(bnext, p->bdbkey, p->bdbkey->struct_size);
- bnext += p->bdbkey->struct_size;
- /* Copy OEM area 0 */
- oem = bnext;
- if (p->oem_area_0_size) {
- memcpy(bnext, p->oem_area_0, p->oem_area_0_size);
- bnext += p->oem_area_0_size;
- }
- /* Copy subkey */
- memcpy(bnext, p->subkey, p->subkey->struct_size);
- bnext += p->subkey->struct_size;
- /*
- * Create header signature using private BDB key.
- *
- * TODO: create the header signature in a totally separate step. That
- * way, the private BDB key is not required each time a BDB is created.
- */
- sig = bdb_create_sig(oem, h->signed_size, p->private_bdbkey,
- p->bdbkey->sig_alg, p->header_sig_description);
- memcpy(bnext, sig, sig->struct_size);
- bnext += sig->struct_size;
- /* Fill in the data */
- data = (struct bdb_data *)bnext;
- data->struct_magic = BDB_DATA_MAGIC;
- data->struct_major_version = BDB_DATA_VERSION_MAJOR;
- data->struct_minor_version = BDB_DATA_VERSION_MINOR;
- data->struct_size = sizeof(struct bdb_data);
- data->data_version = p->data_version;
- data->oem_area_1_size = p->oem_area_1_size;
- data->num_hashes = p->num_hashes;
- data->hash_entry_size = sizeof(struct bdb_hash);
- data->signed_size = data->struct_size + data->oem_area_1_size +
- hashes_size;
- if (p->data_description) {
- strzcpy(data->description, p->data_description,
- sizeof(data->description));
- }
- bnext += data->struct_size;
- /* Copy OEM area 1 */
- oem = bnext;
- if (p->oem_area_1_size) {
- memcpy(bnext, p->oem_area_1, p->oem_area_1_size);
- bnext += p->oem_area_1_size;
- }
- /* Copy hashes */
- memcpy(bnext, p->hash, hashes_size);
- bnext += hashes_size;
- /* Create data signature using private subkey */
- sig = bdb_create_sig(data, data->signed_size, p->private_subkey,
- p->subkey->sig_alg, p->data_sig_description);
- memcpy(bnext, sig, sig->struct_size);
- /* Return the BDB */
- return h;
- }
|