• 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 <openssl/evp.h>
12 #include <openssl/aes.h>
13 #include <openssl/rsa.h>
14 #include <openssl/engine.h>
15 #include <stdio.h>
16 
17 #include "tss2_esys.h"
18 
19 #include "esys_crypto.h"
20 #include "esys_crypto_ossl.h"
21 
22 #include "esys_iutil.h"
23 #include "esys_mu.h"
24 #define LOGMODULE esys_crypto
25 #include "util/log.h"
26 #include "util/aux_util.h"
27 
28 static int
iesys_bn2binpad(const BIGNUM * bn,unsigned char * bin,int bin_length)29 iesys_bn2binpad(const BIGNUM *bn, unsigned char *bin, int bin_length)
30 {
31     int len_bn = BN_num_bytes(bn);
32     int offset = bin_length - len_bn;
33     memset(bin,0,offset);
34     BN_bn2bin(bn, bin + offset);
35     return 1;
36 }
37 
38 /** Context to hold temporary values for iesys_crypto */
39 typedef struct _IESYS_CRYPTO_CONTEXT {
40     enum {
41         IESYS_CRYPTOSSL_TYPE_HASH = 1,
42         IESYS_CRYPTOSSL_TYPE_HMAC,
43     } type; /**< The type of context to hold; hash or hmac */
44     union {
45         struct {
46             EVP_MD_CTX  *ossl_context;
47             const EVP_MD *ossl_hash_alg;
48             size_t hash_len;
49         } hash; /**< the state variables for a hash context */
50         struct {
51             EVP_MD_CTX *ossl_context;
52             const EVP_MD *ossl_hash_alg;
53             size_t hmac_len;
54         } hmac; /**< the state variables for an hmac context */
55     };
56 } IESYS_CRYPTOSSL_CONTEXT;
57 
58 const EVP_MD *
get_ossl_hash_md(TPM2_ALG_ID hashAlg)59 get_ossl_hash_md(TPM2_ALG_ID hashAlg)
60 {
61     switch (hashAlg) {
62     case TPM2_ALG_SHA1:
63         return EVP_sha1();
64         break;
65     case TPM2_ALG_SHA256:
66         return EVP_sha256();
67         break;
68     case TPM2_ALG_SHA384:
69         return EVP_sha384();
70         break;
71     case TPM2_ALG_SHA512:
72         return EVP_sha512();
73         break;
74     default:
75         return NULL;
76     }
77 }
78 
79 /** Provide the context for the computation of a hash digest.
80  *
81  * The context will be created and initialized according to the hash function.
82  * @param[out] context The created context (callee-allocated).
83  * @param[in] hashAlg The hash algorithm for the creation of the context.
84  * @retval TSS2_RC_SUCCESS on success.
85  * @retval TSS2_ESYS_RC_BAD_VALUE or TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
86  * @retval TSS2_ESYS_RC_MEMORY Memory cannot be allocated.
87  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
88  */
89 TSS2_RC
iesys_cryptossl_hash_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,TPM2_ALG_ID hashAlg)90 iesys_cryptossl_hash_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,
91                            TPM2_ALG_ID hashAlg)
92 {
93     TSS2_RC r = TSS2_RC_SUCCESS;
94     LOG_TRACE("call: context=%p hashAlg=%"PRIu16, context, hashAlg);
95     return_if_null(context, "Context is NULL", TSS2_ESYS_RC_BAD_REFERENCE);
96     return_if_null(context, "Null-Pointer passed for context", TSS2_ESYS_RC_BAD_REFERENCE);
97     IESYS_CRYPTOSSL_CONTEXT *mycontext;
98     mycontext = calloc(1, sizeof(IESYS_CRYPTOSSL_CONTEXT));
99     return_if_null(mycontext, "Out of Memory", TSS2_ESYS_RC_MEMORY);
100     mycontext->type = IESYS_CRYPTOSSL_TYPE_HASH;
101 
102     if (!(mycontext->hash.ossl_hash_alg = get_ossl_hash_md(hashAlg))) {
103         goto_error(r, TSS2_ESYS_RC_NOT_IMPLEMENTED,
104                    "Unsupported hash algorithm (%"PRIu16")", cleanup, hashAlg);
105     }
106 
107     if (iesys_crypto_hash_get_digest_size(hashAlg, &mycontext->hash.hash_len)) {
108         goto_error(r, TSS2_ESYS_RC_NOT_IMPLEMENTED,
109                    "Unsupported hash algorithm (%"PRIu16")", cleanup, hashAlg);
110     }
111 
112     if (!(mycontext->hash.ossl_context =  EVP_MD_CTX_create())) {
113         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Error EVP_MD_CTX_create", cleanup);
114     }
115 
116     if (1 != EVP_DigestInit_ex(mycontext->hash.ossl_context,
117                                mycontext->hash.ossl_hash_alg,
118                                NULL)) {
119         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Errror EVP_DigestInit_ex", cleanup);
120     }
121 
122     *context = (IESYS_CRYPTO_CONTEXT_BLOB *) mycontext;
123 
124     return TSS2_RC_SUCCESS;
125 
126  cleanup:
127     if (mycontext->hash.ossl_context)
128         EVP_MD_CTX_destroy(mycontext->hash.ossl_context);
129     SAFE_FREE(mycontext);
130 
131     return r;
132 }
133 
134 /** Update the digest value of a digest object from a byte buffer.
135  *
136  * The context of a digest object will be updated according to the hash
137  * algorithm of the context. <
138  * @param[in,out] context The context of the digest object which will be updated.
139  * @param[in] buffer The data for the update.
140  * @param[in] size The size of the data buffer.
141  * @retval TSS2_RC_SUCCESS on success.
142  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
143  */
144 TSS2_RC
iesys_cryptossl_hash_update(IESYS_CRYPTO_CONTEXT_BLOB * context,const uint8_t * buffer,size_t size)145 iesys_cryptossl_hash_update(IESYS_CRYPTO_CONTEXT_BLOB * context,
146                             const uint8_t * buffer, size_t size)
147 {
148     LOG_TRACE("called for context %p, buffer %p and size %zd", context, buffer,
149               size);
150     if (context == NULL || buffer == NULL) {
151         LOG_ERROR("Null-Pointer passed");
152         return TSS2_ESYS_RC_BAD_REFERENCE;
153     }
154     IESYS_CRYPTOSSL_CONTEXT *mycontext = (IESYS_CRYPTOSSL_CONTEXT *) context;
155     if (mycontext->type != IESYS_CRYPTOSSL_TYPE_HASH) {
156         LOG_ERROR("bad context");
157         return TSS2_ESYS_RC_BAD_REFERENCE;
158     }
159 
160     LOGBLOB_TRACE(buffer, size, "Updating hash with");
161 
162     if (1 != EVP_DigestUpdate(mycontext->hash.ossl_context, buffer, size)) {
163         return_error(TSS2_ESYS_RC_GENERAL_FAILURE, "OSSL hash update");
164     }
165 
166     return TSS2_RC_SUCCESS;
167 }
168 
169 /** Update the digest value of a digest object from a TPM2B object.
170  *
171  * The context of a digest object will be updated according to the hash
172  * algorithm of the context.
173  * @param[in,out] context The context of the digest object which will be updated.
174  * @param[in] b The TPM2B object for the update.
175  * @retval TSS2_RC_SUCCESS on success.
176  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
177  */
178 TSS2_RC
iesys_cryptossl_hash_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context,TPM2B * b)179 iesys_cryptossl_hash_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context, TPM2B * b)
180 {
181     LOG_TRACE("called for context-pointer %p and 2b-pointer %p", context, b);
182     if (context == NULL || b == NULL) {
183         LOG_ERROR("Null-Pointer passed");
184         return TSS2_ESYS_RC_BAD_REFERENCE;
185     }
186     TSS2_RC ret = iesys_cryptossl_hash_update(context, &b->buffer[0], b->size);
187     return ret;
188 }
189 
190 /** Get the digest value of a digest object and close the context.
191  *
192  * The digest value will written to a passed buffer and the resources of the
193  * digest object are released.
194  * @param[in,out] context The context of the digest object to be released
195  * @param[out] buffer The buffer for the digest value (caller-allocated).
196  * @param[out] size The size of the digest.
197  * @retval TSS2_RC_SUCCESS on success.
198  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
199  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
200  */
201 TSS2_RC
iesys_cryptossl_hash_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,uint8_t * buffer,size_t * size)202 iesys_cryptossl_hash_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,
203                             uint8_t * buffer, size_t * size)
204 {
205     unsigned int digest_size = 0;
206 
207     LOG_TRACE("called for context-pointer %p, buffer %p and size-pointer %p",
208               context, buffer, size);
209     if (context == NULL || *context == NULL || buffer == NULL || size == NULL) {
210         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Null-Pointer passed");
211     }
212     IESYS_CRYPTOSSL_CONTEXT *mycontext = * context;
213     if (mycontext->type != IESYS_CRYPTOSSL_TYPE_HASH) {
214         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "bad context");
215     }
216 
217     if (*size < mycontext->hash.hash_len) {
218         return_error(TSS2_ESYS_RC_BAD_SIZE, "Buffer too small");
219     }
220 
221     if (1 != EVP_DigestFinal_ex(mycontext->hash.ossl_context, buffer, &digest_size)) {
222         return_error(TSS2_ESYS_RC_GENERAL_FAILURE, "Ossl error.");
223     }
224 
225     if (digest_size != mycontext->hash.hash_len) {
226         return_error(TSS2_ESYS_RC_GENERAL_FAILURE,
227                      "Invalid size computed by EVP_DigestFinal_ex");
228     }
229 
230     LOGBLOB_TRACE(buffer, mycontext->hash.hash_len, "read hash result");
231 
232     *size = mycontext->hash.hash_len;
233     EVP_MD_CTX_destroy(mycontext->hash.ossl_context);
234     free(mycontext);
235     *context = NULL;
236 
237     return TSS2_RC_SUCCESS;
238 }
239 
240 /** Release the resources of a digest object.
241  *
242  * The assigned resources will be released and the context will be set to NULL.
243  * @param[in,out] context The context of the digest object.
244  */
245 void
iesys_cryptossl_hash_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)246 iesys_cryptossl_hash_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)
247 {
248     LOG_TRACE("called for context-pointer %p", context);
249     if (context == NULL || *context == NULL) {
250         LOG_DEBUG("Null-Pointer passed");
251         return;
252     }
253     IESYS_CRYPTOSSL_CONTEXT *mycontext =
254         (IESYS_CRYPTOSSL_CONTEXT *) * context;
255     if (mycontext->type != IESYS_CRYPTOSSL_TYPE_HASH) {
256         LOG_DEBUG("bad context");
257         return;
258     }
259 
260     EVP_MD_CTX_destroy(mycontext->hash.ossl_context);
261     free(mycontext);
262     *context = NULL;
263 }
264 
265 /* HMAC */
266 
267 /** Provide the context an HMAC digest object from a byte buffer key.
268  *
269  * The context will be created and initialized according to the hash function
270  * and the used HMAC key.
271  * @param[out] context The created context (callee-allocated).
272  * @param[in] hmacAlg The hash algorithm for the HMAC computation.
273  * @param[in] key The byte buffer of the HMAC key.
274  * @param[in] size The size of the HMAC key.
275  * @retval TSS2_RC_SUCCESS on success.
276  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
277  * @retval TSS2_ESYS_RC_MEMORY Memory cannot be allocated.
278  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
279  */
280 TSS2_RC
iesys_cryptossl_hmac_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,TPM2_ALG_ID hashAlg,const uint8_t * key,size_t size)281 iesys_cryptossl_hmac_start(IESYS_CRYPTO_CONTEXT_BLOB ** context,
282                            TPM2_ALG_ID hashAlg,
283                            const uint8_t * key, size_t size)
284 {
285     TSS2_RC r = TSS2_RC_SUCCESS;
286     EVP_PKEY *hkey = NULL;
287 
288     LOG_TRACE("called for context-pointer %p and hmacAlg %d", context, hashAlg);
289     LOGBLOB_TRACE(key, size, "Starting  hmac with");
290     if (context == NULL || key == NULL) {
291         return_error(TSS2_ESYS_RC_BAD_REFERENCE,
292                      "Null-Pointer passed in for context");
293     }
294     IESYS_CRYPTOSSL_CONTEXT *mycontext = calloc(1, sizeof(IESYS_CRYPTOSSL_CONTEXT));
295     return_if_null(mycontext, "Out of Memory", TSS2_ESYS_RC_MEMORY);
296 
297     if (!(mycontext->hmac.ossl_hash_alg = get_ossl_hash_md(hashAlg))) {
298         goto_error(r, TSS2_ESYS_RC_NOT_IMPLEMENTED,
299                    "Unsupported hash algorithm (%"PRIu16")", cleanup, hashAlg);
300     }
301 
302     if (iesys_crypto_hash_get_digest_size(hashAlg, &mycontext->hmac.hmac_len)) {
303         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
304                    "Unsupported hash algorithm (%"PRIu16")", cleanup, hashAlg);
305     }
306 
307     if (!(mycontext->hmac.ossl_context =  EVP_MD_CTX_create())) {
308         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
309                    "Error EVP_MD_CTX_create", cleanup);
310     }
311 
312     if (!(hkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, size))) {
313         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
314                    "EVP_PKEY_new_mac_key", cleanup);
315     }
316 
317     if(1 != EVP_DigestSignInit(mycontext->hmac.ossl_context, NULL,
318                                mycontext->hmac.ossl_hash_alg, NULL, hkey)) {
319         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
320                    "DigestSignInit", cleanup);
321     }
322 
323     mycontext->type = IESYS_CRYPTOSSL_TYPE_HMAC;
324 
325     *context = (IESYS_CRYPTO_CONTEXT_BLOB *) mycontext;
326 
327     EVP_PKEY_free(hkey);
328 
329     return TSS2_RC_SUCCESS;
330 
331  cleanup:
332     if (mycontext->hmac.ossl_context)
333         EVP_MD_CTX_destroy(mycontext->hmac.ossl_context);
334     if(hkey)
335         EVP_PKEY_free(hkey);
336     SAFE_FREE(mycontext);
337     return r;
338 }
339 
340 /** Update and HMAC digest value from a byte buffer.
341  *
342  * The context of a digest object will be updated according to the hash
343  * algorithm and the key of the context.
344  * @param[in,out] context The context of the digest object which will be updated.
345  * @param[in] buffer The data for the update.
346  * @param[in] size The size of the data buffer.
347  * @retval TSS2_RC_SUCCESS on success.
348  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
349  */
350 TSS2_RC
iesys_cryptossl_hmac_update(IESYS_CRYPTO_CONTEXT_BLOB * context,const uint8_t * buffer,size_t size)351 iesys_cryptossl_hmac_update(IESYS_CRYPTO_CONTEXT_BLOB * context,
352                             const uint8_t * buffer, size_t size)
353 {
354     LOG_TRACE("called for context %p, buffer %p and size %zd",
355               context, buffer, size);
356     if (context == NULL || buffer == NULL) {
357         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Null-Pointer passed");
358     }
359     IESYS_CRYPTOSSL_CONTEXT *mycontext = (IESYS_CRYPTOSSL_CONTEXT *) context;
360     if (mycontext->type != IESYS_CRYPTOSSL_TYPE_HMAC) {
361         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "bad context");
362     }
363 
364     LOGBLOB_TRACE(buffer, size, "Updating hmac with");
365 
366     /* Call update with the message */
367     if(1 != EVP_DigestSignUpdate(mycontext->hmac.ossl_context, buffer, size)) {
368         return_error(TSS2_ESYS_RC_GENERAL_FAILURE, "OSSL HMAC update");
369     }
370 
371     return TSS2_RC_SUCCESS;
372 }
373 
374 /** Update and HMAC digest value from a TPM2B object.
375  *
376  * The context of a digest object will be updated according to the hash
377  * algorithm and the key of the context.
378  * @param[in,out] context The context of the digest object which will be updated.
379  * @param[in] b The TPM2B object for the update.
380  * @retval TSS2_RC_SUCCESS on success.
381  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
382  */
383 TSS2_RC
iesys_cryptossl_hmac_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context,TPM2B * b)384 iesys_cryptossl_hmac_update2b(IESYS_CRYPTO_CONTEXT_BLOB * context, TPM2B * b)
385 {
386     LOG_TRACE("called for context-pointer %p and 2b-pointer %p", context, b);
387     if (context == NULL || b == NULL) {
388         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Null-Pointer passed");
389     }
390     TSS2_RC ret = iesys_cryptossl_hmac_update(context, &b->buffer[0], b->size);
391     return ret;
392 }
393 
394 /** Write the HMAC digest value to a byte buffer and close the context.
395  *
396  * The digest value will written to a passed buffer and the resources of the
397  * HMAC object are released.
398  * @param[in,out] context The context of the HMAC object.
399  * @param[out] buffer The buffer for the digest value (caller-allocated).
400  * @param[out] size The size of the digest.
401  * @retval TSS2_RC_SUCCESS on success.
402  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
403  * @retval TSS2_ESYS_RC_BAD_SIZE If the size passed is lower than the HMAC length.
404  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
405  */
406 TSS2_RC
iesys_cryptossl_hmac_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,uint8_t * buffer,size_t * size)407 iesys_cryptossl_hmac_finish(IESYS_CRYPTO_CONTEXT_BLOB ** context,
408                             uint8_t * buffer, size_t * size)
409 {
410 
411     TSS2_RC r = TSS2_RC_SUCCESS;
412 
413     LOG_TRACE("called for context-pointer %p, buffer %p and size-pointer %p",
414               context, buffer, size);
415     if (context == NULL || *context == NULL || buffer == NULL || size == NULL) {
416         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Null-Pointer passed");
417     }
418     IESYS_CRYPTOSSL_CONTEXT *mycontext =
419         (IESYS_CRYPTOSSL_CONTEXT *) * context;
420     if (mycontext->type != IESYS_CRYPTOSSL_TYPE_HMAC) {
421         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "bad context");
422     }
423 
424     if (*size < mycontext->hmac.hmac_len) {
425         return_error(TSS2_ESYS_RC_BAD_SIZE, "Buffer too small");
426     }
427 
428     if (1 != EVP_DigestSignFinal(mycontext->hmac.ossl_context, buffer, size)) {
429         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "DigestSignFinal", cleanup);
430     }
431 
432     LOGBLOB_TRACE(buffer, *size, "read hmac result");
433 
434  cleanup:
435     EVP_MD_CTX_destroy(mycontext->hmac.ossl_context);
436     SAFE_FREE(mycontext);
437     *context = NULL;
438     return r;
439 }
440 
441 /** Write the HMAC digest value to a TPM2B object and close the context.
442  *
443  * The digest value will written to a passed TPM2B object and the resources of
444  * the HMAC object are released.
445  * @param[in,out] context The context of the HMAC object.
446  * @param[out] hmac The buffer for the digest value (caller-allocated).
447  * @retval TSS2_RC_SUCCESS on success.
448  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters.
449  * @retval TSS2_ESYS_RC_BAD_SIZE if the size passed is lower than the HMAC length.
450  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
451  */
452 TSS2_RC
iesys_cryptossl_hmac_finish2b(IESYS_CRYPTO_CONTEXT_BLOB ** context,TPM2B * hmac)453 iesys_cryptossl_hmac_finish2b(IESYS_CRYPTO_CONTEXT_BLOB ** context, TPM2B * hmac)
454 {
455     LOG_TRACE("called for context-pointer %p and 2b-pointer %p", context, hmac);
456     if (context == NULL || *context == NULL || hmac == NULL) {
457         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Null-Pointer passed");
458     }
459     size_t s = hmac->size;
460     TSS2_RC ret = iesys_cryptossl_hmac_finish(context, &hmac->buffer[0], &s);
461     hmac->size = s;
462     return ret;
463 }
464 
465 /** Release the resources of an HAMC object.
466  *
467  * The assigned resources will be released and the context will be set to NULL.
468  * @param[in,out] context The context of the HMAC object.
469  */
470 void
iesys_cryptossl_hmac_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)471 iesys_cryptossl_hmac_abort(IESYS_CRYPTO_CONTEXT_BLOB ** context)
472 {
473     LOG_TRACE("called for context-pointer %p", context);
474     if (context == NULL || *context == NULL) {
475         LOG_DEBUG("Null-Pointer passed");
476         return;
477     }
478     if (*context != NULL) {
479         IESYS_CRYPTOSSL_CONTEXT *mycontext =
480             (IESYS_CRYPTOSSL_CONTEXT *) * context;
481         if (mycontext->type != IESYS_CRYPTOSSL_TYPE_HMAC) {
482             LOG_DEBUG("bad context");
483             return;
484         }
485 
486         EVP_MD_CTX_destroy(mycontext->hmac.ossl_context);
487 
488         free(mycontext);
489         *context = NULL;
490     }
491 }
492 
493 /** Compute random TPM2B data.
494  *
495  * The random data will be generated and written to a passed TPM2B structure.
496  * @param[out] nonce The TPM2B structure for the random data (caller-allocated).
497  * @param[in] num_bytes The number of bytes to be generated.
498  * @retval TSS2_RC_SUCCESS on success.
499  *
500  * NOTE: the TPM should not be used to obtain the random data
501  */
502 TSS2_RC
iesys_cryptossl_random2b(TPM2B_NONCE * nonce,size_t num_bytes)503 iesys_cryptossl_random2b(TPM2B_NONCE * nonce, size_t num_bytes)
504 {
505     const RAND_METHOD *rand_save = RAND_get_rand_method();
506 
507     if (num_bytes == 0) {
508         nonce->size = sizeof(TPMU_HA);
509     } else {
510         nonce->size = num_bytes;
511     }
512 
513 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
514     RAND_set_rand_method(RAND_OpenSSL());
515 #else
516     RAND_set_rand_method(RAND_SSLeay());
517 #endif
518     if (1 != RAND_bytes(&nonce->buffer[0], nonce->size)) {
519         RAND_set_rand_method(rand_save);
520         return_error(TSS2_ESYS_RC_GENERAL_FAILURE,
521                      "Failure in random number generator.");
522     }
523     RAND_set_rand_method(rand_save);
524     return TSS2_RC_SUCCESS;
525 }
526 
527 /** Encryption of a buffer using a public (RSA) key.
528  *
529  * Encrypting a buffer using a public key is used for example during
530  * Esys_StartAuthSession in order to encrypt the salt value.
531  * @param[in] key The key to be used for encryption.
532  * @param[in] in_size The size of the buffer to be encrypted.
533  * @param[in] in_buffer The data buffer to be encrypted.
534  * @param[in] max_out_size The maximum size for the output encrypted buffer.
535  * @param[out] out_buffer The encrypted buffer.
536  * @param[out] out_size The size of the encrypted output.
537  * @param[in] label The label used in the encryption scheme.
538  * @retval TSS2_RC_SUCCESS on success
539  * @retval TSS2_ESYS_RC_BAD_VALUE The algorithm of key is not implemented.
540  * @retval TSS2_ESYS_RC_GENERAL_FAILURE The internal crypto engine failed.
541  */
542 TSS2_RC
iesys_cryptossl_pk_encrypt(TPM2B_PUBLIC * pub_tpm_key,size_t in_size,BYTE * in_buffer,size_t max_out_size,BYTE * out_buffer,size_t * out_size,const char * label)543 iesys_cryptossl_pk_encrypt(TPM2B_PUBLIC * pub_tpm_key,
544                            size_t in_size,
545                            BYTE * in_buffer,
546                            size_t max_out_size,
547                            BYTE * out_buffer,
548                            size_t * out_size, const char *label)
549 {
550     const RAND_METHOD *rand_save = RAND_get_rand_method();
551 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
552     RAND_set_rand_method(RAND_OpenSSL());
553 #else
554     RAND_set_rand_method(RAND_SSLeay());
555 #endif
556 
557     TSS2_RC r = TSS2_RC_SUCCESS;
558     const EVP_MD * hashAlg = NULL;
559     RSA * rsa_key = NULL;
560     EVP_PKEY *evp_rsa_key = NULL;
561     EVP_PKEY_CTX *ctx = NULL;
562     BIGNUM* bne = NULL;
563     int padding;
564     char *label_copy = NULL;
565 
566     if (!(hashAlg = get_ossl_hash_md(pub_tpm_key->publicArea.nameAlg))) {
567         LOG_ERROR("Unsupported hash algorithm (%"PRIu16")",
568                   pub_tpm_key->publicArea.nameAlg);
569         RAND_set_rand_method(rand_save);
570         return TSS2_ESYS_RC_NOT_IMPLEMENTED;
571     }
572 
573     if (!(bne = BN_new())) {
574         goto_error(r, TSS2_ESYS_RC_MEMORY,
575                    "Could not allocate Big Number", cleanup);
576     }
577 
578     switch (pub_tpm_key->publicArea.parameters.rsaDetail.scheme.scheme) {
579     case TPM2_ALG_NULL:
580         padding = RSA_NO_PADDING;
581         break;
582     case TPM2_ALG_RSAES:
583         padding = RSA_PKCS1_PADDING;
584         break;
585     case TPM2_ALG_OAEP:
586         padding = RSA_PKCS1_OAEP_PADDING;
587         break;
588     default:
589         goto_error(r, TSS2_ESYS_RC_BAD_VALUE, "Illegal RSA scheme", cleanup);
590     }
591 
592     UINT32 exp;
593     if (pub_tpm_key->publicArea.parameters.rsaDetail.exponent == 0)
594         exp = 65537;
595     else
596         exp = pub_tpm_key->publicArea.parameters.rsaDetail.exponent;
597     if (1 != BN_set_word(bne, exp)) {
598         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
599                    "Could not set exponent.", cleanup);
600     }
601 
602     if (!(rsa_key = RSA_new())) {
603         goto_error(r, TSS2_ESYS_RC_MEMORY,
604                    "Could not allocate RSA key", cleanup);
605     }
606 
607     if (1 != RSA_generate_key_ex(rsa_key,
608                                  pub_tpm_key->publicArea.parameters.rsaDetail.keyBits,
609                                  bne, NULL)) {
610         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Could not generate RSA key",
611                    cleanup);
612     }
613 
614     if (!(evp_rsa_key = EVP_PKEY_new())) {
615         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
616                    "Could not create evp key.", cleanup);
617     }
618 #if OPENSSL_VERSION_NUMBER < 0x10100000L
619     if (!BN_bin2bn(pub_tpm_key->publicArea.unique.rsa.buffer,
620                            pub_tpm_key->publicArea.unique.rsa.size,
621                            rsa_key->n)) {
622         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
623                    "Could not create rsa n.", cleanup);
624     }
625 #else
626     BIGNUM *n = NULL;
627     if (!(n = BN_bin2bn(pub_tpm_key->publicArea.unique.rsa.buffer,
628                         pub_tpm_key->publicArea.unique.rsa.size,
629                         NULL))) {
630         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
631                    "Could not create rsa n.", cleanup);
632     }
633 
634     if (1 != RSA_set0_key(rsa_key, n, NULL, NULL)) {
635         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
636                    "Could not set rsa n.", cleanup);
637     }
638 #endif
639 
640     if (1 != EVP_PKEY_set1_RSA(evp_rsa_key, rsa_key)) {
641         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
642                    "Could not set rsa key.", cleanup);
643     }
644 
645     if (!(ctx = EVP_PKEY_CTX_new(evp_rsa_key, NULL))) {
646         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
647                    "Could not create evp context.", cleanup);
648     }
649 
650     if (1 != EVP_PKEY_encrypt_init(ctx)) {
651         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
652                    "Could not init encrypt context.", cleanup);
653     }
654 
655     if (1 != EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) {
656         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
657                    "Could not set RSA passing.", cleanup);
658     }
659 
660     label_copy = OPENSSL_strdup(label);
661     if (!label_copy) {
662         goto_error(r, TSS2_ESYS_RC_MEMORY,
663                    "Could not duplicate OAEP label", cleanup);
664     }
665 
666     if (1 != EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label_copy, strlen(label_copy)+1)) {
667         OPENSSL_free(label_copy);
668         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
669                    "Could not set RSA label.", cleanup);
670     }
671 
672     if (1 != EVP_PKEY_CTX_set_rsa_oaep_md(ctx, hashAlg)) {
673         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
674                    "Could not set hash algorithm.", cleanup);
675     }
676 
677     /* Determine out size */
678     if (1 != EVP_PKEY_encrypt(ctx, NULL, out_size, in_buffer, in_size)) {
679         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
680                    "Could not determine ciper size.", cleanup);
681     }
682 
683     if ((size_t)*out_size > max_out_size) {
684         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
685                    "Encrypted data too big", cleanup);
686     }
687 
688     /* Encrypt data */
689     if (1 != EVP_PKEY_encrypt(ctx, out_buffer, out_size, in_buffer, in_size)) {
690         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
691                    "Could not encrypt data.", cleanup);
692     }
693 
694     r = TSS2_RC_SUCCESS;
695 
696  cleanup:
697     OSSL_FREE(ctx, EVP_PKEY_CTX);
698     OSSL_FREE(evp_rsa_key, EVP_PKEY);
699     OSSL_FREE(rsa_key, RSA);
700     OSSL_FREE(bne, BN);
701     RAND_set_rand_method(rand_save);
702     return r;
703 }
704 
705 /** Computation of OSSL ec public point from TPM public point.
706  *
707  * @param[in] group The definition of the used ec curve.
708  * @param[in] key The TPM public key.
709  * @param[out] The TPM's public point in OSSL format.
710  * @retval TSS2_RC_SUCCESS on success.
711  * @retval TSS2_ESYS_RC_GENERAL_FAILURE The internal crypto engine failed.
712  */
713 static TSS2_RC
tpm_pub_to_ossl_pub(EC_GROUP * group,TPM2B_PUBLIC * key,EC_POINT ** tpm_pub_key)714 tpm_pub_to_ossl_pub(EC_GROUP *group, TPM2B_PUBLIC *key, EC_POINT **tpm_pub_key)
715 {
716 
717     TSS2_RC r = TSS2_RC_SUCCESS;
718     BIGNUM *bn_x = NULL;
719     BIGNUM *bn_y = NULL;
720 
721     /* Create the big numbers for the coordinates of the point */
722     if (!(bn_x = BN_bin2bn(&key->publicArea.unique.ecc.x.buffer[0],
723                            key->publicArea.unique.ecc.x.size,
724                            NULL))) {
725         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
726                    "Create big num from byte buffer.", cleanup);
727     }
728 
729     if (!(bn_y = BN_bin2bn(&key->publicArea.unique.ecc.y.buffer[0],
730                            key->publicArea.unique.ecc.y.size,
731                            NULL))) {
732         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
733                    "Create big num from byte buffer.", cleanup);
734     }
735 
736     /* Create the ec point with the affine coordinates of the TPM point */
737     if (!(*tpm_pub_key = EC_POINT_new(group))) {
738         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
739                    "Create point.", cleanup);
740     }
741 
742     if (1 != EC_POINT_set_affine_coordinates_GFp(group,
743                                                  *tpm_pub_key, bn_x,
744                                                  bn_y, NULL)) {
745         OSSL_FREE(*tpm_pub_key, EC_POINT);
746         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
747                    "Set affine coordinates", cleanup);
748     }
749 
750     if (1 != EC_POINT_is_on_curve(group, *tpm_pub_key, NULL)) {
751         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
752                    "The TPM point is not on the curve", cleanup);
753     }
754 
755  cleanup:
756     OSSL_FREE(bn_x, BN);
757     OSSL_FREE(bn_y, BN);
758 
759     return r;
760 }
761 
762 /** Computation of ephemeral ECC key and shared secret Z.
763  *
764  * According to the description in  TPM spec part 1 C 6.1 a shared secret
765  * between application and TPM is computed (ECDH). An ephemeral ECC key and a
766  * TPM keyare used for the ECDH key exchange.
767  * @param[in] key The key to be used for ECDH key exchange.
768  * @param[in] max_out_size the max size for the output of the public key of the
769  *            computed ephemeral key.
770  * @param[out] Z The computed shared secret.
771  * @param[out] Q The public part of the ephemeral key in TPM format.
772  * @param[out] out_buffer The public part of the ephemeral key will be marshaled
773  *             to this buffer.
774  * @param[out] out_size The size of the marshaled output.
775  * @retval TSS2_RC_SUCCESS on success
776  * @retval TSS2_ESYS_RC_BAD_VALUE The algorithm of key is not implemented.
777  * @retval TSS2_ESYS_RC_GENERAL_FAILURE The internal crypto engine failed.
778  */
779 TSS2_RC
iesys_cryptossl_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)780 iesys_cryptossl_get_ecdh_point(TPM2B_PUBLIC *key,
781                                size_t max_out_size,
782                                TPM2B_ECC_PARAMETER *Z,
783                                TPMS_ECC_POINT *Q,
784                                BYTE * out_buffer,
785                                size_t * out_size)
786 {
787     TSS2_RC r = TSS2_RC_SUCCESS;
788     EC_GROUP *group = NULL;               /* Group defines the used curve */
789     EC_KEY *eph_ec_key = NULL;            /* Ephemeral ec key of application */
790     const EC_POINT *eph_pub_key = NULL;   /* Public part of ephemeral key */
791     EC_POINT *tpm_pub_key = NULL;         /* Public part of TPM key */
792     EC_POINT *mul_eph_tpm = NULL;
793     BIGNUM *bn_x = NULL;
794     BIGNUM *bn_y = NULL;
795     size_t key_size;
796     int curveId;
797     size_t offset;
798 
799     /* Set ossl constant for curve type and create group for curve */
800     switch (key->publicArea.parameters.eccDetail.curveID) {
801     case TPM2_ECC_NIST_P192:
802         curveId = NID_X9_62_prime192v1;
803         key_size = 24;
804         break;
805     case TPM2_ECC_NIST_P224:
806         curveId = NID_secp224r1;
807         key_size = 28;
808         break;
809     case TPM2_ECC_NIST_P256:
810         curveId = NID_X9_62_prime256v1;
811         key_size = 32;
812         break;
813     case TPM2_ECC_NIST_P384:
814         curveId = NID_secp384r1;
815         key_size = 48;
816         break;
817     case TPM2_ECC_NIST_P521:
818         curveId = NID_secp521r1;
819         key_size = 66;
820         break;
821     default:
822         return_error(TSS2_ESYS_RC_NOT_IMPLEMENTED,
823                      "ECC curve not implemented.");
824     }
825 
826     if (!(group = EC_GROUP_new_by_curve_name(curveId))) {
827         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
828                    "Create group for curve", cleanup);
829     }
830 
831     /* Create ephemeral key */
832     if (!(eph_ec_key = EC_KEY_new())) {
833         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
834                    "Create ec key", cleanup);
835     }
836     if (1 !=   EC_KEY_set_group(eph_ec_key , group)) {
837 
838         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Set group", cleanup);
839     }
840 
841     if (1 != EC_KEY_generate_key(eph_ec_key)) {
842         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Generate ec key", cleanup);
843     }
844 
845     if (!(eph_pub_key =  EC_KEY_get0_public_key(eph_ec_key))) {
846         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Get public key", cleanup);
847     }
848 
849     if (1 != EC_POINT_is_on_curve(group, eph_pub_key, NULL)) {
850         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
851                    "Ephemeral public key is on curve",cleanup);
852     }
853 
854     /* Write affine coordinates of ephemeral pub key to TPM point Q */
855     if (!(bn_x = BN_new())) {
856         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Create bignum", cleanup);
857     }
858 
859     if (!(bn_y = BN_new())) {
860         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Create bignum", cleanup);
861     }
862 
863     if (1 != EC_POINT_get_affine_coordinates_GFp(group, eph_pub_key, bn_x,
864                                                  bn_y, NULL)) {
865         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
866                    "Get affine x coordinate", cleanup);
867     }
868 
869     if (1 != iesys_bn2binpad(bn_x, &Q->x.buffer[0], key_size)) {
870         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
871                    "Write big num byte buffer", cleanup);
872     }
873 
874     if (1 != iesys_bn2binpad(bn_y, &Q->y.buffer[0], key_size)) {
875         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
876                    "Write big num byte buffer", cleanup);
877     }
878 
879     Q->x.size = key_size;
880     Q->y.size = key_size;
881 
882     /* Create an OSSL EC point from the TPM public point */
883     r = tpm_pub_to_ossl_pub(group, key, &tpm_pub_key);
884     goto_if_error(r, "Convert TPM pub point to ossl pub point", cleanup);
885 
886     /* Multiply the ephemeral private key with TPM public key */
887     const BIGNUM * eph_priv_key = EC_KEY_get0_private_key(eph_ec_key);
888 
889     if (!(mul_eph_tpm = EC_POINT_new(group))) {
890         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Create point.", cleanup);
891     }
892 
893     if (1 != EC_POINT_mul(group, mul_eph_tpm, NULL,
894                           tpm_pub_key, eph_priv_key, NULL)) {
895         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
896                    "ec point multiplication", cleanup);
897     }
898 
899     /* Write the x-part of the affine coordinate to Z */
900     if (1 != EC_POINT_get_affine_coordinates_GFp(group, mul_eph_tpm, bn_x,
901                                                  bn_y, NULL)) {
902         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
903                    "Get affine x coordinate", cleanup);
904     }
905 
906     if (1 != iesys_bn2binpad(bn_x, &Z->buffer[0], key_size)) {
907         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
908                    "Write big num byte buffer", cleanup);
909     }
910 
911     Z->size = key_size;
912 
913     /* Write the public ephemeral key in TPM format to out buffer */
914     offset = 0;
915     r = Tss2_MU_TPMS_ECC_POINT_Marshal(Q,  &out_buffer[0], max_out_size, &offset);
916     goto_if_error(r, "Error marshaling", cleanup);
917     *out_size = offset;
918 
919  cleanup:
920     OSSL_FREE(mul_eph_tpm, EC_POINT);
921     OSSL_FREE(tpm_pub_key, EC_POINT);
922     OSSL_FREE(group,EC_GROUP);
923     OSSL_FREE(eph_ec_key, EC_KEY);
924     /* Note: free of eph_pub_key already done by free of eph_ec_key */
925     OSSL_FREE(bn_x, BN);
926     OSSL_FREE(bn_y, BN);
927     return r;
928 }
929 
930 /** Encrypt data with AES.
931  *
932  * @param[in] key key used for AES.
933  * @param[in] tpm_sym_alg AES type in TSS2 notation (must be TPM2_ALG_AES).
934  * @param[in] key_bits Key size in bits.
935  * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB).
936  *            For parameter encryption only CFB can be used.
937  * @param[in] blk_len Length Block length of AES.
938  * @param[in,out] buffer Data to be encrypted. The encrypted date will be stored
939  *                in this buffer.
940  * @param[in] buffer_size size of data to be encrypted.
941  * @param[in] iv The initialization vector. The size is equal to blk_len.
942  * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and
943  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters,
944  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
945  */
946 TSS2_RC
iesys_cryptossl_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)947 iesys_cryptossl_sym_aes_encrypt(uint8_t * key,
948                                 TPM2_ALG_ID tpm_sym_alg,
949                                 TPMI_AES_KEY_BITS key_bits,
950                                 TPM2_ALG_ID tpm_mode,
951                                 size_t blk_len,
952                                 uint8_t * buffer,
953                                 size_t buffer_size,
954                                 uint8_t * iv)
955 {
956     TSS2_RC r = TSS2_RC_SUCCESS;
957     const EVP_CIPHER  *cipher_alg = NULL;
958     EVP_CIPHER_CTX *ctx = NULL;
959     int cipher_len;
960 
961     if (key == NULL || buffer == NULL) {
962         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Bad reference");
963     }
964 
965     LOGBLOB_TRACE(buffer, buffer_size, "IESYS AES input");
966 
967     /* Parameter blk_len needed for other crypto libraries */
968     (void)blk_len;
969 
970     if (key_bits == 128 && tpm_mode == TPM2_ALG_CFB)
971         cipher_alg = EVP_aes_128_cfb();
972     else if (key_bits == 192 && tpm_mode == TPM2_ALG_CFB)
973         cipher_alg = EVP_aes_192_cfb();
974     else if (key_bits == 256 && tpm_mode == TPM2_ALG_CFB)
975         cipher_alg = EVP_aes_256_cfb();
976     else {
977         goto_error(r, TSS2_ESYS_RC_BAD_VALUE,
978                    "AES algorithm not implemented or illegal mode (CFB expected).",
979                    cleanup);
980     }
981 
982     if (tpm_sym_alg != TPM2_ALG_AES) {
983         goto_error(r, TSS2_ESYS_RC_BAD_VALUE,
984                    "AES encrypt called with wrong algorithm.", cleanup);
985     }
986 
987     /* Create and initialize the context */
988     if(!(ctx = EVP_CIPHER_CTX_new())) {
989         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
990                    "Initialize cipher context", cleanup);
991     }
992 
993     if (1 != EVP_EncryptInit_ex(ctx, cipher_alg, NULL, key, iv)) {
994         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
995                    "Initialize cipher operation", cleanup);
996     }
997     if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) {
998         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Set key and iv", cleanup);
999     }
1000 
1001     /* Perform the encryption */
1002     if (1 != EVP_EncryptUpdate(ctx, buffer, &cipher_len, buffer, buffer_size)) {
1003         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt update", cleanup);
1004     }
1005 
1006     if (1 != EVP_EncryptFinal_ex(ctx, buffer, &cipher_len)) {
1007         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt final", cleanup);
1008     }
1009     LOGBLOB_TRACE(buffer, buffer_size, "IESYS AES output");
1010 
1011  cleanup:
1012 
1013     OSSL_FREE(ctx,EVP_CIPHER_CTX);
1014 
1015     return r;
1016 }
1017 
1018 /** Decrypt data with AES.
1019  *
1020  * @param[in] key key used for AES.
1021  * @param[in] tpm_sym_alg AES type in TSS2 notation (must be TPM2_ALG_AES).
1022  * @param[in] key_bits Key size in bits.
1023  * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB).
1024  *            For parameter encryption only CFB can be used.
1025  * @param[in] blk_len Length Block length of AES.
1026  * @param[in,out] buffer Data to be decrypted. The decrypted date will be stored
1027  *                in this buffer.
1028  * @param[in] buffer_size size of data to be encrypted.
1029  * @param[in] iv The initialization vector. The size is equal to blk_len.
1030  * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and
1031  * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters,
1032  * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library.
1033  */
1034 TSS2_RC
iesys_cryptossl_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)1035 iesys_cryptossl_sym_aes_decrypt(uint8_t * key,
1036                                 TPM2_ALG_ID tpm_sym_alg,
1037                                 TPMI_AES_KEY_BITS key_bits,
1038                                 TPM2_ALG_ID tpm_mode,
1039                                 size_t blk_len,
1040                                 uint8_t * buffer,
1041                                 size_t buffer_size,
1042                                 uint8_t * iv)
1043 {
1044     TSS2_RC r = TSS2_RC_SUCCESS;
1045     const EVP_CIPHER *cipher_alg = NULL;
1046     EVP_CIPHER_CTX *ctx = NULL;
1047     int cipher_len = 0;
1048 
1049     /* Parameter blk_len needed for other crypto libraries */
1050     (void)blk_len;
1051 
1052     if (key == NULL || buffer == NULL) {
1053         return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Bad reference");
1054     }
1055 
1056     if (tpm_sym_alg != TPM2_ALG_AES) {
1057         goto_error(r, TSS2_ESYS_RC_BAD_VALUE,
1058                    "AES encrypt called with wrong algorithm.", cleanup);
1059     }
1060 
1061     if (key_bits == 128 && tpm_mode == TPM2_ALG_CFB)
1062         cipher_alg = EVP_aes_128_cfb();
1063     else if (key_bits == 192 && tpm_mode == TPM2_ALG_CFB)
1064         cipher_alg = EVP_aes_192_cfb();
1065     else if (key_bits == 256 && tpm_mode == TPM2_ALG_CFB)
1066         cipher_alg = EVP_aes_256_cfb();
1067     else {
1068 
1069         goto_error(r, TSS2_ESYS_RC_NOT_IMPLEMENTED,
1070                    "AES algorithm not implemented.", cleanup);
1071     }
1072 
1073     /* Create and initialize the context */
1074     if(!(ctx = EVP_CIPHER_CTX_new())) {
1075         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
1076                    "Initialize cipher context", cleanup);
1077     }
1078 
1079     LOGBLOB_TRACE(buffer, buffer_size, "IESYS AES input");
1080 
1081     if (1 != EVP_DecryptInit_ex(ctx, cipher_alg, NULL, key, iv)) {
1082         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE,
1083                    "Initialize cipher operation", cleanup);
1084     }
1085 
1086     if (1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) {
1087         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Set key and iv", cleanup);
1088     }
1089 
1090     /* Perform the decryption */
1091     if (1 != EVP_DecryptUpdate(ctx, buffer, &cipher_len, buffer, buffer_size)) {
1092         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt update", cleanup);
1093     }
1094 
1095     if (1 != EVP_DecryptFinal_ex(ctx, buffer, &cipher_len)) {
1096         goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt final", cleanup);
1097     }
1098     LOGBLOB_TRACE(buffer, buffer_size, "IESYS AES output");
1099 
1100  cleanup:
1101 
1102     OSSL_FREE(ctx,EVP_CIPHER_CTX);
1103     return r;
1104 }
1105 
1106 
1107 /** Initialize OpenSSL crypto backend.
1108  *
1109  * Initialize OpenSSL internal tables.
1110  *
1111  * @retval TSS2_RC_SUCCESS always returned because OpenSSL_add_all_algorithms
1112  * does not deliver
1113  * a return code.
1114  */
1115 TSS2_RC
iesys_cryptossl_init()1116 iesys_cryptossl_init() {
1117     ENGINE_load_builtin_engines();
1118     OpenSSL_add_all_algorithms();
1119     return TSS2_RC_SUCCESS;
1120 }
1121