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 = 0; 75 const char *sig_key = NULL; 76 77 if (!*argc) { 78 ti->error = DM_VERITY_VERIFY_ERR("Signature key not specified"); 79 return -EINVAL; 80 } 81 82 sig_key = dm_shift_arg(as); 83 (*argc)--; 84 85 ret = verity_verify_get_sig_from_key(sig_key, sig_opts); 86 if (ret < 0) 87 ti->error = DM_VERITY_VERIFY_ERR("Invalid key specified"); 88 89 v->signature_key_desc = kstrdup(sig_key, GFP_KERNEL); 90 if (!v->signature_key_desc) 91 return -ENOMEM; 92 93 return ret; 94 } 95 96 /* 97 * verify_verify_roothash - Verify the root hash of the verity hash device 98 * using builtin trusted keys. 99 * 100 * @root_hash: For verity, the roothash/data to be verified. 101 * @root_hash_len: Size of the roothash/data to be verified. 102 * @sig_data: The trusted signature that verifies the roothash/data. 103 * @sig_len: Size of the signature. 104 * 105 */ 106 int verity_verify_root_hash(const void *root_hash, size_t root_hash_len, 107 const void *sig_data, size_t sig_len) 108 { 109 int ret; 110 111 if (!root_hash || root_hash_len == 0) 112 return -EINVAL; 113 114 if (!sig_data || sig_len == 0) { 115 if (DM_VERITY_IS_SIG_FORCE_ENABLED()) 116 return -ENOKEY; 117 else 118 return 0; 119 } 120 121 ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, 122 sig_len, 123 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING 124 VERIFY_USE_SECONDARY_KEYRING, 125 #else 126 NULL, 127 #endif 128 VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); 129 #ifdef CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING 130 if (ret == -ENOKEY || ret == -EKEYREJECTED) 131 ret = verify_pkcs7_signature(root_hash, root_hash_len, sig_data, 132 sig_len, 133 VERIFY_USE_PLATFORM_KEYRING, 134 VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); 135 #endif 136 137 return ret; 138 } 139 140 void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts) 141 { 142 kfree(sig_opts->sig); 143 sig_opts->sig = NULL; 144 sig_opts->sig_size = 0; 145 } 146