1*3bd94003SHeinz Mauelshagen // SPDX-License-Identifier: GPL-2.0-only
288cd3e6cSJaskaran Khurana /*
388cd3e6cSJaskaran Khurana * Copyright (C) 2019 Microsoft Corporation.
488cd3e6cSJaskaran Khurana *
588cd3e6cSJaskaran Khurana * Author: Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
688cd3e6cSJaskaran Khurana *
788cd3e6cSJaskaran Khurana */
888cd3e6cSJaskaran Khurana #include <linux/device-mapper.h>
988cd3e6cSJaskaran Khurana #include <linux/verification.h>
1088cd3e6cSJaskaran Khurana #include <keys/user-type.h>
1188cd3e6cSJaskaran Khurana #include <linux/module.h>
1288cd3e6cSJaskaran Khurana #include "dm-verity.h"
1388cd3e6cSJaskaran Khurana #include "dm-verity-verify-sig.h"
1488cd3e6cSJaskaran Khurana
1588cd3e6cSJaskaran Khurana #define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s
1688cd3e6cSJaskaran Khurana
1788cd3e6cSJaskaran Khurana static bool require_signatures;
180c1f3193SJohn Keeping module_param(require_signatures, bool, 0444);
1988cd3e6cSJaskaran Khurana MODULE_PARM_DESC(require_signatures,
2088cd3e6cSJaskaran Khurana "Verify the roothash of dm-verity hash tree");
2188cd3e6cSJaskaran Khurana
2288cd3e6cSJaskaran Khurana #define DM_VERITY_IS_SIG_FORCE_ENABLED() \
2388cd3e6cSJaskaran Khurana (require_signatures != false)
2488cd3e6cSJaskaran Khurana
verity_verify_is_sig_opt_arg(const char * arg_name)2588cd3e6cSJaskaran Khurana bool verity_verify_is_sig_opt_arg(const char *arg_name)
2688cd3e6cSJaskaran Khurana {
2788cd3e6cSJaskaran Khurana return (!strcasecmp(arg_name,
2888cd3e6cSJaskaran Khurana DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY));
2988cd3e6cSJaskaran Khurana }
3088cd3e6cSJaskaran Khurana
verity_verify_get_sig_from_key(const char * key_desc,struct dm_verity_sig_opts * sig_opts)3188cd3e6cSJaskaran Khurana static int verity_verify_get_sig_from_key(const char *key_desc,
3288cd3e6cSJaskaran Khurana struct dm_verity_sig_opts *sig_opts)
3388cd3e6cSJaskaran Khurana {
3488cd3e6cSJaskaran Khurana struct key *key;
3588cd3e6cSJaskaran Khurana const struct user_key_payload *ukp;
3688cd3e6cSJaskaran Khurana int ret = 0;
3788cd3e6cSJaskaran Khurana
3888cd3e6cSJaskaran Khurana key = request_key(&key_type_user,
3988cd3e6cSJaskaran Khurana key_desc, NULL);
4088cd3e6cSJaskaran Khurana if (IS_ERR(key))
4188cd3e6cSJaskaran Khurana return PTR_ERR(key);
4288cd3e6cSJaskaran Khurana
4388cd3e6cSJaskaran Khurana down_read(&key->sem);
4488cd3e6cSJaskaran Khurana
4588cd3e6cSJaskaran Khurana ukp = user_key_payload_locked(key);
4688cd3e6cSJaskaran Khurana if (!ukp) {
4788cd3e6cSJaskaran Khurana ret = -EKEYREVOKED;
4888cd3e6cSJaskaran Khurana goto end;
4988cd3e6cSJaskaran Khurana }
5088cd3e6cSJaskaran Khurana
5188cd3e6cSJaskaran Khurana sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL);
5288cd3e6cSJaskaran Khurana if (!sig_opts->sig) {
5388cd3e6cSJaskaran Khurana ret = -ENOMEM;
5488cd3e6cSJaskaran Khurana goto end;
5588cd3e6cSJaskaran Khurana }
5688cd3e6cSJaskaran Khurana sig_opts->sig_size = ukp->datalen;
5788cd3e6cSJaskaran Khurana
5888cd3e6cSJaskaran Khurana memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size);
5988cd3e6cSJaskaran Khurana
6088cd3e6cSJaskaran Khurana end:
6188cd3e6cSJaskaran Khurana up_read(&key->sem);
6288cd3e6cSJaskaran Khurana key_put(key);
6388cd3e6cSJaskaran Khurana
6488cd3e6cSJaskaran Khurana return ret;
6588cd3e6cSJaskaran Khurana }
6688cd3e6cSJaskaran Khurana
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)6788cd3e6cSJaskaran Khurana int verity_verify_sig_parse_opt_args(struct dm_arg_set *as,
6888cd3e6cSJaskaran Khurana struct dm_verity *v,
6988cd3e6cSJaskaran Khurana struct dm_verity_sig_opts *sig_opts,
7088cd3e6cSJaskaran Khurana unsigned int *argc,
7188cd3e6cSJaskaran Khurana const char *arg_name)
7288cd3e6cSJaskaran Khurana {
7388cd3e6cSJaskaran Khurana struct dm_target *ti = v->ti;
7488cd3e6cSJaskaran Khurana int ret = 0;
7588cd3e6cSJaskaran Khurana const char *sig_key = NULL;
7688cd3e6cSJaskaran Khurana
7788cd3e6cSJaskaran Khurana if (!*argc) {
7888cd3e6cSJaskaran Khurana ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified");
7988cd3e6cSJaskaran Khurana return -EINVAL;
8088cd3e6cSJaskaran Khurana }
8188cd3e6cSJaskaran Khurana
8288cd3e6cSJaskaran Khurana sig_key = dm_shift_arg(as);
8388cd3e6cSJaskaran Khurana (*argc)--;
8488cd3e6cSJaskaran Khurana
8588cd3e6cSJaskaran Khurana ret = verity_verify_get_sig_from_key(sig_key, sig_opts);
8688cd3e6cSJaskaran Khurana if (ret < 0)
8788cd3e6cSJaskaran Khurana ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified");
8888cd3e6cSJaskaran Khurana
8988cd3e6cSJaskaran Khurana v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL);
9088cd3e6cSJaskaran Khurana if (!v->signature_key_desc)
9188cd3e6cSJaskaran Khurana return -ENOMEM;
9288cd3e6cSJaskaran Khurana
9388cd3e6cSJaskaran Khurana return ret;
9488cd3e6cSJaskaran Khurana }
9588cd3e6cSJaskaran Khurana
9688cd3e6cSJaskaran Khurana /*
9788cd3e6cSJaskaran Khurana * verify_verify_roothash - Verify the root hash of the verity hash device
9888cd3e6cSJaskaran Khurana * using builtin trusted keys.
9988cd3e6cSJaskaran Khurana *
10088cd3e6cSJaskaran Khurana * @root_hash: For verity, the roothash/data to be verified.
10188cd3e6cSJaskaran Khurana * @root_hash_len: Size of the roothash/data to be verified.
10288cd3e6cSJaskaran Khurana * @sig_data: The trusted signature that verifies the roothash/data.
10388cd3e6cSJaskaran Khurana * @sig_len: Size of the signature.
10488cd3e6cSJaskaran Khurana *
10588cd3e6cSJaskaran Khurana */
verity_verify_root_hash(const void * root_hash,size_t root_hash_len,const void * sig_data,size_t sig_len)10688cd3e6cSJaskaran Khurana int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
10788cd3e6cSJaskaran Khurana const void *sig_data, size_t sig_len)
10888cd3e6cSJaskaran Khurana {
10988cd3e6cSJaskaran Khurana int ret;
11088cd3e6cSJaskaran Khurana
11188cd3e6cSJaskaran Khurana if (!root_hash || root_hash_len == 0)
11288cd3e6cSJaskaran Khurana return -EINVAL;
11388cd3e6cSJaskaran Khurana
11488cd3e6cSJaskaran Khurana if (!sig_data || sig_len == 0) {
11588cd3e6cSJaskaran Khurana if (DM_VERITY_IS_SIG_FORCE_ENABLED())
11688cd3e6cSJaskaran Khurana return -ENOKEY;
11788cd3e6cSJaskaran Khurana else
11888cd3e6cSJaskaran Khurana return 0;
11988cd3e6cSJaskaran Khurana }
12088cd3e6cSJaskaran Khurana
12188cd3e6cSJaskaran Khurana ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data,
1224da8f8c8SMickaël Salaün sig_len,
1234da8f8c8SMickaël Salaün #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING
1244da8f8c8SMickaël Salaün VERIFY_USE_SECONDARY_KEYRING,
1254da8f8c8SMickaël Salaün #else
1264da8f8c8SMickaël Salaün NULL,
1274da8f8c8SMickaël Salaün #endif
1284da8f8c8SMickaël Salaün VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL);
12988cd3e6cSJaskaran Khurana
13088cd3e6cSJaskaran Khurana return ret;
13188cd3e6cSJaskaran Khurana }
13288cd3e6cSJaskaran Khurana
verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts * sig_opts)13388cd3e6cSJaskaran Khurana void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
13488cd3e6cSJaskaran Khurana {
13588cd3e6cSJaskaran Khurana kfree(sig_opts->sig);
13688cd3e6cSJaskaran Khurana sig_opts->sig = NULL;
13788cd3e6cSJaskaran Khurana sig_opts->sig_size = 0;
13888cd3e6cSJaskaran Khurana }
139