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 <keys/user-type.h> 11 #include <linux/module.h> 12 #include "dm-verity.h" 13 #include "dm-verity-verify-sig.h" 14 15 #define DM_VERITY_VERIFY_ERR(s) DM_VERITY_ROOT_HASH_VERIFICATION " " s 16 17 static bool require_signatures; 18 module_param(require_signatures, bool, 0444); 19 MODULE_PARM_DESC(require_signatures, 20 "Verify the roothash of dm-verity hash tree"); 21 22 #define DM_VERITY_IS_SIG_FORCE_ENABLED() \ 23 (require_signatures != false) 24 25 bool verity_verify_is_sig_opt_arg(const char *arg_name) 26 { 27 return (!strcasecmp(arg_name, 28 DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY)); 29 } 30 31 static int verity_verify_get_sig_from_key(const char *key_desc, 32 struct dm_verity_sig_opts *sig_opts) 33 { 34 struct key *key; 35 const struct user_key_payload *ukp; 36 int ret = 0; 37 38 key = request_key(&key_type_user, 39 key_desc, NULL); 40 if (IS_ERR(key)) 41 return PTR_ERR(key); 42 43 down_read(&key->sem); 44 45 ukp = user_key_payload_locked(key); 46 if (!ukp) { 47 ret = -EKEYREVOKED; 48 goto end; 49 } 50 51 sig_opts->sig = kmalloc(ukp->datalen, GFP_KERNEL); 52 if (!sig_opts->sig) { 53 ret = -ENOMEM; 54 goto end; 55 } 56 sig_opts->sig_size = ukp->datalen; 57 58 memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size); 59 60 end: 61 up_read(&key->sem); 62 key_put(key); 63 64 return ret; 65 } 66 67 int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, 68 struct dm_verity *v, 69 struct dm_verity_sig_opts *sig_opts, 70 unsigned int *argc, 71 const char *arg_name) 72 { 73 struct dm_target *ti = v->ti; 74 int ret; 75 const char *sig_key = NULL; 76 77 if (v->signature_key_desc) { 78 ti->error = DM_VERITY_VERIFY_ERR("root_hash_sig_key_desc already specified"); 79 return -EINVAL; 80 } 81 82 if (!*argc) { 83 ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified"); 84 return -EINVAL; 85 } 86 87 sig_key = dm_shift_arg(as); 88 (*argc)--; 89 90 ret = verity_verify_get_sig_from_key(sig_key, sig_opts); 91 if (ret < 0) { 92 ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified"); 93 return ret; 94 } 95 96 v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL); 97 if (!v->signature_key_desc) { 98 ti->error = DM_VERITY_VERIFY_ERR("Could not allocate memory for signature key"); 99 return -ENOMEM; 100 } 101 102 return 0; 103 } 104 105 /* 106 * verify_verify_roothash - Verify the root hash of the verity hash device 107 * using builtin trusted keys. 108 * 109 * @root_hash: For verity, the roothash/data to be verified. 110 * @root_hash_len: Size of the roothash/data to be verified. 111 * @sig_data: The trusted signature that verifies the roothash/data. 112 * @sig_len: Size of the signature. 113 * 114 */ 115 int verity_verify_root_hash(const void *root_hash, size_t root_hash_len, 116 const void *sig_data, size_t sig_len) 117 { 118 int ret; 119 120 if (!root_hash || root_hash_len == 0) 121 return -EINVAL; 122 123 if (!sig_data || sig_len == 0) { 124 if (DM_VERITY_IS_SIG_FORCE_ENABLED()) 125 return -ENOKEY; 126 else 127 return 0; 128 } 129 130 ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, 131 sig_len, 132 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING 133 VERIFY_USE_SECONDARY_KEYRING, 134 #else 135 NULL, 136 #endif 137 VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); 138 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING 139 if (ret == -ENOKEY || ret == -EKEYREJECTED) 140 ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, 141 sig_len, 142 VERIFY_USE_PLATFORM_KEYRING, 143 VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); 144 #endif 145 146 return ret; 147 } 148 149 void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts) 150 { 151 kfree(sig_opts->sig); 152 sig_opts->sig = NULL; 153 sig_opts->sig_size = 0; 154 } 155