mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
More reliable than simply assuming that VB2_SIG_RSA8192 is the last signature. BRANCH=none BUG=chromium:684354 TEST=rm tests/testkeys/key_*; make genkeys -j TEST=make runtests -j Change-Id: I755b3afb50313fcdf292fb3cd5b0dfe09f8593e3 Reviewed-on: https://chromium-review.googlesource.com/438948 Commit-Ready: Nicolas Boichat <drinkcat@chromium.org> Tested-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org>
282 lines
6.9 KiB
C
282 lines
6.9 KiB
C
/* 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 <openssl/pem.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#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;
|
|
}
|