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