1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "internal_crypt_lib.h" 25 #include "nvspdm_cryptlib_extensions.h" 26 27 #ifdef USE_LKCA 28 #define BUFFER_SIZE (2 * 1024 * 1024) 29 #define AUTH_TAG_SIZE 16 30 struct lkca_aead_ctx 31 { 32 struct crypto_aead *aead; 33 struct aead_request *req; 34 char *a_data_buffer; 35 char *in_buffer; 36 char *out_buffer; 37 char tag[AUTH_TAG_SIZE]; 38 }; 39 #endif 40 41 int libspdm_aead_prealloc(void **context, char const *alg) 42 { 43 #ifndef USE_LKCA 44 return -ENODEV; 45 #else 46 struct lkca_aead_ctx *ctx; 47 48 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 49 if (ctx == NULL) { 50 return -ENOMEM; 51 } 52 53 memset(ctx, 0, sizeof(*ctx)); 54 55 ctx->aead = crypto_alloc_aead(alg, CRYPTO_ALG_TYPE_AEAD, 0); 56 if (IS_ERR(ctx->aead)) { 57 pr_notice("could not allocate AEAD algorithm\n"); 58 kfree(ctx); 59 return -ENODEV; 60 } 61 62 ctx->req = aead_request_alloc(ctx->aead, GFP_KERNEL); 63 if (ctx->req == NULL) { 64 pr_info("could not allocate skcipher request\n"); 65 crypto_free_aead(ctx->aead); 66 kfree(ctx); 67 return -ENOMEM; 68 } 69 70 ctx->a_data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); 71 if (ctx->a_data_buffer == NULL) { 72 aead_request_free(ctx->req); 73 crypto_free_aead(ctx->aead); 74 kfree(ctx); 75 return -ENOMEM; 76 } 77 78 ctx->in_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); 79 if (ctx->in_buffer == NULL) { 80 kfree(ctx->a_data_buffer); 81 aead_request_free(ctx->req); 82 crypto_free_aead(ctx->aead); 83 kfree(ctx); 84 return -ENOMEM; 85 } 86 87 ctx->out_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); 88 if (ctx->out_buffer == NULL) { 89 kfree(ctx->a_data_buffer); 90 kfree(ctx->in_buffer); 91 aead_request_free(ctx->req); 92 crypto_free_aead(ctx->aead); 93 kfree(ctx); 94 return -ENOMEM; 95 } 96 97 *context = ctx; 98 return 0; 99 #endif 100 } 101 102 void libspdm_aead_free(void *context) 103 { 104 #ifdef USE_LKCA 105 struct lkca_aead_ctx *ctx = context; 106 crypto_free_aead(ctx->aead); 107 aead_request_free(ctx->req); 108 kfree(ctx->a_data_buffer); 109 kfree(ctx->in_buffer); 110 kfree(ctx->out_buffer); 111 kfree(ctx); 112 #endif 113 } 114 115 #define SG_AEAD_AAD 0 116 #define SG_AEAD_TEXT 1 117 #define SG_AEAD_SIG 2 118 // Number of fields in AEAD scatterlist 119 #define SG_AEAD_LEN 3 120 121 #ifdef USE_LKCA 122 // This function doesn't do any allocs, it uses temp buffers instead 123 static int lkca_aead_internal(struct crypto_aead *aead, 124 struct aead_request *req, 125 const uint8_t *key, size_t key_size, 126 const uint8_t *iv, size_t iv_size, 127 struct scatterlist sg_in[], 128 struct scatterlist sg_out[], 129 size_t a_data_size, 130 size_t data_in_size, 131 size_t *data_out_size, 132 size_t tag_size, 133 bool enc) 134 { 135 DECLARE_CRYPTO_WAIT(wait); 136 int rc = 0; 137 138 if (crypto_aead_setkey(aead, key, key_size)) { 139 pr_info("key could not be set\n"); 140 return -EINVAL; 141 } 142 143 if (crypto_aead_ivsize(aead) != iv_size) { 144 pr_info("iv could not be set\n"); 145 return -EINVAL; 146 } 147 148 aead_request_set_ad(req, a_data_size); 149 150 aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | 151 CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait); 152 153 if (enc) { 154 aead_request_set_crypt(req, sg_in, sg_out, data_in_size, (u8 *) iv); 155 rc = crypto_wait_req(crypto_aead_encrypt(req), &wait); 156 } else { 157 aead_request_set_crypt(req, sg_in, sg_out, data_in_size + tag_size, (u8 *) iv); 158 rc = crypto_wait_req(crypto_aead_decrypt(req), &wait); 159 } 160 161 if (rc != 0) { 162 pr_info("Encryption FAILED\n"); 163 } 164 165 *data_out_size = data_in_size; 166 167 return rc; 168 } 169 #endif 170 171 int libspdm_aead_prealloced(void *context, 172 const uint8_t *key, size_t key_size, 173 const uint8_t *iv, size_t iv_size, 174 const uint8_t *a_data, size_t a_data_size, 175 const uint8_t *data_in, size_t data_in_size, 176 uint8_t *tag, size_t tag_size, 177 uint8_t *data_out, size_t *data_out_size, 178 bool enc) 179 { 180 #ifndef USE_LKCA 181 return -ENODEV; 182 #else 183 int rc = 0; 184 struct scatterlist sg_in[SG_AEAD_LEN]; 185 struct scatterlist sg_out[SG_AEAD_LEN]; 186 struct lkca_aead_ctx *ctx = context; 187 188 189 sg_init_table(sg_in, SG_AEAD_LEN); 190 sg_init_table(sg_out, SG_AEAD_LEN); 191 192 if (!virt_addr_valid(a_data)) { 193 if (a_data_size > BUFFER_SIZE) { 194 return -ENOMEM; 195 } 196 sg_set_buf(&sg_in[SG_AEAD_AAD], ctx->a_data_buffer, a_data_size); 197 sg_set_buf(&sg_out[SG_AEAD_AAD], ctx->a_data_buffer, a_data_size); 198 199 memcpy(ctx->a_data_buffer, a_data, a_data_size); 200 } else { 201 sg_set_buf(&sg_in[SG_AEAD_AAD], a_data, a_data_size); 202 sg_set_buf(&sg_out[SG_AEAD_AAD], a_data, a_data_size); 203 } 204 205 if (!virt_addr_valid(data_in)) { 206 if (data_in_size > BUFFER_SIZE) { 207 return -ENOMEM; 208 } 209 sg_set_buf(&sg_in[SG_AEAD_TEXT], ctx->in_buffer, data_in_size); 210 memcpy(ctx->in_buffer, data_in, data_in_size); 211 } else { 212 sg_set_buf(&sg_in[SG_AEAD_TEXT], data_in, data_in_size); 213 } 214 215 if (!virt_addr_valid(data_out)) { 216 if (data_in_size > BUFFER_SIZE) { 217 return -ENOMEM; 218 } 219 sg_set_buf(&sg_out[SG_AEAD_TEXT], ctx->out_buffer, data_in_size); 220 } else { 221 sg_set_buf(&sg_out[SG_AEAD_TEXT], data_out, data_in_size); 222 } 223 224 // Tag is small enough that memcpy is cheaper than checking if page is virtual 225 if(tag_size > AUTH_TAG_SIZE) { 226 return -ENOMEM; 227 } 228 sg_set_buf(&sg_in[SG_AEAD_SIG], ctx->tag, tag_size); 229 sg_set_buf(&sg_out[SG_AEAD_SIG], ctx->tag, tag_size); 230 231 if(!enc) 232 memcpy(ctx->tag, tag, tag_size); 233 234 rc = lkca_aead_internal(ctx->aead, ctx->req, key, key_size, iv, iv_size, 235 sg_in, sg_out, a_data_size, data_in_size, 236 data_out_size, tag_size, enc); 237 238 if (enc) { 239 memcpy(tag, ctx->tag, tag_size); 240 } 241 242 if (!virt_addr_valid(data_out)) { 243 memcpy(data_out, ctx->out_buffer, data_in_size); 244 } 245 246 return rc; 247 #endif 248 } 249 250 int libspdm_aead(const uint8_t *key, size_t key_size, 251 const uint8_t *iv, size_t iv_size, 252 const uint8_t *a_data, size_t a_data_size, 253 const uint8_t *data_in, size_t data_in_size, 254 const uint8_t *tag, size_t tag_size, 255 uint8_t *data_out, size_t *data_out_size, 256 bool enc, char const *alg) 257 { 258 #ifndef USE_LKCA 259 return -ENODEV; 260 #else 261 struct crypto_aead *aead = NULL; 262 struct aead_request *req = NULL; 263 struct scatterlist sg_in[SG_AEAD_LEN]; 264 struct scatterlist sg_out[SG_AEAD_LEN]; 265 uint8_t *a_data_shadow = NULL; 266 uint8_t *data_in_shadow = NULL; 267 uint8_t *data_out_shadow = NULL; 268 uint8_t *tag_shadow = NULL; 269 int rc = 0; 270 271 aead = crypto_alloc_aead(alg, CRYPTO_ALG_TYPE_AEAD, 0); 272 if (IS_ERR(aead)) { 273 pr_notice("could not allocate AEAD algorithm\n"); 274 return -ENODEV; 275 } 276 277 req = aead_request_alloc(aead, GFP_KERNEL); 278 if (req == NULL) { 279 pr_info("could not allocate skcipher request\n"); 280 rc = -ENOMEM; 281 goto out; 282 } 283 284 sg_init_table(sg_in, SG_AEAD_LEN); 285 sg_init_table(sg_out, SG_AEAD_LEN); 286 287 if (!virt_addr_valid(a_data)) { 288 a_data_shadow = kmalloc(a_data_size, GFP_KERNEL); 289 if (a_data_shadow == NULL) { 290 rc = -ENOMEM; 291 goto out; 292 } 293 294 sg_set_buf(&sg_in[SG_AEAD_AAD], a_data_shadow, a_data_size); 295 sg_set_buf(&sg_out[SG_AEAD_AAD], a_data_shadow, a_data_size); 296 297 memcpy(a_data_shadow, a_data, a_data_size); 298 } else { 299 sg_set_buf(&sg_in[SG_AEAD_AAD], a_data, a_data_size); 300 sg_set_buf(&sg_out[SG_AEAD_AAD], a_data, a_data_size); 301 } 302 303 if (!virt_addr_valid(data_in)) { 304 data_in_shadow = kmalloc(data_in_size, GFP_KERNEL); 305 if (data_in_shadow == NULL) { 306 rc = -ENOMEM; 307 goto out; 308 } 309 310 sg_set_buf(&sg_in[SG_AEAD_TEXT], data_in_shadow, data_in_size); 311 312 memcpy(data_in_shadow, data_in, data_in_size); 313 } else { 314 sg_set_buf(&sg_in[SG_AEAD_TEXT], data_in, data_in_size); 315 } 316 317 if (!virt_addr_valid(data_out)) { 318 data_out_shadow = kmalloc(data_in_size, GFP_KERNEL); 319 if (data_out_shadow == NULL) { 320 rc = -ENOMEM; 321 goto out; 322 } 323 324 sg_set_buf(&sg_out[SG_AEAD_TEXT], data_out_shadow, data_in_size); 325 } else { 326 sg_set_buf(&sg_out[SG_AEAD_TEXT], data_out, data_in_size); 327 } 328 329 if (!virt_addr_valid(tag)) { 330 tag_shadow = kmalloc(tag_size, GFP_KERNEL); 331 if (tag_shadow == NULL) { 332 rc = -ENOMEM; 333 goto out; 334 } 335 336 sg_set_buf(&sg_in[SG_AEAD_SIG], tag_shadow, tag_size); 337 sg_set_buf(&sg_out[SG_AEAD_SIG], tag_shadow, tag_size); 338 339 if(!enc) 340 memcpy(tag_shadow, tag, tag_size); 341 } else { 342 sg_set_buf(&sg_in[SG_AEAD_SIG], tag, tag_size); 343 sg_set_buf(&sg_out[SG_AEAD_SIG], tag, tag_size); 344 } 345 346 rc = lkca_aead_internal(aead, req, key, key_size, iv, iv_size, 347 sg_in, sg_out, a_data_size, data_in_size, 348 data_out_size, tag_size, enc); 349 350 if (enc && (tag_shadow != NULL)) 351 memcpy((uint8_t *) tag, tag_shadow, tag_size); 352 353 if (data_out_shadow != NULL) 354 memcpy(data_out, data_out_shadow, data_in_size); 355 356 out: 357 if (a_data_shadow != NULL) 358 kfree(a_data_shadow); 359 if (data_in_shadow != NULL) 360 kfree(data_in_shadow); 361 if (data_out != NULL) 362 kfree(data_out_shadow); 363 if (tag != NULL) 364 kfree(tag_shadow); 365 if (aead != NULL) 366 crypto_free_aead(aead); 367 if (req != NULL) 368 aead_request_free(req); 369 return rc; 370 #endif 371 } 372 373 // Wrapper to make look like libspdm 374 bool libspdm_aead_gcm_prealloc(void **context) 375 { 376 return libspdm_aead_prealloc(context, "gcm(aes)") == 0; 377 } 378 379 bool libspdm_aead_aes_gcm_encrypt_prealloc(void *context, 380 const uint8_t *key, size_t key_size, 381 const uint8_t *iv, size_t iv_size, 382 const uint8_t *a_data, size_t a_data_size, 383 const uint8_t *data_in, size_t data_in_size, 384 uint8_t *tag_out, size_t tag_size, 385 uint8_t *data_out, size_t *data_out_size) 386 { 387 int32_t ret; 388 389 if (data_in_size > INT_MAX) { 390 return false; 391 } 392 if (a_data_size > INT_MAX) { 393 return false; 394 } 395 if (iv_size != 12) { 396 return false; 397 } 398 switch (key_size) { 399 case 16: 400 case 24: 401 case 32: 402 break; 403 default: 404 return false; 405 } 406 if ((tag_size < 12) || (tag_size > 16)) { 407 return false; 408 } 409 if (data_out_size != NULL) { 410 if ((*data_out_size > INT_MAX) || 411 (*data_out_size < data_in_size)) { 412 return false; 413 } 414 } 415 416 ret = libspdm_aead_prealloced(context, key, key_size, iv, iv_size, 417 a_data, a_data_size, data_in, data_in_size, 418 tag_out, tag_size, data_out, data_out_size, true); 419 420 *data_out_size = data_in_size; 421 422 return ret == 0; 423 } 424 425 bool libspdm_aead_aes_gcm_decrypt_prealloc(void *context, 426 const uint8_t *key, size_t key_size, 427 const uint8_t *iv, size_t iv_size, 428 const uint8_t *a_data, size_t a_data_size, 429 const uint8_t *data_in, size_t data_in_size, 430 const uint8_t *tag, size_t tag_size, 431 uint8_t *data_out, size_t *data_out_size) 432 { 433 int ret; 434 if (data_in_size > INT_MAX) { 435 return false; 436 } 437 if (a_data_size > INT_MAX) { 438 return false; 439 } 440 if (iv_size != 12) { 441 return false; 442 } 443 switch (key_size) { 444 case 16: 445 case 24: 446 case 32: 447 break; 448 default: 449 return false; 450 } 451 if ((tag_size < 12) || (tag_size > 16)) { 452 return false; 453 } 454 if (data_out_size != NULL) { 455 if ((*data_out_size > INT_MAX) || 456 (*data_out_size < data_in_size)) { 457 return false; 458 } 459 } 460 461 ret = libspdm_aead_prealloced(context, key, key_size, iv, iv_size, 462 a_data, a_data_size, data_in, data_in_size, 463 (uint8_t *) tag, tag_size, data_out, data_out_size, false); 464 465 *data_out_size = data_in_size; 466 467 return ret == 0; 468 469 } 470 471