1 /* Public-key operation keyctls 2 * 3 * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12 #include <linux/slab.h> 13 #include <linux/err.h> 14 #include <linux/key.h> 15 #include <linux/keyctl.h> 16 #include <linux/parser.h> 17 #include <linux/uaccess.h> 18 #include <keys/user-type.h> 19 #include "internal.h" 20 21 static void keyctl_pkey_params_free(struct kernel_pkey_params *params) 22 { 23 kfree(params->info); 24 key_put(params->key); 25 } 26 27 enum { 28 Opt_err, 29 Opt_enc, /* "enc=<encoding>" eg. "enc=oaep" */ 30 Opt_hash, /* "hash=<digest-name>" eg. "hash=sha1" */ 31 }; 32 33 static const match_table_t param_keys = { 34 { Opt_enc, "enc=%s" }, 35 { Opt_hash, "hash=%s" }, 36 { Opt_err, NULL } 37 }; 38 39 /* 40 * Parse the information string which consists of key=val pairs. 41 */ 42 static int keyctl_pkey_params_parse(struct kernel_pkey_params *params) 43 { 44 unsigned long token_mask = 0; 45 substring_t args[MAX_OPT_ARGS]; 46 char *c = params->info, *p, *q; 47 int token; 48 49 while ((p = strsep(&c, " \t"))) { 50 if (*p == '\0' || *p == ' ' || *p == '\t') 51 continue; 52 token = match_token(p, param_keys, args); 53 if (token == Opt_err) 54 return -EINVAL; 55 if (__test_and_set_bit(token, &token_mask)) 56 return -EINVAL; 57 q = args[0].from; 58 if (!q[0]) 59 return -EINVAL; 60 61 switch (token) { 62 case Opt_enc: 63 params->encoding = q; 64 break; 65 66 case Opt_hash: 67 params->hash_algo = q; 68 break; 69 70 default: 71 return -EINVAL; 72 } 73 } 74 75 return 0; 76 } 77 78 /* 79 * Interpret parameters. Callers must always call the free function 80 * on params, even if an error is returned. 81 */ 82 static int keyctl_pkey_params_get(key_serial_t id, 83 const char __user *_info, 84 struct kernel_pkey_params *params) 85 { 86 key_ref_t key_ref; 87 void *p; 88 int ret; 89 90 memset(params, 0, sizeof(*params)); 91 params->encoding = "raw"; 92 93 p = strndup_user(_info, PAGE_SIZE); 94 if (IS_ERR(p)) 95 return PTR_ERR(p); 96 params->info = p; 97 98 ret = keyctl_pkey_params_parse(params); 99 if (ret < 0) 100 return ret; 101 102 key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); 103 if (IS_ERR(key_ref)) 104 return PTR_ERR(key_ref); 105 params->key = key_ref_to_ptr(key_ref); 106 107 if (!params->key->type->asym_query) 108 return -EOPNOTSUPP; 109 110 return 0; 111 } 112 113 /* 114 * Get parameters from userspace. Callers must always call the free function 115 * on params, even if an error is returned. 116 */ 117 static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_params, 118 const char __user *_info, 119 int op, 120 struct kernel_pkey_params *params) 121 { 122 struct keyctl_pkey_params uparams; 123 struct kernel_pkey_query info; 124 int ret; 125 126 memset(params, 0, sizeof(*params)); 127 params->encoding = "raw"; 128 129 if (copy_from_user(&uparams, _params, sizeof(uparams)) != 0) 130 return -EFAULT; 131 132 ret = keyctl_pkey_params_get(uparams.key_id, _info, params); 133 if (ret < 0) 134 return ret; 135 136 ret = params->key->type->asym_query(params, &info); 137 if (ret < 0) 138 return ret; 139 140 switch (op) { 141 case KEYCTL_PKEY_ENCRYPT: 142 case KEYCTL_PKEY_DECRYPT: 143 if (uparams.in_len > info.max_enc_size || 144 uparams.out_len > info.max_dec_size) 145 return -EINVAL; 146 break; 147 case KEYCTL_PKEY_SIGN: 148 case KEYCTL_PKEY_VERIFY: 149 if (uparams.in_len > info.max_sig_size || 150 uparams.out_len > info.max_data_size) 151 return -EINVAL; 152 break; 153 default: 154 BUG(); 155 } 156 157 params->in_len = uparams.in_len; 158 params->out_len = uparams.out_len; 159 return 0; 160 } 161 162 /* 163 * Query information about an asymmetric key. 164 */ 165 long keyctl_pkey_query(key_serial_t id, 166 const char __user *_info, 167 struct keyctl_pkey_query __user *_res) 168 { 169 struct kernel_pkey_params params; 170 struct kernel_pkey_query res; 171 long ret; 172 173 memset(¶ms, 0, sizeof(params)); 174 175 ret = keyctl_pkey_params_get(id, _info, ¶ms); 176 if (ret < 0) 177 goto error; 178 179 ret = params.key->type->asym_query(¶ms, &res); 180 if (ret < 0) 181 goto error; 182 183 ret = -EFAULT; 184 if (copy_to_user(_res, &res, sizeof(res)) == 0 && 185 clear_user(_res->__spare, sizeof(_res->__spare)) == 0) 186 ret = 0; 187 188 error: 189 keyctl_pkey_params_free(¶ms); 190 return ret; 191 } 192 193 /* 194 * Encrypt/decrypt/sign 195 * 196 * Encrypt data, decrypt data or sign data using a public key. 197 * 198 * _info is a string of supplementary information in key=val format. For 199 * instance, it might contain: 200 * 201 * "enc=pkcs1 hash=sha256" 202 * 203 * where enc= specifies the encoding and hash= selects the OID to go in that 204 * particular encoding if required. If enc= isn't supplied, it's assumed that 205 * the caller is supplying raw values. 206 * 207 * If successful, the amount of data written into the output buffer is 208 * returned. 209 */ 210 long keyctl_pkey_e_d_s(int op, 211 const struct keyctl_pkey_params __user *_params, 212 const char __user *_info, 213 const void __user *_in, 214 void __user *_out) 215 { 216 struct kernel_pkey_params params; 217 void *in, *out; 218 long ret; 219 220 ret = keyctl_pkey_params_get_2(_params, _info, op, ¶ms); 221 if (ret < 0) 222 goto error_params; 223 224 ret = -EOPNOTSUPP; 225 if (!params.key->type->asym_eds_op) 226 goto error_params; 227 228 switch (op) { 229 case KEYCTL_PKEY_ENCRYPT: 230 params.op = kernel_pkey_encrypt; 231 break; 232 case KEYCTL_PKEY_DECRYPT: 233 params.op = kernel_pkey_decrypt; 234 break; 235 case KEYCTL_PKEY_SIGN: 236 params.op = kernel_pkey_sign; 237 break; 238 default: 239 BUG(); 240 } 241 242 in = memdup_user(_in, params.in_len); 243 if (IS_ERR(in)) { 244 ret = PTR_ERR(in); 245 goto error_params; 246 } 247 248 ret = -ENOMEM; 249 out = kmalloc(params.out_len, GFP_KERNEL); 250 if (!out) 251 goto error_in; 252 253 ret = params.key->type->asym_eds_op(¶ms, in, out); 254 if (ret < 0) 255 goto error_out; 256 257 if (copy_to_user(_out, out, ret) != 0) 258 ret = -EFAULT; 259 260 error_out: 261 kfree(out); 262 error_in: 263 kfree(in); 264 error_params: 265 keyctl_pkey_params_free(¶ms); 266 return ret; 267 } 268 269 /* 270 * Verify a signature. 271 * 272 * Verify a public key signature using the given key, or if not given, search 273 * for a matching key. 274 * 275 * _info is a string of supplementary information in key=val format. For 276 * instance, it might contain: 277 * 278 * "enc=pkcs1 hash=sha256" 279 * 280 * where enc= specifies the signature blob encoding and hash= selects the OID 281 * to go in that particular encoding. If enc= isn't supplied, it's assumed 282 * that the caller is supplying raw values. 283 * 284 * If successful, 0 is returned. 285 */ 286 long keyctl_pkey_verify(const struct keyctl_pkey_params __user *_params, 287 const char __user *_info, 288 const void __user *_in, 289 const void __user *_in2) 290 { 291 struct kernel_pkey_params params; 292 void *in, *in2; 293 long ret; 294 295 ret = keyctl_pkey_params_get_2(_params, _info, KEYCTL_PKEY_VERIFY, 296 ¶ms); 297 if (ret < 0) 298 goto error_params; 299 300 ret = -EOPNOTSUPP; 301 if (!params.key->type->asym_verify_signature) 302 goto error_params; 303 304 in = memdup_user(_in, params.in_len); 305 if (IS_ERR(in)) { 306 ret = PTR_ERR(in); 307 goto error_params; 308 } 309 310 in2 = memdup_user(_in2, params.in2_len); 311 if (IS_ERR(in2)) { 312 ret = PTR_ERR(in2); 313 goto error_in; 314 } 315 316 params.op = kernel_pkey_verify; 317 ret = params.key->type->asym_verify_signature(¶ms, in, in2); 318 319 kfree(in2); 320 error_in: 321 kfree(in); 322 error_params: 323 keyctl_pkey_params_free(¶ms); 324 return ret; 325 } 326