summaryrefslogtreecommitdiff
path: root/host/lib/host_signature2.c
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/host_signature2.c')
-rw-r--r--host/lib/host_signature2.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/host/lib/host_signature2.c b/host/lib/host_signature2.c
new file mode 100644
index 00000000..c5b2c466
--- /dev/null
+++ b/host/lib/host_signature2.c
@@ -0,0 +1,273 @@
+/* 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 signatures.
+ */
+
+#define OPENSSL_NO_SHA
+#include <openssl/engine.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2rsa.h"
+#include "2sha.h"
+#include "host_common.h"
+#include "host_key2.h"
+#include "host_signature2.h"
+#include "host_misc.h"
+
+/**
+ * Get the digest info for a hash algorithm
+ *
+ * @param hash_alg Hash algorithm
+ * @param buf_ptr On success, points to the digest info
+ * @param size_ptr On success, contains the info size in bytes
+ * @return VB2_SUCCESS, or non-zero error code on failure.
+ */
+static int vb2_digest_info(enum vb2_hash_algorithm hash_alg,
+ const uint8_t **buf_ptr,
+ uint32_t *size_ptr)
+{
+ *buf_ptr = NULL;
+ *size_ptr = 0;
+
+ switch (hash_alg) {
+#if VB2_SUPPORT_SHA1
+ case VB2_HASH_SHA1:
+ {
+ static const uint8_t info[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
+ 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
+ };
+ *buf_ptr = info;
+ *size_ptr = sizeof(info);
+ return VB2_SUCCESS;
+ }
+#endif
+#if VB2_SUPPORT_SHA256
+ case VB2_HASH_SHA256:
+ {
+ static const uint8_t info[] = {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20
+ };
+ *buf_ptr = info;
+ *size_ptr = sizeof(info);
+ return VB2_SUCCESS;
+ }
+#endif
+#if VB2_SUPPORT_SHA512
+ case VB2_HASH_SHA512:
+ {
+ static const uint8_t info[] = {
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40
+ };
+ *buf_ptr = info;
+ *size_ptr = sizeof(info);
+ return VB2_SUCCESS;
+ }
+#endif
+ default:
+ return VB2_ERROR_DIGEST_INFO;
+ }
+}
+
+int vb2_sign_data(struct vb2_signature2 **sig_ptr,
+ const uint8_t *data,
+ uint32_t size,
+ const struct vb2_private_key *key,
+ const char *desc)
+{
+ struct vb2_signature2 s = {
+ .c.magic = VB2_MAGIC_SIGNATURE2,
+ .c.struct_version_major = VB2_SIGNATURE2_VERSION_MAJOR,
+ .c.struct_version_minor = VB2_SIGNATURE2_VERSION_MINOR,
+ .c.fixed_size = sizeof(s),
+ .sig_alg = key->sig_alg,
+ .hash_alg = key->hash_alg,
+ .data_size = size,
+ .guid = key->guid,
+ };
+
+ struct vb2_digest_context dc;
+ uint32_t digest_size;
+ const uint8_t *info = NULL;
+ uint32_t info_size = 0;
+ uint32_t sig_digest_size;
+ uint8_t *sig_digest;
+ uint8_t *buf;
+
+ *sig_ptr = NULL;
+
+ /* Use key description if no description supplied */
+ if (!desc)
+ desc = key->desc;
+
+ s.c.desc_size = vb2_desc_size(desc);
+
+ s.sig_offset = s.c.fixed_size + s.c.desc_size;
+ s.sig_size = vb2_sig_size(key->sig_alg, key->hash_alg);
+ if (!s.sig_size)
+ return VB2_SIGN_DATA_SIG_SIZE;
+
+ s.c.total_size = s.sig_offset + s.sig_size;
+
+ /* Determine digest size and allocate buffer */
+ if (s.sig_alg != VB2_SIG_NONE) {
+ if (vb2_digest_info(s.hash_alg, &info, &info_size))
+ return VB2_SIGN_DATA_DIGEST_INFO;
+ }
+
+ digest_size = vb2_digest_size(key->hash_alg);
+ if (!digest_size)
+ return VB2_SIGN_DATA_DIGEST_SIZE;
+
+ sig_digest_size = info_size + digest_size;
+ sig_digest = malloc(sig_digest_size);
+ if (!sig_digest)
+ return VB2_SIGN_DATA_DIGEST_ALLOC;
+
+ /* Prepend digest info, if any */
+ if (info_size)
+ memcpy(sig_digest, info, info_size);
+
+ /* Calculate hash digest */
+ if (vb2_digest_init(&dc, s.hash_alg)) {
+ free(sig_digest);
+ return VB2_SIGN_DATA_DIGEST_INIT;
+ }
+
+ if (vb2_digest_extend(&dc, data, size)) {
+ free(sig_digest);
+ return VB2_SIGN_DATA_DIGEST_EXTEND;
+ }
+
+ if (vb2_digest_finalize(&dc, sig_digest + info_size, digest_size)) {
+ free(sig_digest);
+ return VB2_SIGN_DATA_DIGEST_FINALIZE;
+ }
+
+ /* Allocate signature buffer and copy header */
+ buf = malloc(s.c.total_size);
+ memset(buf, 0, s.c.total_size);
+ memcpy(buf, &s, sizeof(s));
+
+ /* strcpy() is ok because we allocated buffer based on desc length */
+ if (desc)
+ strcpy((char *)buf + s.c.fixed_size, desc);
+
+ if (s.sig_alg == VB2_SIG_NONE) {
+ /* Bare hash signature is just the digest */
+ memcpy(buf + s.sig_offset, sig_digest, sig_digest_size);
+ } else {
+ /* RSA-encrypt the signature */
+ if (RSA_private_encrypt(sig_digest_size,
+ sig_digest,
+ buf + s.sig_offset,
+ key->rsa_private_key,
+ RSA_PKCS1_PADDING) == -1) {
+ free(sig_digest);
+ free(buf);
+ return VB2_SIGN_DATA_RSA_ENCRYPT;
+ }
+ }
+
+ free(sig_digest);
+ *sig_ptr = (struct vb2_signature2 *)buf;
+ return VB2_SUCCESS;
+}
+
+int vb2_sig_size_for_key(uint32_t *size_ptr,
+ const struct vb2_private_key *key,
+ const char *desc)
+{
+ uint32_t size = vb2_sig_size(key->sig_alg, key->hash_alg);
+
+ if (!size)
+ return VB2_ERROR_SIG_SIZE_FOR_KEY;
+
+ size += sizeof(struct vb2_signature2);
+ size += vb2_desc_size(desc ? desc : key->desc);
+
+ *size_ptr = size;
+ return VB2_SUCCESS;
+}
+
+int vb2_sig_size_for_keys(uint32_t *size_ptr,
+ const struct vb2_private_key **key_list,
+ uint32_t key_count)
+{
+ uint32_t total = 0, size = 0;
+ int rv, i;
+
+ *size_ptr = 0;
+
+ for (i = 0; i < key_count; i++) {
+ rv = vb2_sig_size_for_key(&size, key_list[i], NULL);
+ if (rv)
+ return rv;
+ total += size;
+ }
+
+ *size_ptr = total;
+ return VB2_SUCCESS;
+}
+
+int vb2_sign_object(uint8_t *buf,
+ uint32_t sig_offset,
+ const struct vb2_private_key *key,
+ const char *desc)
+{
+ struct vb2_struct_common *c = (struct vb2_struct_common *)buf;
+ struct vb2_signature2 *sig = NULL;
+ int rv;
+
+ rv = vb2_sign_data(&sig, buf, sig_offset, key, desc);
+ if (rv)
+ return rv;
+
+ if (sig_offset + sig->c.total_size > c->total_size) {
+ free(sig);
+ return VB2_SIGN_OBJECT_OVERFLOW;
+ }
+
+ memcpy(buf + sig_offset, sig, sig->c.total_size);
+ free(sig);
+
+ return VB2_SUCCESS;
+}
+
+int vb2_sign_object_multiple(uint8_t *buf,
+ uint32_t sig_offset,
+ const struct vb2_private_key **key_list,
+ uint32_t key_count)
+{
+ struct vb2_struct_common *c = (struct vb2_struct_common *)buf;
+ uint32_t sig_next = sig_offset;
+ int rv, i;
+
+ for (i = 0; i < key_count; i++) {
+ struct vb2_signature2 *sig = NULL;
+
+ rv = vb2_sign_data(&sig, buf, sig_offset, key_list[i], NULL);
+ if (rv)
+ return rv;
+
+ if (sig_next + sig->c.total_size > c->total_size) {
+ free(sig);
+ return VB2_SIGN_OBJECT_OVERFLOW;
+ }
+
+ memcpy(buf + sig_next, sig, sig->c.total_size);
+ sig_next += sig->c.total_size;
+ free(sig);
+ }
+
+ return VB2_SUCCESS;
+}