1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2025 IBM Corporation, Srish Srinivasan <ssrish@linux.ibm.com> 4 */ 5 6 #include <keys/trusted_pkwm.h> 7 #include <keys/trusted-type.h> 8 #include <linux/build_bug.h> 9 #include <linux/key-type.h> 10 #include <linux/parser.h> 11 #include <asm/plpks.h> 12 13 enum { 14 Opt_err, 15 Opt_wrap_flags, 16 }; 17 18 static const match_table_t key_tokens = { 19 {Opt_wrap_flags, "wrap_flags=%s"}, 20 {Opt_err, NULL} 21 }; 22 23 static int getoptions(char *datablob, struct trusted_key_options *opt) 24 { 25 substring_t args[MAX_OPT_ARGS]; 26 char *p = datablob; 27 int token; 28 int res; 29 u16 wrap_flags; 30 unsigned long token_mask = 0; 31 struct trusted_pkwm_options *pkwm; 32 33 if (!datablob) 34 return 0; 35 36 pkwm = opt->private; 37 38 while ((p = strsep(&datablob, " \t"))) { 39 if (*p == '\0' || *p == ' ' || *p == '\t') 40 continue; 41 42 token = match_token(p, key_tokens, args); 43 if (test_and_set_bit(token, &token_mask)) 44 return -EINVAL; 45 46 switch (token) { 47 case Opt_wrap_flags: 48 res = kstrtou16(args[0].from, 16, &wrap_flags); 49 if (res < 0 || wrap_flags > 2) 50 return -EINVAL; 51 pkwm->wrap_flags = wrap_flags; 52 break; 53 default: 54 return -EINVAL; 55 } 56 } 57 return 0; 58 } 59 60 static struct trusted_key_options *trusted_options_alloc(void) 61 { 62 struct trusted_key_options *options; 63 struct trusted_pkwm_options *pkwm; 64 65 options = kzalloc_obj(*options); 66 67 if (options) { 68 pkwm = kzalloc_obj(*pkwm); 69 70 if (!pkwm) { 71 kfree_sensitive(options); 72 options = NULL; 73 } else { 74 options->private = pkwm; 75 } 76 } 77 78 return options; 79 } 80 81 static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob) 82 { 83 struct trusted_key_options *options = NULL; 84 struct trusted_pkwm_options *pkwm = NULL; 85 u8 *input_buf, *output_buf; 86 u32 output_len, input_len; 87 int rc; 88 89 options = trusted_options_alloc(); 90 91 if (!options) 92 return -ENOMEM; 93 94 rc = getoptions(datablob, options); 95 if (rc < 0) 96 goto out; 97 dump_options(options); 98 99 input_len = p->key_len; 100 input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL); 101 if (!input_buf) { 102 pr_err("Input buffer allocation failed. Returning -ENOMEM."); 103 rc = -ENOMEM; 104 goto out; 105 } 106 107 memcpy(input_buf, p->key, p->key_len); 108 109 pkwm = options->private; 110 111 rc = plpks_wrap_object(&input_buf, input_len, pkwm->wrap_flags, 112 &output_buf, &output_len); 113 if (!rc) { 114 memcpy(p->blob, output_buf, output_len); 115 p->blob_len = output_len; 116 dump_payload(p); 117 } else { 118 pr_err("Wrapping of payload key failed: %d\n", rc); 119 } 120 121 kfree(input_buf); 122 kfree(output_buf); 123 124 out: 125 kfree_sensitive(options->private); 126 kfree_sensitive(options); 127 return rc; 128 } 129 130 static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob) 131 { 132 u8 *input_buf, *output_buf; 133 u32 input_len, output_len; 134 int rc; 135 136 input_len = p->blob_len; 137 input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL); 138 if (!input_buf) { 139 pr_err("Input buffer allocation failed. Returning -ENOMEM."); 140 return -ENOMEM; 141 } 142 143 memcpy(input_buf, p->blob, p->blob_len); 144 145 rc = plpks_unwrap_object(&input_buf, input_len, &output_buf, 146 &output_len); 147 if (!rc) { 148 memcpy(p->key, output_buf, output_len); 149 p->key_len = output_len; 150 dump_payload(p); 151 } else { 152 pr_err("Unwrapping of payload failed: %d\n", rc); 153 } 154 155 kfree(input_buf); 156 kfree(output_buf); 157 158 return rc; 159 } 160 161 static int trusted_pkwm_init(void) 162 { 163 int ret; 164 165 if (!plpks_wrapping_is_supported()) { 166 pr_err("H_PKS_WRAP_OBJECT interface not supported\n"); 167 return -ENODEV; 168 } 169 170 ret = plpks_gen_wrapping_key(); 171 if (ret) { 172 pr_err("Failed to generate default wrapping key\n"); 173 return -EINVAL; 174 } 175 176 return register_key_type(&key_type_trusted); 177 } 178 179 static void trusted_pkwm_exit(void) 180 { 181 unregister_key_type(&key_type_trusted); 182 } 183 184 struct trusted_key_ops pkwm_trusted_key_ops = { 185 .migratable = 0, /* non-migratable */ 186 .init = trusted_pkwm_init, 187 .seal = trusted_pkwm_seal, 188 .unseal = trusted_pkwm_unseal, 189 .exit = trusted_pkwm_exit, 190 }; 191