summaryrefslogtreecommitdiff
path: root/host
diff options
context:
space:
mode:
authorJakub Czapiga <jacz@semihalf.com>2022-08-04 17:13:06 +0200
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-10-12 17:41:55 +0000
commit0ca7a9e4dad2e9780690524ced9273fa07052179 (patch)
tree9078489dc0f6e8e79aaf3ff80f2358b5dbc7e814 /host
parentaaeb307f882d0c2e1284636e8423af1d216f6362 (diff)
downloadvboot-0ca7a9e4dad2e9780690524ced9273fa07052179.tar.gz
firmware: host: futility: Add CBFS metadata hash supportstabilize-15183.14.B
This patch adds support for signing and verification of coreboot images supporting VBOOT_CBFS_INTEGRATION. Images with config option CONFIG_VBOOT_CBFS_INTEGRATION=y will be signed with CBFS metadata hash in signature. vb2api_get_metadata_hash() should be used to extract hash value from VBLOCK and then should be used to verify CBFS metadata. To support full verification, CBFS file data verification should also be enabled and correctly handled. BUG=b:197114807 TEST=build with CB:66909 and boot on volteer/voxel with CONFIG_VBOOT_CBFS_INTEGRATION=y BRANCH=none Signed-off-by: Jakub Czapiga <czapiga@google.com> Change-Id: I4075c84820949be24c423ed14e291c89a0032863 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/3811754 Commit-Queue: Julius Werner <jwerner@chromium.org> Reviewed-by: Julius Werner <jwerner@chromium.org> Reviewed-by: Yu-Ping Wu <yupingso@chromium.org>
Diffstat (limited to 'host')
-rw-r--r--host/lib/cbfstool.c168
-rw-r--r--host/lib/host_misc.c50
-rw-r--r--host/lib/host_signature2.c25
-rw-r--r--host/lib/include/cbfstool.h25
-rw-r--r--host/lib/include/host_misc.h23
-rw-r--r--host/lib/include/host_signature.h11
6 files changed, 301 insertions, 1 deletions
diff --git a/host/lib/cbfstool.c b/host/lib/cbfstool.c
index 4bbed028..0f6ed16f 100644
--- a/host/lib/cbfstool.c
+++ b/host/lib/cbfstool.c
@@ -4,9 +4,12 @@
*/
#include "2common.h"
+#include "2crypto.h"
#include "2return_codes.h"
-#include "subprocess.h"
#include "cbfstool.h"
+#include "host_misc.h"
+#include "subprocess.h"
+#include "vboot_host.h"
static const char *get_cbfstool_path(void)
{
@@ -68,3 +71,166 @@ vb2_error_t cbfstool_truncate(const char *file, const char *region,
return VB2_SUCCESS;
}
+
+/* Requires null-terminated buffer */
+static vb2_error_t extract_metadata_hash(const char *buf, struct vb2_hash *hash)
+{
+ enum vb2_hash_algorithm algo;
+ const char *to_find = "\n[METADATA HASH]";
+ char *algo_str = NULL;
+ char *hash_str = NULL;
+ vb2_error_t rv = VB2_ERROR_CBFSTOOL;
+
+ const char *start = strstr(buf, to_find);
+ if (start)
+ start += strlen(to_find);
+
+ if (start) {
+ const int matches = sscanf(start, " %m[^:\n\t ]:%m[^:\n\t ]",
+ &algo_str, &hash_str);
+
+ if (matches < 2)
+ goto done;
+
+ if (!algo_str || !vb2_lookup_hash_alg(algo_str, &algo) ||
+ algo == VB2_HASH_INVALID)
+ goto done;
+ hash->algo = algo;
+
+ if (!hash_str ||
+ strlen(hash_str) != (vb2_digest_size(algo) * 2) ||
+ !parse_hash(&hash->raw[0], vb2_digest_size(algo), hash_str))
+ goto done;
+
+ if (!strstr(buf, "] fully valid"))
+ goto done;
+
+ rv = VB2_SUCCESS;
+ }
+
+done:
+ if (rv != VB2_SUCCESS)
+ hash->algo = VB2_HASH_INVALID;
+
+ free(algo_str);
+ free(hash_str);
+
+ return rv;
+}
+
+vb2_error_t cbfstool_get_metadata_hash(const char *file, const char *region,
+ struct vb2_hash *hash)
+{
+ int status;
+ const char *cbfstool = get_cbfstool_path();
+ const size_t data_buffer_sz = 1024 * 1024;
+ char *data_buffer = malloc(data_buffer_sz);
+ vb2_error_t rv = VB2_ERROR_CBFSTOOL;
+
+ if (!data_buffer)
+ goto done;
+
+ memset(hash, 0, sizeof(*hash));
+ hash->algo = VB2_HASH_INVALID;
+
+ struct subprocess_target output = {
+ .type = TARGET_BUFFER_NULL_TERMINATED,
+ .buffer = {
+ .buf = data_buffer,
+ .size = data_buffer_sz,
+ },
+ };
+ const char *argv[] = {
+ cbfstool, file, "print", "-kv",
+ region ? "-r" : NULL, region, NULL
+ };
+
+ status = subprocess_run(argv, &subprocess_null, &output,
+ &subprocess_null);
+
+ if (status < 0) {
+ fprintf(stderr, "%s(): cbfstool invocation failed: %m\n",
+ __func__);
+ exit(1);
+ }
+
+ if (status > 0)
+ goto done;
+
+ rv = extract_metadata_hash(data_buffer, hash);
+
+done:
+ free(data_buffer);
+ return rv;
+}
+
+/* Requires null-terminated buffer */
+static char *extract_config_value(const char *buf, const char *config_field)
+{
+ char *to_find = NULL;
+
+ if (asprintf(&to_find, "\n%s=", config_field) == -1) {
+ fprintf(stderr, "Out of Memory\n");
+ VB2_DIE("Out of memory\n");
+ }
+
+ const char *start = strstr(buf, to_find);
+ if (start)
+ start += strlen(to_find);
+
+ free(to_find);
+
+ if (start) {
+ char *end = strchr(start, '\n');
+ if (end)
+ return strndup(start, end - start);
+ }
+
+ return NULL;
+}
+
+vb2_error_t cbfstool_get_config_value(const char *file, const char *region,
+ const char *config_field, char **value)
+{
+ int status;
+ const char *cbfstool = get_cbfstool_path();
+ const size_t data_buffer_sz = 1024 * 1024;
+ char *data_buffer = malloc(data_buffer_sz);
+ vb2_error_t rv = VB2_ERROR_CBFSTOOL;
+
+ *value = NULL;
+
+ if (!data_buffer)
+ goto done;
+
+ struct subprocess_target output = {
+ .type = TARGET_BUFFER_NULL_TERMINATED,
+ .buffer = {
+ .buf = data_buffer,
+ .size = data_buffer_sz,
+ },
+ };
+ const char *argv[] = {
+ cbfstool, file, "extract", "-n", "config", "-f", "/dev/stdout",
+ region ? "-r" : NULL, region, NULL
+ };
+
+ status = subprocess_run(argv, &subprocess_null, &output,
+ &subprocess_null);
+
+ if (status < 0) {
+ fprintf(stderr, "%s(): cbfstool invocation failed: %m\n",
+ __func__);
+ exit(1);
+ }
+
+ if (status > 0)
+ goto done;
+
+ *value = extract_config_value(data_buffer, config_field);
+
+ rv = VB2_SUCCESS;
+done:
+ free(data_buffer);
+ return rv;
+}
diff --git a/host/lib/host_misc.c b/host/lib/host_misc.c
index 63d1fee4..899d807f 100644
--- a/host/lib/host_misc.c
+++ b/host/lib/host_misc.c
@@ -116,3 +116,53 @@ vb2_error_t WriteFile(const char* filename, const void *data, uint64_t size)
fclose(f);
return 0;
}
+
+bool parse_hex(uint8_t *val, const char *str)
+{
+ uint8_t v = 0;
+ char c;
+ int digit;
+
+ for (digit = 0; digit < 2; digit++) {
+ c = *str;
+ if (!c)
+ return false;
+ if (!isxdigit(c))
+ return false;
+ c = tolower(c);
+ if (c >= '0' && c <= '9')
+ v += c - '0';
+ else
+ v += 10 + c - 'a';
+ if (!digit)
+ v <<= 4;
+ str++;
+ }
+
+ *val = v;
+ return true;
+}
+
+bool parse_hash(uint8_t *buf, size_t len, const char *str)
+{
+ const char *s = str;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ /* skip whitespace */
+ while (*s && isspace(*s))
+ s++;
+ if (!*s)
+ break;
+ if (!parse_hex(buf, s))
+ break;
+
+ /* on to the next byte */
+ s += 2;
+ buf++;
+ }
+
+ if (i != len || *s)
+ return false;
+ return true;
+}
diff --git a/host/lib/host_signature2.c b/host/lib/host_signature2.c
index 5ec307d6..a588d1ee 100644
--- a/host/lib/host_signature2.c
+++ b/host/lib/host_signature2.c
@@ -132,3 +132,28 @@ struct vb2_signature *vb2_calculate_signature(
/* Return the signature */
return sig;
}
+
+struct vb2_signature *
+vb2_create_signature_from_hash(const struct vb2_hash *hash)
+{
+ const uint32_t hsize = vb2_digest_size(hash->algo);
+
+ /* Unsupported algorithm */
+ if (!hsize)
+ return NULL;
+
+ const uint32_t full_hsize = offsetof(struct vb2_hash, raw) + hsize;
+
+ /* The body size is unknown, so set it to zero */
+ struct vb2_signature *sig =
+ (struct vb2_signature *)vb2_alloc_signature(full_hsize, 0);
+ if (!sig)
+ return NULL;
+
+ if (!memcpy(vb2_signature_data_mutable(sig), hash, full_hsize)) {
+ free(sig);
+ return NULL;
+ }
+
+ return sig;
+}
diff --git a/host/lib/include/cbfstool.h b/host/lib/include/cbfstool.h
index acc6e927..863039ec 100644
--- a/host/lib/include/cbfstool.h
+++ b/host/lib/include/cbfstool.h
@@ -4,9 +4,34 @@
*/
#include "2return_codes.h"
+#include "2sha.h"
#define ENV_CBFSTOOL "CBFSTOOL"
#define DEFAULT_CBFSTOOL "cbfstool"
vb2_error_t cbfstool_truncate(const char *file, const char *region,
size_t *new_size);
+
+/*
+ * Check whether image under `file` path supports CBFS_VERIFICATION,
+ * and contains metadata hash. Hash found is available under *hash. If it was
+ * not found, then hash type will be set to VB2_HASH_INVALID.
+ *
+ * If `region` is NULL, then region option will not be passed to cbfstool.
+ * Operations will be performed on default `COREBOOT` region.
+ */
+vb2_error_t cbfstool_get_metadata_hash(const char *file, const char *region,
+ struct vb2_hash *hash);
+
+/*
+ * Get value of `config` file field.
+ *
+ * This function extracts "config" file from selected region, parses it to find
+ * value of `config_field`, and returns it to `value` as allocated string
+ * (which has to be freed) or NULL if value was not found.
+ *
+ * If `region` is NULL, then region option will not be passed to cbfstool.
+ * Operations will be performed on default `COREBOOT` region.
+ */
+vb2_error_t cbfstool_get_config_value(const char *file, const char *region,
+ const char *config_field, char **value);
diff --git a/host/lib/include/host_misc.h b/host/lib/include/host_misc.h
index 1a59af54..96aba057 100644
--- a/host/lib/include/host_misc.h
+++ b/host/lib/include/host_misc.h
@@ -8,6 +8,8 @@
#ifndef VBOOT_REFERENCE_HOST_MISC_H_
#define VBOOT_REFERENCE_HOST_MISC_H_
+#include <stdbool.h>
+
#include "vboot_struct.h"
#include "vboot_api.h"
@@ -99,4 +101,25 @@ static inline const uint32_t roundup32(uint32_t v)
*/
uint32_t vb2_desc_size(const char *desc);
+/**
+ * Parse byte from hex string.
+ *
+ * @param val Pointer to the value buffer
+ * @param str String to parse
+ * @return true on success, false otherwise.
+ * */
+bool parse_hex(uint8_t *val, const char *str);
+
+
+/**
+ * Parse hash from string.
+ *
+ * @param buf Output buffer. Has to be at least `len` bytes long
+ * @param len Hash length in bytes
+ * @param str Hash string form. Has to be at least 2 * `len` long
+ * Whitespaces are ignored
+ * @return true on success, false otherwise.
+ */
+bool parse_hash(uint8_t *buf, size_t len, const char *str);
+
#endif /* VBOOT_REFERENCE_HOST_MISC_H_ */
diff --git a/host/lib/include/host_signature.h b/host/lib/include/host_signature.h
index 47ffe764..d154a9d5 100644
--- a/host/lib/include/host_signature.h
+++ b/host/lib/include/host_signature.h
@@ -85,4 +85,15 @@ struct vb2_signature *vb2_external_signature(const uint8_t *data, uint32_t size,
uint32_t key_algorithm,
const char *external_signer);
+/**
+ * Create signature using the provided hash as its body. Created signature
+ * contains vb2_hash trimmed to fit digest of its algorithm and nothing more.
+ *
+ * @param hash Hash to create signature from
+ *
+ * @return The signature, or NULL if error. Caller must free() it.
+ */
+struct vb2_signature *
+vb2_create_signature_from_hash(const struct vb2_hash *hash);
+
#endif /* VBOOT_REFERENCE_HOST_SIGNATURE_H_ */