• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3  * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
4  * All rights reserved.
5  ******************************************************************************/
6 
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10 
11 #include <gcrypt.h>
12 #include <stdio.h>
13 
14 #include "tss2_esys.h"
15 
16 #include "esys_crypto.h"
17 #include "esys_iutil.h"
18 #include "esys_mu.h"
19 #define LOGMODULE esys_crypto
20 #include "util/log.h"
21 #include "util/aux_util.h"
22 
23 /** Context to hold temporary values for iesys_crypto */
24 typedef struct _IESYS_CRYPTO_CONTEXT {
25     enum {
26         IESYS_CRYPTOGCRY_TYPE_HASH = 1,
27         IESYS_CRYPTOGCRY_TYPE_HMAC,
28     } type; /**< The type of context to hold; hash or hmac */
29     union {
30         struct {
31             gcry_md_hd_t gcry_context;
32             int gcry_hash_alg;
33             size_t hash_len;
34         } hash; /**< the state variables for a hash context */
35         struct {
36             gcry_mac_hd_t gcry_context;
37             int gcry_hmac_alg;
38             size_t hmac_len;
39         } hmac; /**< the state variables for an hmac context */
40     };
41 } IESYS_CRYPTOGCRY_CONTEXT;
42 
43 
44 /* Convert gcrypt mpi number to binary with fixed length */
mpi2bin(gcry_mpi_t mpi,unsigned char * bin,size_t bin_length,size_t max_out_size)45 static gcry_error_t mpi2bin(gcry_mpi_t mpi, unsigned char *bin,
46 		            size_t  bin_length, size_t max_out_size)
47 {
48     gcry_error_t err;
49     size_t size;
50     size_t offset;
51 
52     /* Determine size of mpi */
53     err = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, max_out_size, &size, mpi);
54     if (err != GPG_ERR_NO_ERROR) {
55         LOG_ERROR("Function gcry_mpi_print");
56         return err;
57     }
58 
59     offset = bin_length - size;
60     memset(&bin[0], 0,offset);
61     err = gcry_mpi_print(GCRYMPI_FMT_USG, &bin[offset], bin_length - offset, &size, mpi);
62     if (err != GPG_ERR_NO_ERROR) {
63         LOG_ERROR("Function gcry_mpi_print");
64     }
65     return err;
66 }
67 
68 /** Provide the context for the computation of a hash digest.
69  *
70  * The context will be created and initialized according to the hash function.
71  * @param[out] context The created context (callee-allocated).
72  * @param[in] hashAlg The hash algorithm for the creation of the context.
73  * @retval TSS2_RC_SUCCESS on success.
74  * @retval TSS2_ESYS_RC_BAD_VALUE or TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
75  * @retval TSS2_ESYS_RC_MEMORY Memory cannot be allocated.
76  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
77  */
78 TSS2_RC
iesys_cryptogcry_hash_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,TPM2_ALG_ID hashAlg)79 iesys_cryptogcry_hash_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,
80                             TPM2_ALG_ID hashAlg)
81 {
82     LOG_TRACE("call: context=%p hashAlg=%"PRIu16, context, hashAlg);
83     return_if_null(context, "Context is NULL", TSS2_ESYS_RC_BAD_REFERENCE);
84 
85     IESYS_CRYPTOGCRY_CONTEXT *mycontext;
86     mycontext = calloc(1, sizeof(IESYS_CRYPTOGCRY_CONTEXT));
87     return_if_null(mycontext, "Out of Memory", TSS2_ESYS_RC_MEMORY);
88 
89     mycontext->type = IESYS_CRYPTOGCRY_TYPE_HASH;
90 
91     switch (hashAlg) {
92     case TPM2_ALG_SHA1:
93         mycontext->hash.gcry_hash_alg = GCRY_MD_SHA1;
94         break;
95     case TPM2_ALG_SHA256:
96         mycontext->hash.gcry_hash_alg = GCRY_MD_SHA256;
97         break;
98     case TPM2_ALG_SHA384:
99         mycontext->hash.gcry_hash_alg = GCRY_MD_SHA384;
100         break;
101     default:
102         LOG_ERROR("Unsupported hash algorithm (%"PRIu16")", hashAlg);
103         free(mycontext);
104         return TSS2_ESYS_RC_NOT_IMPLEMENTED;
105     }
106     int hash_len = gcry_md_get_algo_dlen(mycontext->hash.gcry_hash_alg);
107     if (hash_len <= 0) {
108         LOG_ERROR("Unsupported hash algorithm (%"PRIu16")", hashAlg);
109         free(mycontext);
110         return TSS2_ESYS_RC_GENERAL_FAILURE;
111     }
112     mycontext->hash.hash_len = hash_len;
113 
114     gcry_error_t r = gcry_md_open(&mycontext->hash.gcry_context,
115                                   mycontext->hash.gcry_hash_alg, 0);
116     if (r != 0) {
117         LOG_ERROR("GCry error.");
118         free(mycontext);
119         return TSS2_ESYS_RC_GENERAL_FAILURE;
120     }
121 
122     *context = (IESYS_CRYPTO_CONTEXT_BLOB *) mycontext;
123 
124     return TSS2_RC_SUCCESS;
125 }
126 
127 /** Update the digest value of a digest object from a byte buffer.
128  *
129  * The context of a digest object will be updated according to the hash
130  * algorithm of the context.
131  * @param[in,out] context The context of the digest object which will be updated.
132  * @param[in] buffer The data for the update.
133  * @param[in] size The size of the data buffer.
134  * @retval TSS2_RC_SUCCESS on success.
135  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
136  */
137 TSS2_RC
iesys_cryptogcry_hash_update(IESYS_CRYPTO_CONTEXT_BLOB * context,const uint8_t * buffer,size_t size)138 iesys_cryptogcry_hash_update(IESYS_CRYPTO_CONTEXT_BLOB * context,
139                              const uint8_t * buffer, size_t size)
140 {
141     LOG_TRACE("called for context %p, buffer %p and size %zd", context, buffer,
142               size);
143     if (context == NULL || buffer == NULL) {
144         LOG_ERROR("Null-Pointer passed");
145         return TSS2_ESYS_RC_BAD_REFERENCE;
146     }
147     IESYS_CRYPTOGCRY_CONTEXT *mycontext = (IESYS_CRYPTOGCRY_CONTEXT *) context;
148     if (mycontext->type != IESYS_CRYPTOGCRY_TYPE_HASH) {
149         LOG_ERROR("bad context");
150         return TSS2_ESYS_RC_BAD_REFERENCE;
151     }
152 
153     LOGBLOB_TRACE(buffer, size, "Updating hash with");
154 
155     gcry_md_write(mycontext->hash.gcry_context, buffer, size);
156 
157     return TSS2_RC_SUCCESS;
158 }
159 
160 /** Update the digest value of a digest object from a TPM2B object.
161  *
162  * The context of a digest object will be updated according to the hash
163  * algorithm of the context.
164  * @param[in,out] context The context of the digest object which will be updated.
165  * @param[in] b The TPM2B object for the update.
166  * @retval TSS2_RC_SUCCESS on success.
167  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
168  */
169 TSS2_RC
iesys_cryptogcry_hash_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context,TPM2B * b)170 iesys_cryptogcry_hash_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context, TPM2B * b)
171 {
172     LOG_TRACE("called for context-pointer %p and 2b-pointer %p", context, b);
173     if (context == NULL || b == NULL) {
174         LOG_ERROR("Null-Pointer passed");
175         return TSS2_ESYS_RC_BAD_REFERENCE;
176     }
177     TSS2_RC ret = iesys_cryptogcry_hash_update(context, &b->buffer[0], b->size);
178     return ret;
179 }
180 
181 /** Get the digest value of a digest object and close the context.
182  *
183  * The digest value will written to a passed buffer and the resources of the
184  * digest object are released.
185  * @param[in,out] context The context of the digest object to be released
186  * @param[out] buffer The buffer for the digest value (caller-allocated).
187  * @param[out] size The size of the digest.
188  * @retval TSS2_RC_SUCCESS on success.
189  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
190  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
191  */
192 TSS2_RC
iesys_cryptogcry_hash_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,uint8_t * buffer,size_t * size)193 iesys_cryptogcry_hash_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,
194                              uint8_t * buffer, size_t * size)
195 {
196     LOG_TRACE("called for context-pointer %p, buffer %p and size-pointer %p",
197               context, buffer, size);
198     if (context == NULL || *context == NULL || buffer == NULL || size == NULL) {
199         LOG_ERROR("Null-Pointer passed");
200         return TSS2_ESYS_RC_BAD_REFERENCE;
201     }
202     IESYS_CRYPTOGCRY_CONTEXT *mycontext = * context;
203     if (mycontext->type != IESYS_CRYPTOGCRY_TYPE_HASH) {
204         LOG_ERROR("bad context");
205         return TSS2_ESYS_RC_BAD_REFERENCE;
206     }
207 
208     if (*size < mycontext->hash.hash_len) {
209         LOG_ERROR("Buffer too small");
210         return TSS2_ESYS_RC_BAD_SIZE;
211     }
212 
213     uint8_t *cpHash = gcry_md_read(mycontext->hash.gcry_context,
214                                    mycontext->hash.gcry_hash_alg);
215     return_if_null(cpHash, "GCry error.", TSS2_ESYS_RC_GENERAL_FAILURE);
216 
217     LOGBLOB_TRACE(cpHash, mycontext->hash.hash_len, "read hash result");
218 
219     *size = mycontext->hash.hash_len;
220     memmove(buffer, cpHash, *size);
221 
222     gcry_md_close(mycontext->hash.gcry_context);
223 
224     free(mycontext);
225     *context = NULL;
226 
227     return TSS2_RC_SUCCESS;
228 }
229 
230 /** Release the resources of a digest object.
231  *
232  * The assigned resources will be released and the context will be set to NULL.
233  * @param[in,out] context The context of the digest object.
234  */
235 void
iesys_cryptogcry_hash_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)236 iesys_cryptogcry_hash_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)
237 {
238     LOG_TRACE("called for context-pointer %p", context);
239     if (context == NULL || *context == NULL) {
240         LOG_DEBUG("Null-Pointer passed");
241         return;
242     }
243     IESYS_CRYPTOGCRY_CONTEXT *mycontext =
244         (IESYS_CRYPTOGCRY_CONTEXT *) * context;
245     if (mycontext->type != IESYS_CRYPTOGCRY_TYPE_HASH) {
246         LOG_DEBUG("bad context");
247         return;
248     }
249 
250     gcry_md_close(mycontext->hash.gcry_context);
251     free(mycontext);
252     *context = NULL;
253 }
254 
255 /* HMAC */
256 
257 /** Provide the context an HMAC digest object from a byte buffer key.
258  *
259  * The context will be created and initialized according to the hash function
260  * and the used HMAC key.
261  * @param[out] context The created context (callee-allocated).
262  * @param[in] hmacAlg The hash algorithm for the HMAC computation.
263  * @param[in] key The byte buffer of the HMAC key.
264  * @param[in] size The size of the HMAC key.
265  * @retval TSS2_RC_SUCCESS on success.
266  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
267  * @retval TSS2_ESYS_RC_MEMORY Memory cannot be allocated.
268  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
269  */
270 TSS2_RC
iesys_cryptogcry_hmac_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,TPM2_ALG_ID hmacAlg,const uint8_t * key,size_t size)271 iesys_cryptogcry_hmac_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,
272                             TPM2_ALG_ID hmacAlg,
273                             const uint8_t * key, size_t size)
274 {
275     TSS2_RC r;
276 
277     LOG_TRACE("called for context-pointer %p and hmacAlg %d", context, hmacAlg);
278     LOGBLOB_TRACE(key, size, "Starting  hmac with");
279     if (context == NULL || key == NULL) {
280         LOG_ERROR("Null-Pointer passed in for context");
281         return TSS2_ESYS_RC_BAD_REFERENCE;
282     }
283     IESYS_CRYPTOGCRY_CONTEXT *mycontext =
284         calloc(1, sizeof(IESYS_CRYPTOGCRY_CONTEXT));
285     return_if_null(mycontext, "Out of Memory", TSS2_ESYS_RC_MEMORY);
286 
287     switch (hmacAlg) {
288     case TPM2_ALG_SHA1:
289         mycontext->hmac.gcry_hmac_alg = GCRY_MAC_HMAC_SHA1;
290         break;
291     case TPM2_ALG_SHA256:
292         mycontext->hmac.gcry_hmac_alg = GCRY_MAC_HMAC_SHA256;
293         break;
294     default:
295         LOG_ERROR("Unsupported hmac algo.");
296         free(mycontext);
297         return TSS2_ESYS_RC_NOT_IMPLEMENTED;
298     }
299 
300     int hmac_len = gcry_mac_get_algo_maclen(mycontext->hmac.gcry_hmac_alg);
301     if (hmac_len <= 0) {
302         LOG_ERROR("GCry error.");
303         free(mycontext);
304         return TSS2_ESYS_RC_GENERAL_FAILURE;
305     }
306 
307     mycontext->type = IESYS_CRYPTOGCRY_TYPE_HMAC;
308     mycontext->hmac.hmac_len = hmac_len;
309 
310     r = gcry_mac_open(&mycontext->hmac.gcry_context,
311                       mycontext->hmac.gcry_hmac_alg, 0, NULL);
312     if (r != 0) {
313         LOG_ERROR("GCry error.");
314         free(mycontext);
315         return TSS2_ESYS_RC_GENERAL_FAILURE;
316     }
317 
318     r = gcry_mac_setkey(mycontext->hmac.gcry_context, key, size);
319     if (r != 0) {
320         LOG_ERROR("GCry error.");
321         gcry_mac_close(mycontext->hmac.gcry_context);
322         free(mycontext);
323         return TSS2_ESYS_RC_GENERAL_FAILURE;
324     }
325 
326     *context = (IESYS_CRYPTO_CONTEXT_BLOB *) mycontext;
327 
328     return TSS2_RC_SUCCESS;
329 }
330 
331 /** Update and HMAC digest value from a byte buffer.
332  *
333  * The context of a digest object will be updated according to the hash
334  * algorithm and the key of the context.
335  * @param[in,out] context The context of the digest object which will be updated.
336  * @param[in] buffer The data for the update.
337  * @param[in] size The size of the data buffer.
338  * @retval TSS2_RC_SUCCESS on success.
339  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
340  */
341 TSS2_RC
iesys_cryptogcry_hmac_update(IESYS_CRYPTO_CONTEXT_BLOB * context,const uint8_t * buffer,size_t size)342 iesys_cryptogcry_hmac_update(IESYS_CRYPTO_CONTEXT_BLOB * context,
343                              const uint8_t * buffer, size_t size)
344 {
345     LOG_TRACE("called for context %p, buffer %p and size %zd",
346               context, buffer, size);
347     if (context == NULL || buffer == NULL) {
348         LOG_ERROR("Null-Pointer passed");
349         return TSS2_ESYS_RC_BAD_REFERENCE;
350     }
351     IESYS_CRYPTOGCRY_CONTEXT *mycontext = (IESYS_CRYPTOGCRY_CONTEXT *) context;
352     if (mycontext->type != IESYS_CRYPTOGCRY_TYPE_HMAC) {
353         LOG_ERROR("bad context");
354         return TSS2_ESYS_RC_BAD_REFERENCE;
355     }
356 
357     LOGBLOB_TRACE(buffer, size, "Updating hmac with");
358 
359     if (GPG_ERR_NO_ERROR != gcry_mac_write(mycontext->hmac.gcry_context, buffer, size)) {
360         return_error(TSS2_ESYS_RC_GENERAL_FAILURE, "Gcrypt hmac update");
361     }
362 
363     return TSS2_RC_SUCCESS;
364 }
365 
366 /** Update and HMAC digest value from a TPM2B object.
367  *
368  * The context of a digest object will be updated according to the hash
369  * algorithm and the key of the context.
370  * @param[in,out] context The context of the digest object which will be updated.
371  * @param[in] b The TPM2B object for the update.
372  * @retval TSS2_RC_SUCCESS on success.
373  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
374  */
375 TSS2_RC
iesys_cryptogcry_hmac_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context,TPM2B * b)376 iesys_cryptogcry_hmac_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context, TPM2B * b)
377 {
378     LOG_TRACE("called for context-pointer %p and 2b-pointer %p", context, b);
379     if (context == NULL || b == NULL) {
380         LOG_ERROR("Null-Pointer passed");
381         return TSS2_ESYS_RC_BAD_REFERENCE;
382     }
383     TSS2_RC ret = iesys_cryptogcry_hmac_update(context, &b->buffer[0], b->size);
384     return ret;
385 }
386 
387 /** Write the HMAC digest value to a byte buffer and close the context.
388  *
389  * The digest value will written to a passed buffer and the resources of the
390  * HMAC object are released.
391  * @param[in,out] context The context of the HMAC object.
392  * @param[out] buffer The buffer for the digest value (caller-allocated).
393  * @param[out] size The size of the digest.
394  * @retval TSS2_RC_SUCCESS on success.
395  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
396  * @retval TSS2_ESYS_RC_BAD_SIZE If the size passed is lower than the HMAC length.
397  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
398  */
399 TSS2_RC
iesys_cryptogcry_hmac_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,uint8_t * buffer,size_t * size)400 iesys_cryptogcry_hmac_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,
401                              uint8_t * buffer, size_t * size)
402 {
403     LOG_TRACE("called for context-pointer %p, buffer %p and size-pointer %p",
404               context, buffer, size);
405     if (context == NULL || *context == NULL || buffer == NULL || size == NULL) {
406         LOG_ERROR("Null-Pointer passed");
407         return TSS2_ESYS_RC_BAD_REFERENCE;
408     }
409     IESYS_CRYPTOGCRY_CONTEXT *mycontext =
410         (IESYS_CRYPTOGCRY_CONTEXT *) * context;
411     if (mycontext->type != IESYS_CRYPTOGCRY_TYPE_HMAC) {
412         LOG_ERROR("bad context");
413         return TSS2_ESYS_RC_BAD_REFERENCE;
414     }
415 
416     if (*size < mycontext->hmac.hmac_len) {
417         LOG_ERROR("Buffer too small");
418         return TSS2_ESYS_RC_BAD_SIZE;
419     }
420 
421     TSS2_RC r = gcry_mac_read(mycontext->hmac.gcry_context, buffer, size);
422     if (r != 0) {
423         LOG_ERROR("GCry error.");
424         return TSS2_ESYS_RC_GENERAL_FAILURE;
425     }
426 
427     LOGBLOB_TRACE(buffer, *size, "read hmac result");
428 
429     gcry_mac_close(mycontext->hmac.gcry_context);
430 
431     free(mycontext);
432     *context = NULL;
433 
434     return TSS2_RC_SUCCESS;
435 }
436 
437 /** Write the HMAC digest value to a TPM2B object and close the context.
438  *
439  * The digest value will written to a passed TPM2B object and the resources of
440  * the HMAC object are released.
441  * @param[in,out] context The context of the HMAC object.
442  * @param[out] hmac The buffer for the digest value (caller-allocated).
443  * @retval TSS2_RC_SUCCESS on success.
444  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
445  * @retval TSS2_ESYS_RC_BAD_SIZE if the size passed is lower than the HMAC length.
446  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
447  */
448 TSS2_RC
iesys_cryptogcry_hmac_finish2b(IESYS_CRYPTO_CONTEXT_BLOB ** context,TPM2B * hmac)449 iesys_cryptogcry_hmac_finish2b(IESYS_CRYPTO_CONTEXT_BLOB ** context, TPM2B * hmac)
450 {
451     LOG_TRACE("called for context-pointer %p and 2b-pointer %p", context, hmac);
452     if (context == NULL || *context == NULL || hmac == NULL) {
453         LOG_ERROR("Null-Pointer passed");
454         return TSS2_ESYS_RC_BAD_REFERENCE;
455     }
456     size_t s = hmac->size;
457     TSS2_RC ret = iesys_cryptogcry_hmac_finish(context, &hmac->buffer[0], &s);
458     hmac->size = s;
459     return ret;
460 }
461 
462 /** Release the resources of an HAMC object.
463  *
464  * The assigned resources will be released and the context will be set to NULL.
465  * @param[in,out] context The context of the HMAC object.
466  */
467 void
iesys_cryptogcry_hmac_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)468 iesys_cryptogcry_hmac_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)
469 {
470     LOG_TRACE("called for context-pointer %p", context);
471     if (context == NULL || *context == NULL) {
472         LOG_DEBUG("Null-Pointer passed");
473         return;
474     }
475     if (*context != NULL) {
476         IESYS_CRYPTOGCRY_CONTEXT *mycontext =
477             (IESYS_CRYPTOGCRY_CONTEXT *) * context;
478         if (mycontext->type != IESYS_CRYPTOGCRY_TYPE_HMAC) {
479             LOG_DEBUG("bad context");
480             return;
481         }
482 
483         gcry_mac_close(mycontext->hmac.gcry_context);
484 
485         free(mycontext);
486         *context = NULL;
487     }
488 }
489 
490 /** Compute random TPM2B data.
491  *
492  * The random data will be generated and written to a passed TPM2B structure.
493  * @param[out] nonce The TPM2B structure for the random data (caller-allocated).
494  * @param[in] num_bytes The number of bytes to be generated.
495  * @retval TSS2_RC_SUCCESS on success.
496  */
497 TSS2_RC
iesys_cryptogcry_random2b(TPM2B_NONCE * nonce,size_t num_bytes)498 iesys_cryptogcry_random2b(TPM2B_NONCE * nonce, size_t num_bytes)
499 {
500     if (num_bytes == 0) {
501         nonce->size = sizeof(TPMU_HA);
502     } else {
503         nonce->size = num_bytes;
504     }
505     /*
506      * possible values for random level:
507      *  GCRY_WEAK_RANDOM GCRY_STRONG_RANDOM  GCRY_VERY_STRONG_RANDOM
508      */
509     gcry_randomize(&nonce->buffer[0], nonce->size, GCRY_STRONG_RANDOM);
510     return TSS2_RC_SUCCESS;
511 }
512 
513 /** Encryption of a buffer using a public (RSA) key.
514  *
515  * Encrypting a buffer using a public key is used for example during
516  * Esys_StartAuthSession in order to encrypt the salt value.
517  * @param[in] key The key to be used for encryption.
518  * @param[in] in_size The size of the buffer to be encrypted.
519  * @param[in] in_buffer The data buffer to be encrypted.
520  * @param[in] max_out_size The maximum size for the output encrypted buffer.
521  * @param[out] out_buffer The encrypted buffer.
522  * @param[out] out_size The size of the encrypted output.
523  * @param[in] label The label used in the encryption scheme.
524  * @retval TSS2_RC_SUCCESS on success
525  * @retval TSS2_ESYS_RC_BAD_VALUE The algorithm of key is not implemented.
526  * @retval TSS2_ESYS_RC_GENERAL_FAILURE The internal crypto engine failed.
527  */
528 TSS2_RC
iesys_cryptogcry_pk_encrypt(TPM2B_PUBLIC * key,size_t in_size,BYTE * in_buffer,size_t max_out_size,BYTE * out_buffer,size_t * out_size,const char * label)529 iesys_cryptogcry_pk_encrypt(TPM2B_PUBLIC * key,
530                             size_t in_size,
531                             BYTE * in_buffer,
532                             size_t max_out_size,
533                             BYTE * out_buffer,
534                             size_t * out_size, const char *label)
535 {
536     TSS2_RC r;
537     gcry_error_t err;
538     char *hash_alg;
539     size_t lsize = 0;
540     BYTE exponent[4] = { 0x00, 0x01, 0x00, 0x01 };
541     char *padding;
542     gcry_sexp_t sexp_data = NULL, sexp_key = NULL,
543                 sexp_cipher = NULL, sexp_cipher_a = NULL;
544     gcry_mpi_t mpi_cipher = NULL;
545 
546     if (label != NULL)
547         lsize = strlen(label) + 1;
548     switch (key->publicArea.nameAlg) {
549     case TPM2_ALG_SHA1:
550         hash_alg = "sha1";
551         break;
552     case TPM2_ALG_SHA256:
553         hash_alg = "sha256";
554         break;
555     default:
556         LOG_ERROR("Hash alg not implemented");
557         return TSS2_ESYS_RC_NOT_IMPLEMENTED;
558     }
559     switch (key->publicArea.parameters.rsaDetail.scheme.scheme) {
560     case TPM2_ALG_NULL:
561         padding = "raw";
562         break;
563     case TPM2_ALG_RSAES:
564         padding = "pkcs1";
565         break;
566     case TPM2_ALG_OAEP:
567         padding = "oaep";
568         break;
569     default:
570         LOG_ERROR("Illegal RSA scheme");
571         return TSS2_ESYS_RC_BAD_VALUE;
572     }
573     size_t offset = 0;
574     UINT32 exp;
575     if (key->publicArea.parameters.rsaDetail.exponent == 0)
576         exp = 65537;
577     else
578         exp = key->publicArea.parameters.rsaDetail.exponent;
579     r = Tss2_MU_UINT32_Marshal(exp, &exponent[0], sizeof(UINT32), &offset);
580     if (r != TSS2_RC_SUCCESS) {
581         LOG_ERROR("Marshaling");
582         return r;
583     }
584     err = gcry_sexp_build(&sexp_data, NULL,
585                           "(data (flags %s) (hash-algo %s) (label %b) (value %b) )",
586                           padding, hash_alg, lsize, label, (int)in_size,
587                           in_buffer);
588     if (err != GPG_ERR_NO_ERROR) {
589         LOG_ERROR("Function gcry_sexp_build");
590         return TSS2_ESYS_RC_GENERAL_FAILURE;
591     }
592     err = gcry_sexp_build(&sexp_key, NULL, "(public-key (rsa (n %b) (e %b)))",
593                           (int)key->publicArea.unique.rsa.size,
594                           &key->publicArea.unique.rsa.buffer[0], 4, exponent);
595     if (err != GPG_ERR_NO_ERROR) {
596         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
597                    "Function gcry_sexp_build", cleanup);
598     }
599     err = gcry_pk_encrypt(&sexp_cipher, sexp_data, sexp_key);
600     if (err != GPG_ERR_NO_ERROR) {
601         fprintf (stderr, "Failure: %s/%s\n",
602                  gcry_strsource (err),
603                  gcry_strerror (err));
604         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
605                    "Function gcry_pk_encrypt", cleanup);
606     }
607     sexp_cipher_a = gcry_sexp_find_token(sexp_cipher, "a", 0);
608     mpi_cipher = gcry_sexp_nth_mpi(sexp_cipher_a, 1, GCRYMPI_FMT_USG);
609     if (!mpi_cipher) {
610         LOG_ERROR("Function gcry_sexp_nth_mpi");
611         return TSS2_ESYS_RC_MEMORY;
612     }
613     err = mpi2bin(mpi_cipher, &out_buffer[0], key->publicArea.unique.rsa.size, max_out_size);
614     if (err != GPG_ERR_NO_ERROR) {
615         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
616                    "Function mpi2bin", cleanup);
617     }
618 
619     *out_size = key->publicArea.unique.rsa.size;
620     gcry_mpi_release(mpi_cipher);
621     gcry_sexp_release(sexp_data);
622     gcry_sexp_release(sexp_key);
623     gcry_sexp_release(sexp_cipher);
624     gcry_sexp_release(sexp_cipher_a);
625     return TSS2_RC_SUCCESS;
626 
627 cleanup:
628     if (mpi_cipher)
629         gcry_mpi_release(mpi_cipher);
630 
631     if (mpi_cipher)
632         gcry_sexp_release(sexp_data);
633 
634     if (mpi_cipher)
635         gcry_sexp_release(sexp_key);
636 
637     if (mpi_cipher)
638         gcry_sexp_release(sexp_cipher);
639 
640     if (mpi_cipher)
641         gcry_sexp_release(sexp_cipher_a);
642 
643     return r;
644 }
645 
646 /** Computation of ephemeral ECC key and shared secret Z.
647  *
648  * According to the description in  TPM spec part 1 C 6.1 a shared secret
649  * between application and TPM is computed (ECDH). An ephemeral ECC key and a
650  * TPM keyare used for the ECDH key exchange.
651  * @param[in] key The key to be used for ECDH key exchange.
652  * @param[in] max_out_size the max size for the output of the public key of the
653  *            computed ephemeral key.
654  * @param[out] Z The computed shared secret.
655  * @param[out] Q The public part of the ephemeral key in TPM format.
656  * @param[out] out_buffer The public part of the ephemeral key will be marshaled
657  *             to this buffer.
658  * @param[out] out_size The size of the marshaled output.
659  * @retval TSS2_RC_SUCCESS on success
660  * @retval TSS2_ESYS_RC_BAD_VALUE The algorithm of key is not implemented.
661  * @retval TSS2_ESYS_RC_GENERAL_FAILURE The internal crypto engine failed.
662  */
663 TSS2_RC
iesys_cryptogcry_get_ecdh_point(TPM2B_PUBLIC * key,size_t max_out_size,TPM2B_ECC_PARAMETER * Z,TPMS_ECC_POINT * Q,BYTE * out_buffer,size_t * out_size)664 iesys_cryptogcry_get_ecdh_point(TPM2B_PUBLIC *key,
665                                 size_t max_out_size,
666                                 TPM2B_ECC_PARAMETER *Z,
667                                 TPMS_ECC_POINT *Q,
668                                 BYTE * out_buffer,
669                                 size_t * out_size)
670 {
671 /*
672  * Format strings for some gcrypt sexps have to be created with sprintf due to
673  * a bug in libgcrypt. %s does not work in libgcypt with these sexps.
674  */
675 #define SEXP_GENKEY_ECC  "(genkey (ecc (curve %s)))"
676 #define SEXP_ECC_POINT "(ecc (curve %s) (q.x  %sb) (q.y %sb))"
677 
678     TSS2_RC r;
679     char *curveId;
680     gcry_sexp_t mpi_tpm_sq = NULL;     /* sexp for public part of TPM  key*/
681     gcry_sexp_t mpi_sd = NULL;         /* sexp for private part of ephemeral key */
682     gcry_sexp_t mpi_s_pub_q = NULL;    /* sexp for public part of ephemeral key */
683     gcry_mpi_point_t mpi_q = NULL;     /* public point of ephemeral key */
684     gcry_mpi_point_t mpi_tpm_q = NULL; /* public point of TPM key */
685     gcry_mpi_t mpi_d = NULL;           /* private part of ephemeral key */
686     gcry_mpi_point_t mpi_qd = NULL;    /* result of mpi_tpm_q * mpi_d */
687     gcry_ctx_t ctx = NULL;             /* context for ec curves */
688     size_t offset = 0;
689     gcry_mpi_t mpi_x = gcry_mpi_new(521);  /* big number for x coordinate */
690     gcry_mpi_t mpi_y = gcry_mpi_new(521);  /* big number for y coordinate */
691     size_t max_ecc_size;                   /* max size of ecc coordinate */
692 
693     /* Set libcrypt constant for curve type */
694     switch (key->publicArea.parameters.eccDetail.curveID) {
695     case TPM2_ECC_NIST_P192:
696         curveId = "\"NIST P-192\"";
697         max_ecc_size = (192+7)/8;
698         break;
699     case TPM2_ECC_NIST_P224:
700         curveId = "\"NIST P-224\"";
701         max_ecc_size = (224+7)/8;
702         break;
703     case TPM2_ECC_NIST_P256:
704         curveId = "\"NIST P-256\"";
705         max_ecc_size = (256+7)/8;
706         break;
707     case TPM2_ECC_NIST_P384:
708         curveId = "\"NIST P-384\"";
709         max_ecc_size = (384+7)/8;
710         break;
711     case TPM2_ECC_NIST_P521:
712         curveId = "\"NIST P-521\"";
713         max_ecc_size = (521+7)/8;
714         break;
715     default:
716         LOG_ERROR("Illegal ECC curve ID");
717         return TSS2_ESYS_RC_BAD_VALUE;
718     }
719 
720     /* compute ephemeral ecc key */
721     gcry_sexp_t ekey_spec = NULL, ekey_pair = NULL;
722     { /* scope for sexp_ecc_key */
723         char sexp_ecc_key [sizeof(SEXP_GENKEY_ECC)+strlen(curveId)
724                            -1];  // -1 = (-2 for %s +1 for \0)
725 
726         if (sprintf(&sexp_ecc_key[0], SEXP_GENKEY_ECC, curveId) < 1) {
727             goto_error(r, TSS2_ESYS_RC_MEMORY, "asprintf", cleanup);
728         }
729 
730         if (gcry_sexp_build(&ekey_spec, NULL,
731                             sexp_ecc_key) != GPG_ERR_NO_ERROR) {
732             goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "gcry_sexp_build", cleanup);
733         }
734     }
735 
736     if (gcry_pk_genkey (&ekey_pair, ekey_spec) != GPG_ERR_NO_ERROR) {
737         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Create ephemeral ecc key",
738                    cleanup);
739     }
740 
741     /* Get private ephemeral key d  */
742     mpi_sd = gcry_sexp_find_token(ekey_pair, "d", 0);
743     if (mpi_sd == NULL) {
744         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
745                    "Get private part of ecc key", cleanup);
746     }
747     mpi_d = gcry_sexp_nth_mpi(mpi_sd, 1, GCRYMPI_FMT_USG);
748     if (mpi_d == NULL) {
749         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
750                    "Get private part of ecc key from sexp", cleanup);
751     }
752 
753     /* Construct ephemeral public key */
754     mpi_s_pub_q = gcry_sexp_find_token(ekey_pair, "public-key", 0);
755     if (mpi_s_pub_q == NULL) {
756         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Get public part ecc key",
757                    cleanup);
758     }
759 
760     if (gcry_mpi_ec_new (&ctx, mpi_s_pub_q, curveId) != GPG_ERR_NO_ERROR) {
761         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Create ec", cleanup);
762     }
763     mpi_q =  gcry_mpi_ec_get_point ("q", ctx, 1);
764     if (mpi_q == NULL) {
765         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Get ecc point", cleanup);
766     }
767 
768     /* Check whether point is on curve */
769     if (!gcry_mpi_ec_curve_point(mpi_q, ctx)) {
770         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Point not on curve", cleanup);
771     }
772 
773     /* Store ephemeral public key in Q */
774     if (gcry_mpi_ec_get_affine (mpi_x, mpi_y, mpi_q, ctx)) {
775         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Point is at infinity",
776                    cleanup);
777     }
778 
779     if (mpi2bin(mpi_x, &Q->x.buffer[0], max_ecc_size, max_out_size)) {
780         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Get x part of point",
781                    cleanup);
782     }
783 
784     if (mpi2bin(mpi_y, &Q->y.buffer[0], max_ecc_size, max_out_size)) {
785         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Get y part of point",
786                    cleanup);
787     }
788 
789     Q->x.size = max_ecc_size;
790     Q->y.size = max_ecc_size;
791     gcry_ctx_release(ctx);
792 
793     { /* scope for sexp_point */
794 
795         /* Get public point from TPM key */
796         char sexp_point [sizeof(SEXP_ECC_POINT) + strlen(curveId)
797                          + key->publicArea.unique.ecc.x.size
798                          + key->publicArea.unique.ecc.y.size
799                          - 5];  /* -1 = (-4 for 2*%sb -2 for %s +1 for \0) */
800 
801         if (sprintf(&sexp_point[0], SEXP_ECC_POINT,
802                     curveId, "%", "%") <1 ) {
803             goto_error(r, TSS2_ESYS_RC_MEMORY, "asprintf", cleanup);
804         }
805 
806         if ( gcry_sexp_build(&mpi_tpm_sq, NULL,
807                               sexp_point,
808                               key->publicArea.unique.ecc.x.size,
809                               &key->publicArea.unique.ecc.x.buffer[0],
810                               key->publicArea.unique.ecc.y.size,
811                              &key->publicArea.unique.ecc.y.buffer[0])) {
812             goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
813                        "Function gcry_mpi_scan", cleanup);
814 
815         }
816     }
817     offset = 0;
818     r = Tss2_MU_TPMS_ECC_POINT_Marshal(Q,  &out_buffer[0], max_out_size, &offset);
819     return_if_error(r, "Error marshaling");
820     *out_size = offset;
821 
822     /* Multiply d and Q */
823     if (gcry_mpi_ec_new (&ctx, mpi_tpm_sq, curveId)) {
824         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "create ec curve", cleanup);
825     }
826     mpi_tpm_q =  gcry_mpi_ec_get_point ("q", ctx, 1);
827     mpi_qd = gcry_mpi_point_new(256);
828     gcry_mpi_ec_mul(mpi_qd , mpi_d, mpi_tpm_q, ctx);
829 
830     /* Store the x coordinate of d*Q in Z which will be used for KDFe */
831     if (gcry_mpi_ec_get_affine (mpi_x, mpi_y, mpi_qd, ctx)) {
832         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
833                    "Point is at infinity", cleanup);
834     }
835 
836     if (mpi2bin(mpi_x, &Z->buffer[0], max_ecc_size, TPM2_MAX_ECC_KEY_BYTES)) {
837         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
838                    "Get x coordinate d*Q", cleanup);
839     }
840 
841     Z->size = max_ecc_size;
842     LOGBLOB_DEBUG(&Z->buffer[0], Z->size, "Z (Q*d)");
843 
844  cleanup:
845     if (ctx)
846         gcry_ctx_release(ctx);
847 
848     if (mpi_x)
849         gcry_mpi_release(mpi_x);
850 
851     if (mpi_y)
852         gcry_mpi_release(mpi_y);
853 
854     if (mpi_d)
855         gcry_mpi_release(mpi_d);
856 
857     if (mpi_sd)
858         gcry_sexp_release(mpi_sd);
859 
860     if (mpi_tpm_q)
861         gcry_mpi_point_release(mpi_tpm_q);
862 
863     if (mpi_qd)
864         gcry_mpi_point_release(mpi_qd);
865 
866     if (mpi_q)
867         gcry_mpi_point_release(mpi_q);
868 
869     if (mpi_tpm_sq)
870         gcry_sexp_release(mpi_tpm_sq);
871 
872     if (mpi_s_pub_q)
873         gcry_sexp_release(mpi_s_pub_q);
874 
875     if (ekey_spec)
876         gcry_sexp_release(ekey_spec);
877 
878     if (ekey_pair)
879         gcry_sexp_release(ekey_pair);
880 
881     return r;
882 }
883 
884 /** Initialize AES context for encryption / decryption.
885  *
886  * @param[out] handle for AES context
887  * @param[in] key key used for AES.
888  * @param[in] tpm_sym_alg AES type in TSS2 notation.
889  * @param[in] key_bits Key size in bits.
890  * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB).
891  *         For parameter encryption only CFB can be used.
892  * @param[in] iv_len Length of initialization vector (iv) in byte.
893  * @param[in] iv The initialization vector.
894  * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE for invalid
895  *         parameters, TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto
896  *         library.
897  */
898 static TSS2_RC
iesys_cryptogcry_sym_aes_init(gcry_cipher_hd_t * cipher_hd,uint8_t * key,TPM2_ALG_ID tpm_sym_alg,TPMI_AES_KEY_BITS key_bits,TPM2_ALG_ID tpm_mode,size_t iv_len,uint8_t * iv)899 iesys_cryptogcry_sym_aes_init(gcry_cipher_hd_t * cipher_hd,
900                               uint8_t * key,
901                               TPM2_ALG_ID tpm_sym_alg,
902                               TPMI_AES_KEY_BITS key_bits,
903                               TPM2_ALG_ID tpm_mode,
904                               size_t iv_len, uint8_t * iv)
905 {
906 
907     LOGBLOB_TRACE(key, (key_bits + 7) / 8, "IESYS AES key");
908     LOGBLOB_TRACE(iv, iv_len, "IESYS AES iv");
909     int algo, mode, len;
910     size_t key_len = 0;
911     gcry_error_t err;
912     TSS2_RC r = TSS2_RC_SUCCESS;
913 
914     switch (tpm_sym_alg) {
915     case TPM2_ALG_AES:
916         switch (key_bits) {
917         case 128:
918             algo = GCRY_CIPHER_AES128;
919             len = 128;
920             break;
921         case 192:
922             algo = GCRY_CIPHER_AES192;
923             len = 192;
924             break;
925         case 256:
926             algo = GCRY_CIPHER_AES256;
927             len = 256;
928             break;
929         default:
930             LOG_ERROR("Illegal key length.");
931             return TSS2_ESYS_RC_BAD_VALUE;
932         }
933         switch (tpm_mode) {
934         case TPM2_ALG_CFB:
935             mode = GCRY_CIPHER_MODE_CFB;
936             break;
937         default:
938             LOG_ERROR("Illegal symmetric algorithm.");
939             return TSS2_ESYS_RC_BAD_VALUE;
940         }
941         break;
942     default:
943         LOG_ERROR("Illegal symmetric algorithm.");
944         return TSS2_ESYS_RC_BAD_VALUE;
945     }
946     key_len = (len + 7) / 8;
947     err = gcry_cipher_open(cipher_hd, algo, mode, 0);
948     if (err != GPG_ERR_NO_ERROR) {
949         LOG_ERROR("Opening gcrypt context");
950         return TSS2_ESYS_RC_GENERAL_FAILURE;
951     }
952     if (iv_len != 0) {
953         err = gcry_cipher_setiv(*cipher_hd, &iv[0], iv_len);
954         if (err != GPG_ERR_NO_ERROR) {
955             LOG_ERROR("Function gcry_cipher_setiv");
956             gcry_cipher_close(*cipher_hd);
957             r = TSS2_ESYS_RC_GENERAL_FAILURE;
958         }
959     }
960     if (r == TSS2_RC_SUCCESS) {
961         err = gcry_cipher_setkey(*cipher_hd, key, key_len);
962         if (err != GPG_ERR_NO_ERROR) {
963             LOG_ERROR("Function gcry_cipher_setkey");
964             gcry_cipher_close(*cipher_hd);
965             r = TSS2_ESYS_RC_GENERAL_FAILURE;
966         }
967     }
968     return r;
969 }
970 
971 /** Encrypt data with AES.
972  *
973  * @param[in] key key used for AES.
974  * @param[in] tpm_sym_alg AES type in TSS2 notation (must be TPM2_ALG_AES).
975  * @param[in] key_bits Key size in bits.
976  * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation.
977  * @param[in] blk_len Length Block length of AES.
978  * @param[in,out] buffer Data to be encrypted. The encrypted date will be stored
979  *                in this buffer.
980  * @param[in] buffer_size size of data to be encrypted.
981  * @param[in] iv The initialization vector. The size is equal to blk_len.
982  * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and
983  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters,
984  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
985  */
986 TSS2_RC
iesys_cryptogcry_sym_aes_encrypt(uint8_t * key,TPM2_ALG_ID tpm_sym_alg,TPMI_AES_KEY_BITS key_bits,TPM2_ALG_ID tpm_mode,size_t blk_len,uint8_t * buffer,size_t buffer_size,uint8_t * iv)987 iesys_cryptogcry_sym_aes_encrypt(uint8_t * key,
988                                  TPM2_ALG_ID tpm_sym_alg,
989                                  TPMI_AES_KEY_BITS key_bits,
990                                  TPM2_ALG_ID tpm_mode,
991                                  size_t blk_len,
992                                  uint8_t * buffer,
993                                  size_t buffer_size,
994                                  uint8_t * iv)
995 {
996     gcry_cipher_hd_t cipher_hd;
997     gcry_error_t err;
998     TSS2_RC r;
999 
1000     if (key == NULL || buffer == NULL) {
1001         LOG_ERROR("Bad reference");
1002         return TSS2_ESYS_RC_BAD_REFERENCE;
1003     }
1004 
1005     r = iesys_cryptogcry_sym_aes_init(&cipher_hd, key, tpm_sym_alg,
1006                                       key_bits, tpm_mode, blk_len, iv);
1007     if (r != TSS2_RC_SUCCESS)
1008         return r;
1009     LOGBLOB_TRACE(buffer, buffer_size, "IESYS AES input");
1010     err = gcry_cipher_encrypt(cipher_hd, buffer, buffer_size, NULL, 0);
1011     LOGBLOB_TRACE(buffer, buffer_size, "IESYS AES output");
1012     if (err != GPG_ERR_NO_ERROR) {
1013         LOG_ERROR("Function gcry_cipher_encrypt");
1014         r = TSS2_ESYS_RC_GENERAL_FAILURE;
1015     }
1016     gcry_cipher_close(cipher_hd);
1017     return r;
1018 }
1019 
1020 /** Decrypt data with AES.
1021  *
1022  * @param[in] key key used for AES.
1023  * @param[in] tpm_sym_alg AES type in TSS2 notation (must be TPM2_ALG_AES).
1024  * @param[in] key_bits Key size in bits.
1025  * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB).
1026  * @param[in] blk_len Length Block length of AES.
1027  * @param[in,out] buffer Data to be decrypted. The decrypted date will be stored
1028  *                in this buffer.
1029  * @param[in] buffer_size size of data to be encrypted.
1030  * @param[in] iv The initialization vector. The size is equal to blk_len.
1031  * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and
1032  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters,
1033  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
1034  */
1035 TSS2_RC
iesys_cryptogcry_sym_aes_decrypt(uint8_t * key,TPM2_ALG_ID tpm_sym_alg,TPMI_AES_KEY_BITS key_bits,TPM2_ALG_ID tpm_mode,size_t blk_len,uint8_t * buffer,size_t buffer_size,uint8_t * iv)1036 iesys_cryptogcry_sym_aes_decrypt(uint8_t * key,
1037                                  TPM2_ALG_ID tpm_sym_alg,
1038                                  TPMI_AES_KEY_BITS key_bits,
1039                                  TPM2_ALG_ID tpm_mode,
1040                                  size_t blk_len,
1041                                  uint8_t * buffer,
1042                                  size_t buffer_size,
1043                                  uint8_t * iv)
1044 {
1045     gcry_cipher_hd_t cipher_hd;
1046     gcry_error_t err;
1047     TSS2_RC r;
1048 
1049     if (key == NULL || buffer == NULL) {
1050         LOG_ERROR("Bad reference");
1051         return TSS2_ESYS_RC_BAD_REFERENCE;
1052     }
1053 
1054     if (tpm_sym_alg != TPM2_ALG_AES) {
1055         LOG_ERROR("AES expected");
1056         return TSS2_ESYS_RC_BAD_VALUE;
1057     }
1058 
1059     r = iesys_cryptogcry_sym_aes_init(&cipher_hd, key, tpm_sym_alg,
1060                                       key_bits, tpm_mode, blk_len, iv);
1061     if (r != TSS2_RC_SUCCESS)
1062         return r;
1063     err = gcry_cipher_decrypt(cipher_hd, buffer, buffer_size, NULL, 0);
1064     if (err != GPG_ERR_NO_ERROR) {
1065         LOG_ERROR("Function gcry_cipher_decrypt");
1066         r = TSS2_ESYS_RC_GENERAL_FAILURE;
1067     }
1068     gcry_cipher_close(cipher_hd);
1069     return r;
1070 }
1071 
1072 /** Initialize gcrypt crypto backend.
1073  *
1074  * Initialize gcrypt internal tables.
1075  *
1076  * @retval TSS2_RC_SUCCESS ong success.
1077  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for version mismatch.
1078  */
1079 TSS2_RC
iesys_cryptogcry_init()1080 iesys_cryptogcry_init() {
1081     if (!gcry_check_version (GCRYPT_VERSION))
1082     {
1083         LOG_ERROR("Version mismatch for gcrypt");
1084         return TSS2_ESYS_RC_GENERAL_FAILURE;
1085     }
1086     return TSS2_RC_SUCCESS;
1087 }
1088