summaryrefslogtreecommitdiff
path: root/host
diff options
context:
space:
mode:
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_ */