// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2019 Microsoft Corporation. * * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com> * */ #include <linux/device-mapper.h> #include <linux/verification.h> #include <keys/user-type.h> #include <linux/module.h> #include "dm-verity.h" #include "dm-verity-verify-sig.h" #define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s static bool require_signatures; module_param(require_signatures, bool, 0444); MODULE_PARM_DESC(require_signatures, "Verify the roothash of dm-verity hash tree"); #define DM_VERITY_IS_SIG_FORCE_ENABLED() \ (require_signatures != false) bool verity_verify_is_sig_opt_arg(const char *arg_name) { return (!strcasecmp(arg_name, DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY)); } static int verity_verify_get_sig_from_key(const char *key_desc, struct dm_verity_sig_opts *sig_opts) { struct key *key; const struct user_key_payload *ukp; int ret = 0; key = request_key(&key_type_user, key_desc, NULL); if (IS_ERR(key)) return PTR_ERR(key); down_read(&key->sem); ukp = user_key_payload_locked(key); if (!ukp) { ret = -EKEYREVOKED; goto end; } sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL); if (!sig_opts->sig) { ret = -ENOMEM; goto end; } sig_opts->sig_size = ukp->datalen; memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size); end: up_read(&key->sem); key_put(key); return ret; } int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, struct dm_verity_sig_opts *sig_opts, unsigned int *argc, const char *arg_name) { struct dm_target *ti = v->ti; int ret = 0; const char *sig_key = NULL; if (!*argc) { ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified"); return -EINVAL; } sig_key = dm_shift_arg(as); (*argc)--; ret = verity_verify_get_sig_from_key(sig_key, sig_opts); if (ret < 0) ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified"); v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL); if (!v->signature_key_desc) return -ENOMEM; return ret; } /* * verify_verify_roothash - Verify the root hash of the verity hash device * using builtin trusted keys. * * @root_hash: For verity, the roothash/data to be verified. * @root_hash_len: Size of the roothash/data to be verified. * @sig_data: The trusted signature that verifies the roothash/data. * @sig_len: Size of the signature. * */ int verity_verify_root_hash(const void *root_hash, size_t root_hash_len, const void *sig_data, size_t sig_len) { int ret; if (!root_hash || root_hash_len == 0) return -EINVAL; if (!sig_data || sig_len == 0) { if (DM_VERITY_IS_SIG_FORCE_ENABLED()) return -ENOKEY; else return 0; } ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, sig_len, #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING VERIFY_USE_SECONDARY_KEYRING, #else NULL, #endif VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); return ret; } void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts) { kfree(sig_opts->sig); sig_opts->sig = NULL; sig_opts->sig_size = 0; }