xref: /linux/drivers/md/dm-verity-verify-sig.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2019 Microsoft Corporation.
4  *
5  * Author:  Jaskaran Singh Khurana <jaskarankhurana@linux.microsoft.com>
6  *
7  */
8 #include <linux/device-mapper.h>
9 #include <linux/verification.h>
10 #include <linux/key.h>
11 #include <keys/user-type.h>
12 #include <linux/module.h>
13 #include "dm-verity.h"
14 #include "dm-verity-verify-sig.h"
15 
16 #define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s
17 
18 static struct key *dm_verity_keyring;
19 
20 static bool dm_verity_keyring_unsealed __ro_after_init;
21 module_param_named(keyring_unsealed, dm_verity_keyring_unsealed, bool, 0444);
22 MODULE_PARM_DESC(keyring_unsealed, "Leave the dm-verity keyring unsealed");
23 
24 static bool require_signatures;
25 module_param(require_signatures, bool, 0444);
26 MODULE_PARM_DESC(require_signatures,
27 		"Verify the roothash of dm-verity hash tree");
28 
29 #define DM_VERITY_IS_SIG_FORCE_ENABLED() \
30 	(require_signatures != false)
31 
32 bool verity_verify_is_sig_opt_arg(const char *arg_name)
33 {
34 	return (!strcasecmp(arg_name,
35 			    DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY));
36 }
37 
38 static int verity_verify_get_sig_from_key(const char *key_desc,
39 					struct dm_verity_sig_opts *sig_opts)
40 {
41 	struct key *key;
42 	const struct user_key_payload *ukp;
43 	int ret = 0;
44 
45 	key = request_key(&key_type_user,
46 			key_desc, NULL);
47 	if (IS_ERR(key))
48 		return PTR_ERR(key);
49 
50 	down_read(&key->sem);
51 
52 	ukp = user_key_payload_locked(key);
53 	if (!ukp) {
54 		ret = -EKEYREVOKED;
55 		goto end;
56 	}
57 
58 	sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL);
59 	if (!sig_opts->sig) {
60 		ret = -ENOMEM;
61 		goto end;
62 	}
63 	sig_opts->sig_size = ukp->datalen;
64 
65 	memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size);
66 
67 end:
68 	up_read(&key->sem);
69 	key_put(key);
70 
71 	return ret;
72 }
73 
74 int verity_verify_sig_parse_opt_args(struct dm_arg_set *as,
75 				     struct dm_verity *v,
76 				     struct dm_verity_sig_opts *sig_opts,
77 				     unsigned int *argc,
78 				     const char *arg_name)
79 {
80 	struct dm_target *ti = v->ti;
81 	int ret;
82 	const char *sig_key = NULL;
83 
84 	if (v->signature_key_desc) {
85 		ti->error = DM_VERITY_VERIFY_ERR("root_hash_sig_key_desc already specified");
86 		return -EINVAL;
87 	}
88 
89 	if (!*argc) {
90 		ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified");
91 		return -EINVAL;
92 	}
93 
94 	sig_key = dm_shift_arg(as);
95 	(*argc)--;
96 
97 	ret = verity_verify_get_sig_from_key(sig_key, sig_opts);
98 	if (ret < 0) {
99 		ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified");
100 		return ret;
101 	}
102 
103 	v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL);
104 	if (!v->signature_key_desc) {
105 		ti->error = DM_VERITY_VERIFY_ERR("Could not allocate memory for signature key");
106 		return -ENOMEM;
107 	}
108 
109 	return 0;
110 }
111 
112 /*
113  * verify_verify_roothash - Verify the root hash of the verity hash device
114  *			     using builtin trusted keys.
115  *
116  * @root_hash: For verity, the roothash/data to be verified.
117  * @root_hash_len: Size of the roothash/data to be verified.
118  * @sig_data: The trusted signature that verifies the roothash/data.
119  * @sig_len: Size of the signature.
120  *
121  */
122 int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
123 			    const void *sig_data, size_t sig_len)
124 {
125 	int ret;
126 
127 	if (!root_hash || root_hash_len == 0)
128 		return -EINVAL;
129 
130 	if (!sig_data  || sig_len == 0) {
131 		if (DM_VERITY_IS_SIG_FORCE_ENABLED())
132 			return -ENOKEY;
133 		else
134 			return 0;
135 	}
136 
137 	ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data,
138 				sig_len,
139 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING
140 				VERIFY_USE_SECONDARY_KEYRING,
141 #else
142 				NULL,
143 #endif
144 				VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL);
145 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING
146 	if (ret == -ENOKEY || ret == -EKEYREJECTED)
147 		ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data,
148 					sig_len,
149 					VERIFY_USE_PLATFORM_KEYRING,
150 					VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL);
151 #endif
152 
153 	if (ret != -ENOKEY && ret != -EKEYREJECTED)
154 		return ret;
155 
156 	if (dm_verity_keyring->keys.nr_leaves_on_tree &&
157 	    dm_verity_keyring->restrict_link)
158 		ret = verify_pkcs7_signature(root_hash, root_hash_len,
159 					     sig_data, sig_len,
160 					     dm_verity_keyring,
161 					     VERIFYING_UNSPECIFIED_SIGNATURE,
162 					     NULL, NULL);
163 
164 	return ret;
165 }
166 
167 void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
168 {
169 	kfree(sig_opts->sig);
170 	sig_opts->sig = NULL;
171 	sig_opts->sig_size = 0;
172 }
173 
174 int __init dm_verity_verify_sig_init(void)
175 {
176 	dm_verity_keyring = keyring_alloc(".dm-verity",
177 					  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
178 					  current_cred(),
179 					  KEY_POS_SEARCH |
180 					  KEY_USR_VIEW | KEY_USR_READ |
181 					  KEY_USR_WRITE | KEY_USR_SEARCH |
182 					  KEY_USR_SETATTR,
183 					  KEY_ALLOC_NOT_IN_QUOTA,
184 					  NULL, NULL);
185 	if (IS_ERR(dm_verity_keyring))
186 		panic("dm-verity can't allocate keyring\n");
187 
188 	if (!dm_verity_keyring_unsealed &&
189 	    keyring_restrict(make_key_ref(dm_verity_keyring, true), NULL, NULL))
190 		panic("dm-verity can't seal keyring\n");
191 
192 	return 0;
193 }
194 
195 void dm_verity_verify_sig_exit(void)
196 {
197 	key_revoke(dm_verity_keyring);
198 	key_put(dm_verity_keyring);
199 }
200