diff options
Diffstat (limited to 'crypto/asymmetric_keys/asymmetric_type.c')
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 265 |
1 files changed, 203 insertions, 62 deletions
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index eb8cd46..bcbbbd7 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -15,6 +15,7 @@ #include <linux/seq_file.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/ctype.h> #include "asymmetric_keys.h" MODULE_LICENSE("GPL"); @@ -22,85 +23,209 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(asymmetric_key_parsers); static DECLARE_RWSEM(asymmetric_key_parsers_sem); -/* - * Match asymmetric key id with partial match - * @id: key id to match in a form "id:<id>" +/** + * asymmetric_key_generate_id: Construct an asymmetric key ID + * @val_1: First binary blob + * @len_1: Length of first binary blob + * @val_2: Second binary blob + * @len_2: Length of second binary blob + * + * Construct an asymmetric key ID from a pair of binary blobs. */ -int asymmetric_keyid_match(const char *kid, const char *id) +struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, + size_t len_1, + const void *val_2, + size_t len_2) { - size_t idlen, kidlen; + struct asymmetric_key_id *kid; + + kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2, + GFP_KERNEL); + if (!kid) + return ERR_PTR(-ENOMEM); + kid->len = len_1 + len_2; + memcpy(kid->data, val_1, len_1); + memcpy(kid->data + len_1, val_2, len_2); + return kid; +} +EXPORT_SYMBOL_GPL(asymmetric_key_generate_id); - if (!kid || !id) - return 0; +/** + * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same. + * @kid_1, @kid_2: The key IDs to compare + */ +bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1, + const struct asymmetric_key_id *kid2) +{ + if (!kid1 || !kid2) + return false; + if (kid1->len != kid2->len) + return false; + return memcmp(kid1->data, kid2->data, kid1->len) == 0; +} +EXPORT_SYMBOL_GPL(asymmetric_key_id_same); - /* make it possible to use id as in the request: "id:<id>" */ - if (strncmp(id, "id:", 3) == 0) - id += 3; +/** + * asymmetric_key_id_partial - Return true if two asymmetric keys IDs + * partially match + * @kid_1, @kid_2: The key IDs to compare + */ +bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1, + const struct asymmetric_key_id *kid2) +{ + if (!kid1 || !kid2) + return false; + if (kid1->len < kid2->len) + return false; + return memcmp(kid1->data + (kid1->len - kid2->len), + kid2->data, kid2->len) == 0; +} +EXPORT_SYMBOL_GPL(asymmetric_key_id_partial); - /* Anything after here requires a partial match on the ID string */ - idlen = strlen(id); - kidlen = strlen(kid); - if (idlen > kidlen) - return 0; +/** + * asymmetric_match_key_ids - Search asymmetric key IDs + * @kids: The list of key IDs to check + * @match_id: The key ID we're looking for + * @match: The match function to use + */ +static bool asymmetric_match_key_ids( + const struct asymmetric_key_ids *kids, + const struct asymmetric_key_id *match_id, + bool (*match)(const struct asymmetric_key_id *kid1, + const struct asymmetric_key_id *kid2)) +{ + int i; + + if (!kids || !match_id) + return false; + for (i = 0; i < ARRAY_SIZE(kids->id); i++) + if (match(kids->id[i], match_id)) + return true; + return false; +} - kid += kidlen - idlen; - if (strcasecmp(id, kid) != 0) - return 0; +/** + * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID. + * @id: The ID as a hex string. + */ +struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id) +{ + struct asymmetric_key_id *match_id; + size_t hexlen; + int ret; - return 1; + if (!*id) + return ERR_PTR(-EINVAL); + hexlen = strlen(id); + if (hexlen & 1) + return ERR_PTR(-EINVAL); + + match_id = kmalloc(sizeof(struct asymmetric_key_id) + hexlen / 2, + GFP_KERNEL); + if (!match_id) + return ERR_PTR(-ENOMEM); + match_id->len = hexlen / 2; + ret = hex2bin(match_id->data, id, hexlen / 2); + if (ret < 0) { + kfree(match_id); + return ERR_PTR(-EINVAL); + } + return match_id; } -EXPORT_SYMBOL_GPL(asymmetric_keyid_match); /* - * Match asymmetric keys on (part of) their name - * We have some shorthand methods for matching keys. We allow: - * - * "<desc>" - request a key by description - * "id:<id>" - request a key matching the ID - * "<subtype>:<id>" - request a key of a subtype + * Match asymmetric keys by an exact match on an ID. */ -static int asymmetric_key_match(const struct key *key, const void *description) +static bool asymmetric_key_cmp(const struct key *key, + const struct key_match_data *match_data) { - const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); - const char *spec = description; - const char *id; - ptrdiff_t speclen; + const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); + const struct asymmetric_key_id *match_id = match_data->preparsed; - if (!subtype || !spec || !*spec) - return 0; + return asymmetric_match_key_ids(kids, match_id, + asymmetric_key_id_same); +} - /* See if the full key description matches as is */ - if (key->description && strcmp(key->description, description) == 0) - return 1; +/* + * Match asymmetric keys by a partial match on an IDs. + */ +static bool asymmetric_key_cmp_partial(const struct key *key, + const struct key_match_data *match_data) +{ + const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); + const struct asymmetric_key_id *match_id = match_data->preparsed; - /* All tests from here on break the criterion description into a - * specifier, a colon and then an identifier. - */ - id = strchr(spec, ':'); - if (!id) - return 0; + return asymmetric_match_key_ids(kids, match_id, + asymmetric_key_id_partial); +} + +/* + * Preparse the match criterion. If we don't set lookup_type and cmp, + * the default will be an exact match on the key description. + * + * There are some specifiers for matching key IDs rather than by the key + * description: + * + * "id:<id>" - find a key by partial match on any available ID + * "ex:<id>" - find a key by exact match on any available ID + * + * These have to be searched by iteration rather than by direct lookup because + * the key is hashed according to its description. + */ +static int asymmetric_key_match_preparse(struct key_match_data *match_data) +{ + struct asymmetric_key_id *match_id; + const char *spec = match_data->raw_data; + const char *id; + bool (*cmp)(const struct key *, const struct key_match_data *) = + asymmetric_key_cmp; - speclen = id - spec; - id++; + if (!spec || !*spec) + return -EINVAL; + if (spec[0] == 'i' && + spec[1] == 'd' && + spec[2] == ':') { + id = spec + 3; + cmp = asymmetric_key_cmp_partial; + } else if (spec[0] == 'e' && + spec[1] == 'x' && + spec[2] == ':') { + id = spec + 3; + } else { + goto default_match; + } - if (speclen == 2 && memcmp(spec, "id", 2) == 0) - return asymmetric_keyid_match(asymmetric_key_id(key), id); + match_id = asymmetric_key_hex_to_key_id(id); + if (IS_ERR(match_id)) + return PTR_ERR(match_id); - if (speclen == subtype->name_len && - memcmp(spec, subtype->name, speclen) == 0) - return 1; + match_data->preparsed = match_id; + match_data->cmp = cmp; + match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; + return 0; +default_match: return 0; } /* + * Free the preparsed the match criterion. + */ +static void asymmetric_key_match_free(struct key_match_data *match_data) +{ + kfree(match_data->preparsed); +} + +/* * Describe the asymmetric key */ static void asymmetric_key_describe(const struct key *key, struct seq_file *m) { const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); - const char *kid = asymmetric_key_id(key); - size_t n; + const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); + const struct asymmetric_key_id *kid; + const unsigned char *p; + int n; seq_puts(m, key->description); @@ -108,13 +233,16 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m) seq_puts(m, ": "); subtype->describe(key, m); - if (kid) { + if (kids && kids->id[1]) { + kid = kids->id[1]; seq_putc(m, ' '); - n = strlen(kid); - if (n <= 8) - seq_puts(m, kid); - else - seq_puts(m, kid + n - 8); + n = kid->len; + p = kid->data; + if (n > 4) { + p += n - 4; + n = 4; + } + seq_printf(m, "%*phN", n, p); } seq_puts(m, " ["); @@ -165,6 +293,8 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep) static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) { struct asymmetric_key_subtype *subtype = prep->type_data[0]; + struct asymmetric_key_ids *kids = prep->type_data[1]; + int i; pr_devel("==>%s()\n", __func__); @@ -172,7 +302,11 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) subtype->destroy(prep->payload[0]); module_put(subtype->owner); } - kfree(prep->type_data[1]); + if (kids) { + for (i = 0; i < ARRAY_SIZE(kids->id); i++) + kfree(kids->id[i]); + kfree(kids); + } kfree(prep->description); } @@ -182,13 +316,20 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) static void asymmetric_key_destroy(struct key *key) { struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); + struct asymmetric_key_ids *kids = key->type_data.p[1]; + if (subtype) { subtype->destroy(key->payload.data); module_put(subtype->owner); key->type_data.p[0] = NULL; } - kfree(key->type_data.p[1]); - key->type_data.p[1] = NULL; + + if (kids) { + kfree(kids->id[0]); + kfree(kids->id[1]); + kfree(kids); + key->type_data.p[1] = NULL; + } } struct key_type key_type_asymmetric = { @@ -196,10 +337,10 @@ struct key_type key_type_asymmetric = { .preparse = asymmetric_key_preparse, .free_preparse = asymmetric_key_free_preparse, .instantiate = generic_key_instantiate, - .match = asymmetric_key_match, + .match_preparse = asymmetric_key_match_preparse, + .match_free = asymmetric_key_match_free, .destroy = asymmetric_key_destroy, .describe = asymmetric_key_describe, - .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE, }; EXPORT_SYMBOL_GPL(key_type_asymmetric); |