summaryrefslogtreecommitdiff
path: root/host/lib/host_key2.c
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/host_key2.c')
-rw-r--r--host/lib/host_key2.c419
1 files changed, 419 insertions, 0 deletions
diff --git a/host/lib/host_key2.c b/host/lib/host_key2.c
new file mode 100644
index 00000000..eb252ef1
--- /dev/null
+++ b/host/lib/host_key2.c
@@ -0,0 +1,419 @@
+/* Copyright (c) 2014 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.
+ */
+
+#define OPENSSL_NO_SHA
+#include <openssl/engine.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2rsa.h"
+#include "host_common.h"
+#include "host_key2.h"
+#include "host_misc.h"
+
+void vb2_private_key_free(struct vb2_private_key *key)
+{
+ if (!key)
+ return;
+
+ if (key->rsa_private_key)
+ RSA_free(key->rsa_private_key);
+
+ if (key->desc)
+ free(key->desc);
+
+ free(key);
+}
+
+int vb2_private_key_unpack(struct vb2_private_key **key_ptr,
+ const uint8_t *buf,
+ uint32_t size)
+{
+ const struct vb2_packed_private_key2 *pkey =
+ (const struct vb2_packed_private_key2 *)buf;
+ struct vb2_private_key *key;
+ const unsigned char *start;
+ uint32_t min_offset = 0;
+
+ *key_ptr = NULL;
+
+ /*
+ * Check magic number.
+ *
+ * TODO: If it doesn't match, pass through to the old packed key format.
+ */
+ if (pkey->c.magic != VB2_MAGIC_PACKED_PRIVATE_KEY2)
+ return VB2_ERROR_UNPACK_PRIVATE_KEY_MAGIC;
+
+ if (vb2_verify_common_header(buf, size))
+ return VB2_ERROR_UNPACK_PRIVATE_KEY_HEADER;
+
+ /* Make sure key data is inside */
+ if (vb2_verify_common_member(pkey, &min_offset,
+ pkey->key_offset, pkey->key_size))
+ return VB2_ERROR_UNPACK_PRIVATE_KEY_DATA;
+
+ /*
+ * Check for compatible version. No need to check minor version, since
+ * that's compatible across readers matching the major version, and we
+ * haven't added any new fields.
+ */
+ if (pkey->c.struct_version_major !=
+ VB2_PACKED_PRIVATE_KEY2_VERSION_MAJOR)
+ return VB2_ERROR_UNPACK_PRIVATE_KEY_STRUCT_VERSION;
+
+ /* Allocate the new key */
+ key = malloc(sizeof(*key));
+ if (!key)
+ return VB2_ERROR_UNPACK_PRIVATE_KEY_ALLOC;
+
+ memset(key, 0, sizeof(*key));
+
+ /* Copy key algorithms and guid */
+ key->sig_alg = pkey->sig_alg;
+ key->hash_alg = pkey->hash_alg;
+ key->guid = pkey->guid;
+
+ /* Unpack RSA key */
+ start = (const unsigned char *)(buf + pkey->key_offset);
+ key->rsa_private_key = d2i_RSAPrivateKey(0, &start, pkey->key_size);
+ if (!key->rsa_private_key) {
+ free(key);
+ return VB2_ERROR_UNPACK_PRIVATE_KEY_RSA;
+ }
+
+ /* Key description */
+ if (pkey->c.desc_size) {
+ if (vb2_private_key_set_desc(
+ key, (const char *)(buf + pkey->c.fixed_size))) {
+ vb2_private_key_free(key);
+ return VB2_ERROR_UNPACK_PRIVATE_KEY_DESC;
+ }
+ }
+
+ *key_ptr = key;
+ return VB2_SUCCESS;
+}
+
+int vb2_private_key_read(struct vb2_private_key **key_ptr,
+ const char *filename)
+{
+ uint32_t size = 0;
+ uint8_t *buf;
+ int rv;
+
+ *key_ptr = NULL;
+
+ rv = vb2_read_file(filename, &buf, &size);
+ if (rv)
+ return rv;
+
+ rv = vb2_private_key_unpack(key_ptr, buf, size);
+
+ free(buf);
+
+ return rv;
+}
+
+int vb2_private_key_read_pem(struct vb2_private_key **key_ptr,
+ const char *filename)
+{
+ struct vb2_private_key *key;
+ FILE *f;
+
+ *key_ptr = NULL;
+
+ /* Allocate the new key */
+ key = malloc(sizeof(*key));
+ if (!key)
+ return VB2_ERROR_READ_PEM_ALLOC;
+
+ memset(key, 0, sizeof(*key));
+
+ /* Read private key */
+ f = fopen(filename, "r");
+ if (!f) {
+ free(key);
+ return VB2_ERROR_READ_PEM_FILE_OPEN;
+ }
+
+ key->rsa_private_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
+ if (!key->rsa_private_key) {
+ free(key);
+ return VB2_ERROR_READ_PEM_RSA;
+ }
+
+ *key_ptr = key;
+ return VB2_SUCCESS;
+}
+
+int vb2_private_key_set_desc(struct vb2_private_key *key, const char *desc)
+{
+ if (key->desc)
+ free(key->desc);
+
+ if (desc) {
+ key->desc = strdup(desc);
+ if (!key->desc)
+ return VB2_ERROR_PRIVATE_KEY_SET_DESC;
+ } else {
+ key->desc = NULL;
+ }
+
+ return VB2_SUCCESS;
+}
+
+int vb2_private_key_write(const struct vb2_private_key *key,
+ const char *filename)
+{
+ struct vb2_packed_private_key2 pkey = {
+ .c.magic = VB2_MAGIC_PACKED_PRIVATE_KEY2,
+ .c.struct_version_major = VB2_PACKED_PRIVATE_KEY2_VERSION_MAJOR,
+ .c.struct_version_minor = VB2_PACKED_PRIVATE_KEY2_VERSION_MINOR,
+ .c.fixed_size = sizeof(pkey),
+ .sig_alg = key->sig_alg,
+ .hash_alg = key->hash_alg,
+ .guid = key->guid,
+ };
+ uint8_t *buf;
+ uint8_t *rsabuf = NULL;
+ int rsalen;
+ int rv;
+
+ memcpy(&pkey.guid, &key->guid, sizeof(pkey.guid));
+
+ if (key->desc)
+ pkey.c.desc_size = roundup32(strlen(key->desc) + 1);
+
+ /* Pack RSA key */
+ rsalen = i2d_RSAPrivateKey(key->rsa_private_key, &rsabuf);
+ if (rsalen <= 0)
+ return VB2_ERROR_PRIVATE_KEY_WRITE_RSA;
+
+ pkey.key_offset = pkey.c.fixed_size + pkey.c.desc_size;
+ pkey.key_size = roundup32(rsalen);
+ pkey.c.total_size = pkey.key_offset + pkey.key_size;
+
+ /* Pack private key */
+ buf = malloc(pkey.c.total_size);
+ if (!buf) {
+ free(rsabuf);
+ return VB2_ERROR_PRIVATE_KEY_WRITE_ALLOC;
+ }
+
+ memset(buf, 0, pkey.c.total_size);
+ memcpy(buf, &pkey, sizeof(pkey));
+
+ /* strcpy() is ok here because we checked the length above */
+ if (key->desc)
+ strcpy((char *)buf + pkey.c.fixed_size, key->desc);
+
+ memcpy(buf + pkey.key_offset, rsabuf, rsalen);
+ free(rsabuf);
+
+ rv = vb2_write_object(filename, buf);
+ free(buf);
+
+ return rv ? VB2_ERROR_PRIVATE_KEY_WRITE_FILE : VB2_SUCCESS;
+}
+
+/**
+ * Allocate a public key buffer of sufficient size for the signature algorithm.
+ *
+ * This only initializes the sig_alg field and the guid field to an empty
+ * guid. It does not set any of the other fields in *key_ptr.
+ *
+ * @param key_ptr Destination for newly allocated key; this must be
+ * freed with vb2_public_key_free().
+ * @param sig_alg Signature algorithm for key.
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+static int vb2_public_key_alloc(struct vb2_public_key **key_ptr,
+ enum vb2_signature_algorithm sig_alg)
+{
+ struct vb2_public_key *key;
+ uint32_t key_data_size = vb2_packed_key_size(sig_alg);
+
+ /* The buffer contains the key, its GUID, and its packed data */
+ uint32_t buf_size = sizeof(*key) + sizeof(struct vb2_guid) +
+ key_data_size;
+
+ if (!key_data_size)
+ return VB2_ERROR_PUBLIC_KEY_ALLOC_SIZE;
+
+ key = malloc(buf_size);
+ if (!key)
+ return VB2_ERROR_PUBLIC_KEY_ALLOC;
+
+ memset(key, 0, buf_size);
+ key->guid = (struct vb2_guid *)(key + 1);
+ key->sig_alg = sig_alg;
+
+ *key_ptr = key;
+
+ return VB2_SUCCESS;
+}
+
+void vb2_public_key_free(struct vb2_public_key *key)
+{
+ if (key->desc)
+ free((void *)key->desc);
+
+ free(key);
+}
+
+/**
+ * Return the packed data for a key allocated with vb2_public_key_alloc().
+ *
+ * The packed data is in the same buffer, following the key struct and GUID.
+ */
+static uint8_t *vb2_public_key_packed_data(struct vb2_public_key *key)
+{
+ return (uint8_t *)(key->guid + 1);
+}
+
+int vb2_public_key_read_keyb(struct vb2_public_key **key_ptr,
+ const char *filename)
+{
+ struct vb2_public_key *key = NULL;
+ uint8_t *key_data, *key_buf;
+ uint32_t key_size;
+ enum vb2_signature_algorithm sig_alg;
+
+ *key_ptr = NULL;
+
+ if (vb2_read_file(filename, &key_data, &key_size))
+ return VB2_ERROR_READ_KEYB_DATA;
+
+ /* Guess the signature algorithm from the key size */
+ for (sig_alg = VB2_SIG_RSA1024; sig_alg <= VB2_SIG_RSA8192; sig_alg++) {
+ if (key_size == vb2_packed_key_size(sig_alg))
+ break;
+ }
+ if (sig_alg > VB2_SIG_RSA8192) {
+ free(key_data);
+ return VB2_ERROR_READ_KEYB_SIZE;
+ }
+
+ if (vb2_public_key_alloc(&key, sig_alg)) {
+ free(key_data);
+ return VB2_ERROR_READ_KEYB_ALLOC;
+ }
+
+ /* Copy data from the file buffer to the public key buffer */
+ key_buf = vb2_public_key_packed_data(key);
+ memcpy(key_buf, key_data, key_size);
+ free(key_data);
+
+ if (vb2_unpack_key2_data(key, key_buf, key_size)) {
+ vb2_public_key_free(key);
+ return VB2_ERROR_READ_KEYB_UNPACK;
+ }
+
+ *key_ptr = key;
+
+ return VB2_SUCCESS;
+}
+
+int vb2_public_key_set_desc(struct vb2_public_key *key, const char *desc)
+{
+ if (key->desc)
+ free((void *)key->desc);
+
+ if (desc) {
+ key->desc = strdup(desc);
+ if (!key->desc)
+ return VB2_ERROR_PUBLIC_KEY_SET_DESC;
+ } else {
+ key->desc = NULL;
+ }
+
+ return VB2_SUCCESS;
+}
+
+int vb2_packed_key2_read(struct vb2_packed_key2 **key_ptr,
+ const char *filename)
+{
+ struct vb2_public_key key;
+ uint8_t *buf;
+ uint32_t size;
+
+ *key_ptr = NULL;
+
+ if (!vb2_read_file(filename, &buf, &size))
+ return VB2_ERROR_READ_PACKED_KEY_DATA;
+
+ /* Sanity check: make sure key unpacks properly */
+ if (!vb2_unpack_key(&key, buf, size))
+ return VB2_ERROR_READ_PACKED_KEY;
+
+ *key_ptr = (struct vb2_packed_key2 *)buf;
+
+ return VB2_SUCCESS;
+}
+
+int vb2_public_key_pack(struct vb2_packed_key2 **key_ptr,
+ const struct vb2_public_key *pubk)
+{
+ struct vb2_packed_key2 key = {
+ .c.magic = VB2_MAGIC_PACKED_KEY2,
+ .c.struct_version_major = VB2_PACKED_KEY2_VERSION_MAJOR,
+ .c.struct_version_minor = VB2_PACKED_KEY2_VERSION_MINOR,
+ };
+ uint8_t *buf;
+ uint32_t *buf32;
+
+ *key_ptr = NULL;
+
+ /* Calculate sizes and offsets */
+ key.c.fixed_size = sizeof(key);
+
+ if (pubk->desc)
+ key.c.desc_size = roundup32(strlen(pubk->desc) + 1);
+
+ key.key_offset = key.c.fixed_size + key.c.desc_size;
+
+ key.key_size = vb2_packed_key_size(pubk->sig_alg);
+ if (!key.key_size)
+ return VB2_ERROR_PUBLIC_KEY_PACK_SIZE;
+
+ key.c.total_size = key.key_offset + key.key_size;
+
+ /* Copy/initialize fields */
+ key.key_version = pubk->version;
+ key.sig_alg = pubk->sig_alg;
+ key.hash_alg = pubk->hash_alg;
+ key.guid = *pubk->guid;
+
+ /* Allocate the new buffer */
+ buf = malloc(key.c.total_size);
+ memset(buf, 0, key.c.total_size);
+
+ /* Copy data into the buffer */
+ memcpy(buf, &key, sizeof(key));
+
+ /* strcpy() is safe because we allocated above based on strlen() */
+ if (pubk->desc) {
+ strcpy((char *)(buf + key.c.fixed_size), pubk->desc);
+ buf[key.c.fixed_size + key.c.desc_size - 1] = 0;
+ }
+
+ /* Re-pack the key arrays */
+ buf32 = (uint32_t *)(buf + key.key_offset);
+ buf32[0] = pubk->arrsize;
+ buf32[1] = pubk->n0inv;
+ memcpy(buf32 + 2, pubk->n, pubk->arrsize * sizeof(uint32_t));
+ memcpy(buf32 + 2 + pubk->arrsize, pubk->rr,
+ pubk->arrsize * sizeof(uint32_t));
+
+ *key_ptr = (struct vb2_packed_key2 *)buf;
+
+ return VB2_SUCCESS;
+}