Loading Documentation/security/keys.txt +52 −13 Original line number Diff line number Diff line Loading @@ -888,11 +888,11 @@ payload contents" for more information. const char *callout_info); This is used to request a key or keyring with a description that matches the description specified according to the key type's match function. This permits approximate matching to occur. If callout_string is not NULL, then /sbin/request-key will be invoked in an attempt to obtain the key from userspace. In that case, callout_string will be passed as an argument to the program. the description specified according to the key type's match_preparse() method. This permits approximate matching to occur. If callout_string is not NULL, then /sbin/request-key will be invoked in an attempt to obtain the key from userspace. In that case, callout_string will be passed as an argument to the program. Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be returned. Loading Loading @@ -1225,16 +1225,55 @@ The structure has a number of fields, some of which are mandatory: It is safe to sleep in this method. (*) int (*match)(const struct key *key, const void *desc); (*) int (*match_preparse)(struct key_match_data *match_data); This method is called to match a key against a description. It should return non-zero if the two match, zero if they don't. This method is optional. It is called when a key search is about to be performed. It is given the following structure: This method should not need to lock the key in any way. The type and description can be considered invariant, and the payload should not be accessed (the key may not yet be instantiated). struct key_match_data { bool (*cmp)(const struct key *key, const struct key_match_data *match_data); const void *raw_data; void *preparsed; unsigned lookup_type; }; It is not safe to sleep in this method; the caller may hold spinlocks. On entry, raw_data will be pointing to the criteria to be used in matching a key by the caller and should not be modified. (*cmp)() will be pointing to the default matcher function (which does an exact description match against raw_data) and lookup_type will be set to indicate a direct lookup. The following lookup_type values are available: [*] KEYRING_SEARCH_LOOKUP_DIRECT - A direct lookup hashes the type and description to narrow down the search to a small number of keys. [*] KEYRING_SEARCH_LOOKUP_ITERATE - An iterative lookup walks all the keys in the keyring until one is matched. This must be used for any search that's not doing a simple direct match on the key description. The method may set cmp to point to a function of its choice that does some other form of match, may set lookup_type to KEYRING_SEARCH_LOOKUP_ITERATE and may attach something to the preparsed pointer for use by (*cmp)(). (*cmp)() should return true if a key matches and false otherwise. If preparsed is set, it may be necessary to use the match_free() method to clean it up. The method should return 0 if successful or a negative error code otherwise. It is permitted to sleep in this method, but (*cmp)() may not sleep as locks will be held over it. If match_preparse() is not provided, keys of this type will be matched exactly by their description. (*) void (*match_free)(struct key_match_data *match_data); This method is optional. If given, it called to clean up match_data->preparsed after a successful call to match_preparse(). (*) void (*revoke)(struct key *key); Loading crypto/asymmetric_keys/asymmetric_keys.h +6 −2 Original line number Diff line number Diff line Loading @@ -9,9 +9,13 @@ * 2 of the Licence, or (at your option) any later version. */ int asymmetric_keyid_match(const char *kid, const char *id); extern bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids, const struct asymmetric_key_id *match_id); static inline const char *asymmetric_key_id(const struct key *key) extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); static inline const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key) { return key->type_data.p[1]; } crypto/asymmetric_keys/asymmetric_type.c +160 −63 Original line number Diff line number Diff line Loading @@ -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"); Loading @@ -22,85 +23,166 @@ 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_match_key_ids - Search asymmetric key IDs * @kids: The list of key IDs to check * @match_id: The key ID we're looking for */ bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids, const struct asymmetric_key_id *match_id) { if (!kids || !match_id) return false; if (asymmetric_key_id_same(kids->id[0], match_id)) return true; if (asymmetric_key_id_same(kids->id[1], match_id)) return true; return false; } EXPORT_SYMBOL_GPL(asymmetric_match_key_ids); /* Anything after here requires a partial match on the ID string */ idlen = strlen(id); kidlen = strlen(kid); if (idlen > kidlen) 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; kid += kidlen - idlen; if (strcasecmp(id, kid) != 0) return 0; 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; } return 1; /* * Match asymmetric keys by ID. */ static bool asymmetric_key_cmp(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; return asymmetric_match_key_ids(kids, 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: * 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: * * "<desc>" - request a key by description * "id:<id>" - request a key matching the ID * "<subtype>:<id>" - request a key of a subtype * "id:<id>" - request a key by 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(const struct key *key, const void *description) static int asymmetric_key_match_preparse(struct key_match_data *match_data) { const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); const char *spec = description; struct asymmetric_key_id *match_id; const char *spec = match_data->raw_data; const char *id; ptrdiff_t speclen; if (!subtype || !spec || !*spec) return 0; if (!spec || !*spec) return -EINVAL; if (spec[0] == 'i' && spec[1] == 'd' && spec[2] == ':') { id = spec + 3; } else { goto default_match; } /* See if the full key description matches as is */ if (key->description && strcmp(key->description, description) == 0) return 1; match_id = asymmetric_key_hex_to_key_id(id); if (!match_id) return -ENOMEM; /* All tests from here on break the criterion description into a * specifier, a colon and then an identifier. */ id = strchr(spec, ':'); if (!id) match_data->preparsed = match_id; match_data->cmp = asymmetric_key_cmp; match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; return 0; speclen = id - spec; id++; if (speclen == 2 && memcmp(spec, "id", 2) == 0) return asymmetric_keyid_match(asymmetric_key_id(key), id); if (speclen == subtype->name_len && memcmp(spec, subtype->name, speclen) == 0) return 1; 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); Loading @@ -108,13 +190,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[0]) { kid = kids->id[0]; 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 > 8) { p += n - 8; n = 8; } seq_printf(m, "%*phN", n, p); } seq_puts(m, " ["); Loading Loading @@ -165,6 +250,7 @@ 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]; pr_devel("==>%s()\n", __func__); Loading @@ -172,7 +258,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) { kfree(kids->id[0]); kfree(kids->id[1]); kfree(kids); } kfree(prep->description); } Loading @@ -182,24 +272,31 @@ 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]); if (kids) { kfree(kids->id[0]); kfree(kids->id[1]); kfree(kids); key->type_data.p[1] = NULL; } } struct key_type key_type_asymmetric = { .name = "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); Loading crypto/asymmetric_keys/pkcs7_key_type.c +0 −2 Original line number Diff line number Diff line Loading @@ -72,11 +72,9 @@ error: */ static struct key_type key_type_pkcs7 = { .name = "pkcs7_test", .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .preparse = pkcs7_preparse, .free_preparse = user_free_preparse, .instantiate = generic_key_instantiate, .match = user_match, .revoke = user_revoke, .destroy = user_destroy, .describe = user_describe, Loading crypto/asymmetric_keys/pkcs7_parser.c +60 −39 Original line number Diff line number Diff line Loading @@ -29,8 +29,25 @@ struct pkcs7_parse_context { enum OID last_oid; /* Last OID encountered */ unsigned x509_index; unsigned sinfo_index; const void *raw_serial; unsigned raw_serial_size; unsigned raw_issuer_size; const void *raw_issuer; }; /* * Free a signed information block. */ static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) { if (sinfo) { mpi_free(sinfo->sig.mpi[0]); kfree(sinfo->sig.digest); kfree(sinfo->signing_cert_id); kfree(sinfo); } } /** * pkcs7_free_message - Free a PKCS#7 message * @pkcs7: The PKCS#7 message to free Loading @@ -54,9 +71,7 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7) while (pkcs7->signed_infos) { sinfo = pkcs7->signed_infos; pkcs7->signed_infos = sinfo->next; mpi_free(sinfo->sig.mpi[0]); kfree(sinfo->sig.digest); kfree(sinfo); pkcs7_free_signed_info(sinfo); } kfree(pkcs7); } Loading @@ -71,51 +86,46 @@ EXPORT_SYMBOL_GPL(pkcs7_free_message); struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) { struct pkcs7_parse_context *ctx; struct pkcs7_message *msg; long ret; struct pkcs7_message *msg = ERR_PTR(-ENOMEM); int ret; ret = -ENOMEM; msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); if (!msg) goto error_no_sig; ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL); if (!ctx) goto error_no_ctx; goto out_no_ctx; ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); if (!ctx->msg) goto out_no_msg; ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); if (!ctx->sinfo) goto error_no_sinfo; goto out_no_sinfo; ctx->msg = msg; ctx->data = (unsigned long)data; ctx->ppcerts = &ctx->certs; ctx->ppsinfo = &ctx->msg->signed_infos; /* Attempt to decode the signature */ ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen); if (ret < 0) goto error_decode; if (ret < 0) { msg = ERR_PTR(ret); goto out; } msg = ctx->msg; ctx->msg = NULL; out: while (ctx->certs) { struct x509_certificate *cert = ctx->certs; ctx->certs = cert->next; x509_free_certificate(cert); } mpi_free(ctx->sinfo->sig.mpi[0]); kfree(ctx->sinfo->sig.digest); kfree(ctx->sinfo); pkcs7_free_signed_info(ctx->sinfo); out_no_sinfo: pkcs7_free_message(ctx->msg); out_no_msg: kfree(ctx); out_no_ctx: return msg; error_decode: mpi_free(ctx->sinfo->sig.mpi[0]); kfree(ctx->sinfo->sig.digest); kfree(ctx->sinfo); error_no_sinfo: kfree(ctx); error_no_ctx: pkcs7_free_message(msg); error_no_sig: return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(pkcs7_parse_message); Loading Loading @@ -246,10 +256,10 @@ int pkcs7_extract_cert(void *context, size_t hdrlen, if (IS_ERR(x509)) return PTR_ERR(x509); pr_debug("Got cert for %s\n", x509->subject); pr_debug("- fingerprint %s\n", x509->fingerprint); x509->index = ++ctx->x509_index; pr_debug("Got cert %u for %s\n", x509->index, x509->subject); pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data); *ctx->ppcerts = x509; ctx->ppcerts = &x509->next; return 0; Loading Loading @@ -338,8 +348,8 @@ int pkcs7_sig_note_serial(void *context, size_t hdrlen, const void *value, size_t vlen) { struct pkcs7_parse_context *ctx = context; ctx->sinfo->raw_serial = value; ctx->sinfo->raw_serial_size = vlen; ctx->raw_serial = value; ctx->raw_serial_size = vlen; return 0; } Loading @@ -351,8 +361,8 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen, const void *value, size_t vlen) { struct pkcs7_parse_context *ctx = context; ctx->sinfo->raw_issuer = value; ctx->sinfo->raw_issuer_size = vlen; ctx->raw_issuer = value; ctx->raw_issuer_size = vlen; return 0; } Loading Loading @@ -385,10 +395,21 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, const void *value, size_t vlen) { struct pkcs7_parse_context *ctx = context; ctx->sinfo->index = ++ctx->sinfo_index; *ctx->ppsinfo = ctx->sinfo; ctx->ppsinfo = &ctx->sinfo->next; struct pkcs7_signed_info *sinfo = ctx->sinfo; struct asymmetric_key_id *kid; /* Generate cert issuer + serial number key ID */ kid = asymmetric_key_generate_id(ctx->raw_serial, ctx->raw_serial_size, ctx->raw_issuer, ctx->raw_issuer_size); if (IS_ERR(kid)) return PTR_ERR(kid); sinfo->signing_cert_id = kid; sinfo->index = ++ctx->sinfo_index; *ctx->ppsinfo = sinfo; ctx->ppsinfo = &sinfo->next; ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); if (!ctx->sinfo) return -ENOMEM; Loading Loading
Documentation/security/keys.txt +52 −13 Original line number Diff line number Diff line Loading @@ -888,11 +888,11 @@ payload contents" for more information. const char *callout_info); This is used to request a key or keyring with a description that matches the description specified according to the key type's match function. This permits approximate matching to occur. If callout_string is not NULL, then /sbin/request-key will be invoked in an attempt to obtain the key from userspace. In that case, callout_string will be passed as an argument to the program. the description specified according to the key type's match_preparse() method. This permits approximate matching to occur. If callout_string is not NULL, then /sbin/request-key will be invoked in an attempt to obtain the key from userspace. In that case, callout_string will be passed as an argument to the program. Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be returned. Loading Loading @@ -1225,16 +1225,55 @@ The structure has a number of fields, some of which are mandatory: It is safe to sleep in this method. (*) int (*match)(const struct key *key, const void *desc); (*) int (*match_preparse)(struct key_match_data *match_data); This method is called to match a key against a description. It should return non-zero if the two match, zero if they don't. This method is optional. It is called when a key search is about to be performed. It is given the following structure: This method should not need to lock the key in any way. The type and description can be considered invariant, and the payload should not be accessed (the key may not yet be instantiated). struct key_match_data { bool (*cmp)(const struct key *key, const struct key_match_data *match_data); const void *raw_data; void *preparsed; unsigned lookup_type; }; It is not safe to sleep in this method; the caller may hold spinlocks. On entry, raw_data will be pointing to the criteria to be used in matching a key by the caller and should not be modified. (*cmp)() will be pointing to the default matcher function (which does an exact description match against raw_data) and lookup_type will be set to indicate a direct lookup. The following lookup_type values are available: [*] KEYRING_SEARCH_LOOKUP_DIRECT - A direct lookup hashes the type and description to narrow down the search to a small number of keys. [*] KEYRING_SEARCH_LOOKUP_ITERATE - An iterative lookup walks all the keys in the keyring until one is matched. This must be used for any search that's not doing a simple direct match on the key description. The method may set cmp to point to a function of its choice that does some other form of match, may set lookup_type to KEYRING_SEARCH_LOOKUP_ITERATE and may attach something to the preparsed pointer for use by (*cmp)(). (*cmp)() should return true if a key matches and false otherwise. If preparsed is set, it may be necessary to use the match_free() method to clean it up. The method should return 0 if successful or a negative error code otherwise. It is permitted to sleep in this method, but (*cmp)() may not sleep as locks will be held over it. If match_preparse() is not provided, keys of this type will be matched exactly by their description. (*) void (*match_free)(struct key_match_data *match_data); This method is optional. If given, it called to clean up match_data->preparsed after a successful call to match_preparse(). (*) void (*revoke)(struct key *key); Loading
crypto/asymmetric_keys/asymmetric_keys.h +6 −2 Original line number Diff line number Diff line Loading @@ -9,9 +9,13 @@ * 2 of the Licence, or (at your option) any later version. */ int asymmetric_keyid_match(const char *kid, const char *id); extern bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids, const struct asymmetric_key_id *match_id); static inline const char *asymmetric_key_id(const struct key *key) extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); static inline const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key) { return key->type_data.p[1]; }
crypto/asymmetric_keys/asymmetric_type.c +160 −63 Original line number Diff line number Diff line Loading @@ -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"); Loading @@ -22,85 +23,166 @@ 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_match_key_ids - Search asymmetric key IDs * @kids: The list of key IDs to check * @match_id: The key ID we're looking for */ bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids, const struct asymmetric_key_id *match_id) { if (!kids || !match_id) return false; if (asymmetric_key_id_same(kids->id[0], match_id)) return true; if (asymmetric_key_id_same(kids->id[1], match_id)) return true; return false; } EXPORT_SYMBOL_GPL(asymmetric_match_key_ids); /* Anything after here requires a partial match on the ID string */ idlen = strlen(id); kidlen = strlen(kid); if (idlen > kidlen) 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; kid += kidlen - idlen; if (strcasecmp(id, kid) != 0) return 0; 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; } return 1; /* * Match asymmetric keys by ID. */ static bool asymmetric_key_cmp(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; return asymmetric_match_key_ids(kids, 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: * 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: * * "<desc>" - request a key by description * "id:<id>" - request a key matching the ID * "<subtype>:<id>" - request a key of a subtype * "id:<id>" - request a key by 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(const struct key *key, const void *description) static int asymmetric_key_match_preparse(struct key_match_data *match_data) { const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); const char *spec = description; struct asymmetric_key_id *match_id; const char *spec = match_data->raw_data; const char *id; ptrdiff_t speclen; if (!subtype || !spec || !*spec) return 0; if (!spec || !*spec) return -EINVAL; if (spec[0] == 'i' && spec[1] == 'd' && spec[2] == ':') { id = spec + 3; } else { goto default_match; } /* See if the full key description matches as is */ if (key->description && strcmp(key->description, description) == 0) return 1; match_id = asymmetric_key_hex_to_key_id(id); if (!match_id) return -ENOMEM; /* All tests from here on break the criterion description into a * specifier, a colon and then an identifier. */ id = strchr(spec, ':'); if (!id) match_data->preparsed = match_id; match_data->cmp = asymmetric_key_cmp; match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; return 0; speclen = id - spec; id++; if (speclen == 2 && memcmp(spec, "id", 2) == 0) return asymmetric_keyid_match(asymmetric_key_id(key), id); if (speclen == subtype->name_len && memcmp(spec, subtype->name, speclen) == 0) return 1; 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); Loading @@ -108,13 +190,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[0]) { kid = kids->id[0]; 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 > 8) { p += n - 8; n = 8; } seq_printf(m, "%*phN", n, p); } seq_puts(m, " ["); Loading Loading @@ -165,6 +250,7 @@ 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]; pr_devel("==>%s()\n", __func__); Loading @@ -172,7 +258,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) { kfree(kids->id[0]); kfree(kids->id[1]); kfree(kids); } kfree(prep->description); } Loading @@ -182,24 +272,31 @@ 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]); if (kids) { kfree(kids->id[0]); kfree(kids->id[1]); kfree(kids); key->type_data.p[1] = NULL; } } struct key_type key_type_asymmetric = { .name = "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); Loading
crypto/asymmetric_keys/pkcs7_key_type.c +0 −2 Original line number Diff line number Diff line Loading @@ -72,11 +72,9 @@ error: */ static struct key_type key_type_pkcs7 = { .name = "pkcs7_test", .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .preparse = pkcs7_preparse, .free_preparse = user_free_preparse, .instantiate = generic_key_instantiate, .match = user_match, .revoke = user_revoke, .destroy = user_destroy, .describe = user_describe, Loading
crypto/asymmetric_keys/pkcs7_parser.c +60 −39 Original line number Diff line number Diff line Loading @@ -29,8 +29,25 @@ struct pkcs7_parse_context { enum OID last_oid; /* Last OID encountered */ unsigned x509_index; unsigned sinfo_index; const void *raw_serial; unsigned raw_serial_size; unsigned raw_issuer_size; const void *raw_issuer; }; /* * Free a signed information block. */ static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo) { if (sinfo) { mpi_free(sinfo->sig.mpi[0]); kfree(sinfo->sig.digest); kfree(sinfo->signing_cert_id); kfree(sinfo); } } /** * pkcs7_free_message - Free a PKCS#7 message * @pkcs7: The PKCS#7 message to free Loading @@ -54,9 +71,7 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7) while (pkcs7->signed_infos) { sinfo = pkcs7->signed_infos; pkcs7->signed_infos = sinfo->next; mpi_free(sinfo->sig.mpi[0]); kfree(sinfo->sig.digest); kfree(sinfo); pkcs7_free_signed_info(sinfo); } kfree(pkcs7); } Loading @@ -71,51 +86,46 @@ EXPORT_SYMBOL_GPL(pkcs7_free_message); struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) { struct pkcs7_parse_context *ctx; struct pkcs7_message *msg; long ret; struct pkcs7_message *msg = ERR_PTR(-ENOMEM); int ret; ret = -ENOMEM; msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); if (!msg) goto error_no_sig; ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL); if (!ctx) goto error_no_ctx; goto out_no_ctx; ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); if (!ctx->msg) goto out_no_msg; ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); if (!ctx->sinfo) goto error_no_sinfo; goto out_no_sinfo; ctx->msg = msg; ctx->data = (unsigned long)data; ctx->ppcerts = &ctx->certs; ctx->ppsinfo = &ctx->msg->signed_infos; /* Attempt to decode the signature */ ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen); if (ret < 0) goto error_decode; if (ret < 0) { msg = ERR_PTR(ret); goto out; } msg = ctx->msg; ctx->msg = NULL; out: while (ctx->certs) { struct x509_certificate *cert = ctx->certs; ctx->certs = cert->next; x509_free_certificate(cert); } mpi_free(ctx->sinfo->sig.mpi[0]); kfree(ctx->sinfo->sig.digest); kfree(ctx->sinfo); pkcs7_free_signed_info(ctx->sinfo); out_no_sinfo: pkcs7_free_message(ctx->msg); out_no_msg: kfree(ctx); out_no_ctx: return msg; error_decode: mpi_free(ctx->sinfo->sig.mpi[0]); kfree(ctx->sinfo->sig.digest); kfree(ctx->sinfo); error_no_sinfo: kfree(ctx); error_no_ctx: pkcs7_free_message(msg); error_no_sig: return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(pkcs7_parse_message); Loading Loading @@ -246,10 +256,10 @@ int pkcs7_extract_cert(void *context, size_t hdrlen, if (IS_ERR(x509)) return PTR_ERR(x509); pr_debug("Got cert for %s\n", x509->subject); pr_debug("- fingerprint %s\n", x509->fingerprint); x509->index = ++ctx->x509_index; pr_debug("Got cert %u for %s\n", x509->index, x509->subject); pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data); *ctx->ppcerts = x509; ctx->ppcerts = &x509->next; return 0; Loading Loading @@ -338,8 +348,8 @@ int pkcs7_sig_note_serial(void *context, size_t hdrlen, const void *value, size_t vlen) { struct pkcs7_parse_context *ctx = context; ctx->sinfo->raw_serial = value; ctx->sinfo->raw_serial_size = vlen; ctx->raw_serial = value; ctx->raw_serial_size = vlen; return 0; } Loading @@ -351,8 +361,8 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen, const void *value, size_t vlen) { struct pkcs7_parse_context *ctx = context; ctx->sinfo->raw_issuer = value; ctx->sinfo->raw_issuer_size = vlen; ctx->raw_issuer = value; ctx->raw_issuer_size = vlen; return 0; } Loading Loading @@ -385,10 +395,21 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, const void *value, size_t vlen) { struct pkcs7_parse_context *ctx = context; ctx->sinfo->index = ++ctx->sinfo_index; *ctx->ppsinfo = ctx->sinfo; ctx->ppsinfo = &ctx->sinfo->next; struct pkcs7_signed_info *sinfo = ctx->sinfo; struct asymmetric_key_id *kid; /* Generate cert issuer + serial number key ID */ kid = asymmetric_key_generate_id(ctx->raw_serial, ctx->raw_serial_size, ctx->raw_issuer, ctx->raw_issuer_size); if (IS_ERR(kid)) return PTR_ERR(kid); sinfo->signing_cert_id = kid; sinfo->index = ++ctx->sinfo_index; *ctx->ppsinfo = sinfo; ctx->ppsinfo = &sinfo->next; ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); if (!ctx->sinfo) return -ENOMEM; Loading