/* Copyright (c) 2011 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 keys. */ /* TODO: change all 'return 0', 'return 1' into meaningful return codes */ #include #include #include #include #include "2sysincludes.h" #include "2common.h" #include "2rsa.h" #include "2sha.h" #include "host_common.h" #include "host_key.h" #include "host_key2.h" #include "host_misc.h" #include "vb2_common.h" #include "vboot_common.h" enum vb2_crypto_algorithm vb2_get_crypto_algorithm( enum vb2_hash_algorithm hash_alg, enum vb2_signature_algorithm sig_alg) { /* Make sure algorithms are in the range supported by crypto alg */ if (sig_alg < VB2_SIG_RSA1024 || sig_alg >= VB2_SIG_ALG_COUNT) return VB2_ALG_COUNT; if (hash_alg < VB2_HASH_SHA1 || hash_alg > VB2_HASH_SHA512) return VB2_ALG_COUNT; return (sig_alg - VB2_SIG_RSA1024) * (VB2_HASH_SHA512 - VB2_HASH_SHA1 + 1) + (hash_alg - VB2_HASH_SHA1); }; struct vb2_private_key *vb2_read_private_key(const char *filename) { uint8_t *buf = NULL; uint32_t bufsize = 0; if (VB2_SUCCESS != vb2_read_file(filename, &buf, &bufsize)) { VbExError("unable to read from file %s\n", filename); return NULL; } struct vb2_private_key *key = (struct vb2_private_key *)calloc(sizeof(*key), 1); if (!key) { VbExError("Unable to allocate private key\n"); free(buf); return NULL; } uint64_t alg = *(uint64_t *)buf; key->hash_alg = vb2_crypto_to_hash(alg); key->sig_alg = vb2_crypto_to_signature(alg); const unsigned char *start = buf + sizeof(alg); key->rsa_private_key = d2i_RSAPrivateKey(0, &start, bufsize - sizeof(alg)); if (!key->rsa_private_key) { VbExError("Unable to parse RSA private key\n"); free(buf); free(key); return NULL; } free(buf); return key; } struct vb2_private_key *vb2_read_private_key_pem( const char* filename, enum vb2_crypto_algorithm algorithm) { if (algorithm >= VB2_ALG_COUNT) { VB2_DEBUG("%s() called with invalid algorithm!\n", __FUNCTION__); return NULL; } /* Read private key */ FILE *f = fopen(filename, "r"); if (!f) { VB2_DEBUG("%s(): Couldn't open key file: %s\n", __FUNCTION__, filename); return NULL; } struct rsa_st *rsa_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL); fclose(f); if (!rsa_key) { VB2_DEBUG("%s(): Couldn't read private key from file: %s\n", __FUNCTION__, filename); return NULL; } /* Store key and algorithm in our struct */ struct vb2_private_key *key = (struct vb2_private_key *)calloc(sizeof(*key), 1); if (!key) { RSA_free(rsa_key); return NULL; } key->rsa_private_key = rsa_key; key->hash_alg = vb2_crypto_to_hash(algorithm); key->sig_alg = vb2_crypto_to_signature(algorithm); /* Return the key */ return key; } void vb2_free_private_key(struct vb2_private_key *key) { if (!key) return; if (key->rsa_private_key) RSA_free(key->rsa_private_key); free(key); } int vb2_write_private_key(const char *filename, const struct vb2_private_key *key) { /* Convert back to legacy vb1 algorithm enum */ uint64_t alg = vb2_get_crypto_algorithm(key->hash_alg, key->sig_alg); if (alg == VB2_ALG_COUNT) { fprintf(stderr, "Can't find crypto algorithm\n"); return VB2_ERROR_VB1_CRYPTO_ALGORITHM; } uint8_t *outbuf = NULL; int buflen = i2d_RSAPrivateKey(key->rsa_private_key, &outbuf); if (buflen <= 0) { fprintf(stderr, "Unable to write private key buffer\n"); return VB2_ERROR_PRIVATE_KEY_WRITE_RSA; } FILE *f = fopen(filename, "wb"); if (!f) { fprintf(stderr, "Unable to open file %s\n", filename); free(outbuf); return VB2_ERROR_PRIVATE_KEY_WRITE_FILE; } if (1 != fwrite(&alg, sizeof(alg), 1, f) || 1 != fwrite(outbuf, buflen, 1, f)) { fprintf(stderr, "Unable to write to file %s\n", filename); fclose(f); unlink(filename); /* Delete any partial file */ free(outbuf); return VB2_ERROR_PRIVATE_KEY_WRITE_FILE; } fclose(f); free(outbuf); return VB2_SUCCESS; } void vb2_init_packed_key(struct vb2_packed_key *key, uint8_t *key_data, uint32_t key_size) { memset(key, 0, sizeof(*key)); key->key_offset = vb2_offset_of(key, key_data); key->key_size = key_size; key->algorithm = VB2_ALG_COUNT; /* Key not present yet */ } struct vb2_packed_key *vb2_alloc_packed_key(uint32_t key_size, uint32_t algorithm, uint32_t version) { struct vb2_packed_key *key = (struct vb2_packed_key *)calloc(sizeof(*key) + key_size, 1); if (!key) return NULL; key->algorithm = algorithm; key->key_version = version; key->key_size = key_size; key->key_offset = sizeof(*key); return key; } int vb2_copy_packed_key(struct vb2_packed_key *dest, const struct vb2_packed_key *src) { if (dest->key_size < src->key_size) return VB2_ERROR_COPY_KEY_SIZE; dest->key_size = src->key_size; dest->algorithm = src->algorithm; dest->key_version = src->key_version; memcpy((uint8_t *)vb2_packed_key_data(dest), vb2_packed_key_data(src), src->key_size); return VB2_SUCCESS; } struct vb2_packed_key *vb2_read_packed_key(const char *filename) { struct vb2_packed_key *key = NULL; uint32_t file_size = 0; if (VB2_SUCCESS != vb2_read_file(filename, (uint8_t **)&key, &file_size)) { return NULL; } if (packed_key_looks_ok(key, file_size)) return key; /* Error */ free(key); return NULL; } struct vb2_packed_key *vb2_read_packed_keyb(const char *filename, uint32_t algorithm, uint32_t version) { if (algorithm >= VB2_ALG_COUNT) { fprintf(stderr, "%s() - invalid algorithm\n", __func__); return NULL; } if (version > VB2_MAX_KEY_VERSION) { /* Currently, TPM only supports 16-bit version */ fprintf(stderr, "%s() - invalid version 0x%x\n", __func__, version); return NULL; } uint8_t *key_data = NULL; uint32_t key_size = 0; if (VB2_SUCCESS != vb2_read_file(filename, &key_data, &key_size)) return NULL; uint32_t expected_key_size = vb2_packed_key_size(vb2_crypto_to_signature(algorithm)); if (!expected_key_size || expected_key_size != key_size) { fprintf(stderr, "%s() - wrong key size %u for algorithm %u\n", __func__, key_size, algorithm); free(key_data); return NULL; } struct vb2_packed_key *key = vb2_alloc_packed_key(key_size, algorithm, version); if (!key) { free(key_data); return NULL; } memcpy((uint8_t *)vb2_packed_key_data(key), key_data, key_size); free(key_data); return key; } int vb2_write_packed_key(const char *filename, const struct vb2_packed_key *key) { /* Copy the key, so its data is contiguous with the header */ struct vb2_packed_key *kcopy = vb2_alloc_packed_key(key->key_size, 0, 0); if (!kcopy) return VB2_ERROR_PACKED_KEY_ALLOC; if (VB2_SUCCESS != vb2_copy_packed_key(kcopy, key)) { free(kcopy); return VB2_ERROR_PACKED_KEY_COPY; } /* Write the copy, then free it */ int rv = vb2_write_file(filename, kcopy, kcopy->key_offset + kcopy->key_size); free(kcopy); return rv; }