diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/lib/cbfstool.c | 168 | ||||
-rw-r--r-- | host/lib/host_misc.c | 50 | ||||
-rw-r--r-- | host/lib/host_signature2.c | 25 | ||||
-rw-r--r-- | host/lib/include/cbfstool.h | 25 | ||||
-rw-r--r-- | host/lib/include/host_misc.h | 23 | ||||
-rw-r--r-- | host/lib/include/host_signature.h | 11 |
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_ */ |