/* Asymmetric public-key cryptography key type * * See Documentation/security/asymmetric-keys.txt * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence * as published by the Free Software Foundation; either version * 2 of the Licence, or (at your option) any later version. */ //#include //#include //#include //#include //#include //#include //#include //#include //#include "asymmetric_keys.h" // // MODULE_LICENSE("GPL"); #include "asymmetric-type.h" #include "errno.h" #include "../rewrite/Lib.SoulExtraction.rewrite.h" #include "config.h" #define GFP_ATOMIC /*(__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)*/ 1 #define GFP_KERNEL /*(__GFP_RECLAIM | __GFP_IO | __GFP_FS)*/ 2 #define GFP_KERNEL_ACCOUNT /*(GFP_KERNEL | __GFP_ACCOUNT)*/ 3 #define GFP_NOWAIT /*(__GFP_KSWAPD_RECLAIM)*/ 4 #define GFP_NOIO /*(__GFP_RECLAIM)*/ 5 #define GFP_NOFS /*(__GFP_RECLAIM | __GFP_IO)*/ 6 #define GFP_USER /*(__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL)*/ 7 #define GFP_DMA /*__GFP_DMA*/ 8 #define GFP_DMA32 /*__GFP_DMA32*/ 9 #define GFP_HIGHUSER /*(GFP_USER | __GFP_HIGHMEM)*/ 10 #define GFP_HIGHUSER_MOVABLE /*(GFP_HIGHUSER | __GFP_MOVABLE)*/ 11 #define GFP_TRANSHUGE_LIGHT 12 #define GFP_TRANSHUGE /*(GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM)*/ 13 #define ERR_PTR(err) ((void *)((long)(err))) #define PTR_ERR(ptr) ((long)(ptr)) #define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000)) // const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = { // [VERIFYING_MODULE_SIGNATURE] = "mod sig", // [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig", // [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig", // [VERIFYING_KEY_SIGNATURE] = "key sig", // [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig", // [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig", // }; // EXPORT_SYMBOL_GPL(key_being_used_for); // // static LIST_HEAD(asymmetric_key_parsers); // static DECLARE_RWSEM(asymmetric_key_parsers_sem); /** * find_asymmetric_key - Find a key by ID. * @keyring: The keys to search. * @id_0: The first ID to look for or NULL. * @id_1: The second ID to look for or NULL. * @partial: Use partial match if true, exact if false. * * Find a key in the given keyring by identifier. The preferred identifier is * the id_0 and the fallback identifier is the id_1. If both are given, the * lookup is by the former, but the latter must also match. */ // struct key *find_asymmetric_key(struct key *keyring, // const struct asymmetric_key_id *id_0, // const struct asymmetric_key_id *id_1, // bool partial) //{ // struct key *key; // key_ref_t ref; // const char *lookup; // char *req, *p; // int len; // // BUG_ON(!id_0 && !id_1); // // if (id_0) { // lookup = id_0->data; // len = id_0->len; // } else { // lookup = id_1->data; // len = id_1->len; // } // // /* Construct an identifier "id:". */ // p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); // if (!req) // return ERR_PTR(-ENOMEM); // // if (partial) { // *p++ = 'i'; // *p++ = 'd'; // } else { // *p++ = 'e'; // *p++ = 'x'; // } // *p++ = ':'; // p = bin2hex(p, lookup, len); // *p = 0; // // pr_debug("Look up: \"%s\"\n", req); // // ref = keyring_search(make_key_ref(keyring, 1), // &key_type_asymmetric, req); // if (IS_ERR(ref)) // pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); // kfree(req); // // if (IS_ERR(ref)) { // switch (PTR_ERR(ref)) { // /* Hide some search errors */ // case -EACCES: // case -ENOTDIR: // case -EAGAIN: // return ERR_PTR(-ENOKEY); // default: // return ERR_CAST(ref); // } // } // // key = key_ref_to_ptr(ref); // if (id_0 && id_1) { // const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); // // if (!kids->id[1]) { // pr_debug("First ID matches, but second is missing\n"); // goto reject; // } // if (!asymmetric_key_id_same(id_1, kids->id[1])) { // pr_debug("First ID matches, but second does not\n"); // goto reject; // } // } // // pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); // return key; // // reject: // key_put(key); // return ERR_PTR(-EKEYREJECTED); // } // EXPORT_SYMBOL_GPL(find_asymmetric_key); /** * 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. */ struct asymmetric_key_id * asymmetric_key_generate_id(const void *val_1, size_t len_1, const void *val_2, size_t len_2) { 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); /** * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same. * @kid_1, @kid_2: The key IDs to compare */ unsigned char 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); /** * 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); /** * 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; // } /* helper function can be called directly with pre-allocated memory */ // inline int __asymmetric_key_hex_to_key_id(const char *id, // struct asymmetric_key_id *match_id, // size_t hexlen) //{ // match_id->len = hexlen; // return hex2bin(match_id->data, id, hexlen); // } /** * 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 asciihexlen; // int ret; // // if (!*id) // return ERR_PTR(-EINVAL); // asciihexlen = strlen(id); // if (asciihexlen & 1) // return ERR_PTR(-EINVAL); // // match_id = kmalloc(sizeof(struct asymmetric_key_id) + asciihexlen / 2, // GFP_KERNEL); // if (!match_id) // return ERR_PTR(-ENOMEM); // ret = __asymmetric_key_hex_to_key_id(id, match_id, asciihexlen / 2); // if (ret < 0) { // kfree(match_id); // return ERR_PTR(-EINVAL); // } // return match_id; // } /* * Match asymmetric keys by an exact match on an 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, // asymmetric_key_id_same); // } /* * 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; // // 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:" - find a key by partial match on any available ID * "ex:" - 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; // // 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; // } // // match_id = asymmetric_key_hex_to_key_id(id); // if (IS_ERR(match_id)) // return PTR_ERR(match_id); // // 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 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); // // if (subtype) { // seq_puts(m, ": "); // subtype->describe(key, m); // // if (kids && kids->id[1]) { // kid = kids->id[1]; // seq_putc(m, ' '); // n = kid->len; // p = kid->data; // if (n > 4) { // p += n - 4; // n = 4; // } // seq_printf(m, "%p", n, p); // } // // seq_puts(m, " ["); // /* put something here to indicate the key's capabilities */ // seq_putc(m, ']'); // } // } /* * Preparse a asymmetric payload to get format the contents appropriately for the * internal payload to cut down on the number of scans of the data performed. * * We also generate a proposed description from the contents of the key that * can be used to name the key if the user doesn't want to provide one. */ // static int asymmetric_key_preparse(struct key_preparsed_payload *prep) //{ // struct asymmetric_key_parser *parser; // int ret; // // pr_devel("==>%s()\n", __func__); // // if (prep->datalen == 0) // return -EINVAL; // // down_read(&asymmetric_key_parsers_sem); // // ret = -EBADMSG; // list_for_each_entry(parser, &asymmetric_key_parsers, link) { // pr_debug("Trying parser '%s'\n", parser->name); // // ret = parser->parse(prep); // if (ret != -EBADMSG) { // pr_debug("Parser recognised the format (ret %d)\n", // ret); // break; // } // } // // up_read(&asymmetric_key_parsers_sem); // pr_devel("<==%s() = %d\n", __func__, ret); // return ret; // } /* * Clean up the key ID list */ // static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids) //{ // int i; // // if (kids) { // for (i = 0; i < ARRAY_SIZE(kids->id); i++) // kfree(kids->id[i]); // kfree(kids); // } // } /* * Clean up the preparse data */ // static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) //{ // struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype]; // struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids]; // // pr_devel("==>%s()\n", __func__); // // if (subtype) { // subtype->destroy(prep->payload.data[asym_crypto], // prep->payload.data[asym_auth]); // module_put(subtype->owner); // } // asymmetric_key_free_kids(kids); // kfree(prep->description); // } /* * dispose of the data dangling from the corpse of a asymmetric key */ // static void asymmetric_key_destroy(struct key *key) //{ // struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); // struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids]; // void *data = key->payload.data[asym_crypto]; // void *auth = key->payload.data[asym_auth]; // // key->payload.data[asym_crypto] = NULL; // key->payload.data[asym_subtype] = NULL; // key->payload.data[asym_key_ids] = NULL; // key->payload.data[asym_auth] = NULL; // // if (subtype) { // subtype->destroy(data, auth); // module_put(subtype->owner); // } // // asymmetric_key_free_kids(kids); // } // static struct key_restriction *asymmetric_restriction_alloc( // key_restrict_link_func_t check, // struct key *key) //{ // struct key_restriction *keyres = // kzalloc(sizeof(struct key_restriction), GFP_KERNEL); // // if (!keyres) // return ERR_PTR(-ENOMEM); // // keyres->check = check; // keyres->key = key; // keyres->keytype = &key_type_asymmetric; // // return keyres; // } /* * look up keyring restrict functions for asymmetric keys */ // static struct key_restriction *asymmetric_lookup_restriction( // const char *restriction) //{ // char *restrict_method; // char *parse_buf; // char *next; // struct key_restriction *ret = ERR_PTR(-EINVAL); // // if (strcmp("builtin_trusted", restriction) == 0) // return asymmetric_restriction_alloc( // restrict_link_by_builtin_trusted, NULL); // // if (strcmp("builtin_and_secondary_trusted", restriction) == 0) // return asymmetric_restriction_alloc( // restrict_link_by_builtin_and_secondary_trusted, NULL); // // parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL); // if (!parse_buf) // return ERR_PTR(-ENOMEM); // // next = parse_buf; // restrict_method = strsep(&next, ":"); // // if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) { // char *key_text; // key_serial_t serial; // struct key *key; // key_restrict_link_func_t link_fn = // restrict_link_by_key_or_keyring; // bool allow_null_key = false; // // key_text = strsep(&next, ":"); // // if (next) { // if (strcmp(next, "chain") != 0) // goto out; // // link_fn = restrict_link_by_key_or_keyring_chain; // allow_null_key = true; // } // // if (kstrtos32(key_text, 0, &serial) < 0) // goto out; // // if ((serial == 0) && allow_null_key) { // key = NULL; // } else { // key = key_lookup(serial); // if (IS_ERR(key)) { // ret = ERR_CAST(key); // goto out; // } // } // // ret = asymmetric_restriction_alloc(link_fn, key); // if (IS_ERR(ret)) // key_put(key); // } // // out: // kfree(parse_buf); // return ret; // } // struct key_type key_type_asymmetric = { // .name = "asymmetric", // .preparse = asymmetric_key_preparse, // .free_preparse = asymmetric_key_free_preparse, // .instantiate = generic_key_instantiate, // .match_preparse = asymmetric_key_match_preparse, // .match_free = asymmetric_key_match_free, // .destroy = asymmetric_key_destroy, // .describe = asymmetric_key_describe, // .lookup_restriction = asymmetric_lookup_restriction, // }; // EXPORT_SYMBOL_GPL(key_type_asymmetric); /** * register_asymmetric_key_parser - Register a asymmetric key blob parser * @parser: The parser to register */ // int register_asymmetric_key_parser(struct asymmetric_key_parser *parser) //{ // struct asymmetric_key_parser *cursor; // int ret; // // down_write(&asymmetric_key_parsers_sem); // // list_for_each_entry(cursor, &asymmetric_key_parsers, link) { // if (strcmp(cursor->name, parser->name) == 0) { // pr_err("Asymmetric key parser '%s' already registered\n", // parser->name); // ret = -EEXIST; // goto out; // } // } // // list_add_tail(&parser->link, &asymmetric_key_parsers); // // pr_notice("Asymmetric key parser '%s' registered\n", parser->name); // ret = 0; // // out: // up_write(&asymmetric_key_parsers_sem); // return ret; // } // EXPORT_SYMBOL_GPL(register_asymmetric_key_parser); /** * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser * @parser: The parser to unregister */ // void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser) //{ // down_write(&asymmetric_key_parsers_sem); // list_del(&parser->link); // up_write(&asymmetric_key_parsers_sem); // // pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name); // } // EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); /* * Module stuff */ // static int __init asymmetric_key_init(void) //{ // return register_key_type(&key_type_asymmetric); // } // // static void __exit asymmetric_key_cleanup(void) //{ // unregister_key_type(&key_type_asymmetric); // } // // module_init(asymmetric_key_init); // module_exit(asymmetric_key_cleanup);