• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3  * Copyright 2018-2019, 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 <stdlib.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include <errno.h>
15 #include <string.h>
16 
17 #include "tss2_fapi.h"
18 #include "fapi_int.h"
19 #include "fapi_util.h"
20 #include "tss2_esys.h"
21 #include "fapi_crypto.h"
22 #include "fapi_policy.h"
23 #include "ifapi_policyutil_execute.h"
24 #include "ifapi_json_deserialize.h"
25 #define LOGMODULE fapi
26 #include "util/log.h"
27 #include "util/aux_util.h"
28 
29 /** One-Call function for Fapi_Decrypt
30  *
31  * Decrypts data that was previously encrypted with Fapi_Encrypt.
32  *
33  * @param[in,out] context The FAPI_CONTEXT
34  * @param[in] keyPath The decryption key.
35  * @param[in] cipherText The ciphertext to decrypt.
36  * @param[in] cipherTextSize The size of the ciphertext to decrypt.
37  * @param[out] plainText the decrypted ciphertext. May be NULL
38  *             (callee-allocated)
39  * @param[out] plainTextSize The size of the ciphertext in bytes. May be NULL
40  *
41  * @retval TSS2_RC_SUCCESS: if the function call was a success.
42  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or cipherText is NULL.
43  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
44  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if can’t find the key necessary to decrypt
45  *         the file.
46  * @retval TSS2_FAPI_RC_BAD_KEY: if the decryption key is unsuitable for the
47  *         requested operation.
48  * @retval TSS2_FAPI_RC_BAD_VALUE: if the decryption fails
49  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
50  *         operation already pending.
51  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
52  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
53  *         internal operations or return parameters.
54  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
55  *         config file.
56  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
57  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
58  *         this function needs to be called again.
59  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
60  *         during authorization.
61  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
62  *         is not set.
63  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
64  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
65  *         was not successful.
66  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
67  */
68 TSS2_RC
Fapi_Decrypt(FAPI_CONTEXT * context,char const * keyPath,uint8_t const * cipherText,size_t cipherTextSize,uint8_t ** plainText,size_t * plainTextSize)69 Fapi_Decrypt(
70     FAPI_CONTEXT    *context,
71     char      const *keyPath,
72     uint8_t   const *cipherText,
73     size_t           cipherTextSize,
74     uint8_t        **plainText,
75     size_t          *plainTextSize)
76 {
77     LOG_TRACE("called for context:%p", context);
78 
79     TSS2_RC r, r2;
80 
81     /* Check for NULL parameters */
82     check_not_null(context);
83     check_not_null(keyPath);
84     check_not_null(cipherText);
85 
86     /* Check whether TCTI and ESYS are initialized */
87     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
88                    TSS2_FAPI_RC_NO_TPM);
89 
90     /* If the async state automata of FAPI shall be tested, then we must not set
91        the timeouts of ESYS to blocking mode.
92        During testing, the mssim tcti will ensure multiple re-invocations.
93        Usually however the synchronous invocations of FAPI shall instruct ESYS
94        to block until a result is available. */
95 #ifndef TEST_FAPI_ASYNC
96     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
97     return_if_error_reset_state(r, "Set Timeout to blocking");
98 #endif /* TEST_FAPI_ASYNC */
99 
100     r = Fapi_Decrypt_Async(context, keyPath, cipherText, cipherTextSize);
101     return_if_error_reset_state(r, "Data_Encrypt");
102 
103     do {
104         /* We wait for file I/O to be ready if the FAPI state automata
105            are in a file I/O state. */
106         r = ifapi_io_poll(&context->io);
107         return_if_error(r, "Something went wrong with IO polling");
108 
109         /* Repeatedly call the finish function, until FAPI has transitioned
110            through all execution stages / states of this invocation. */
111         r = Fapi_Decrypt_Finish(context, plainText, plainTextSize);
112     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
113 
114     /* Reset the ESYS timeout to non-blocking, immediate response. */
115     r2 = Esys_SetTimeout(context->esys, 0);
116     return_if_error(r2, "Set Timeout to non-blocking");
117 
118     return_if_error_reset_state(r, "Data_Decrypt");
119 
120     LOG_TRACE("finished");
121     return TSS2_RC_SUCCESS;
122 }
123 
124 /** Asynchronous function for Fapi_Decrypt
125  *
126  * Decrypts data that was previously encrypted with Fapi_Encrypt.
127  *
128  * Call Fapi_Decrypt_Finish to finish the execution of this command.
129  *
130  * @param[in,out] context The FAPI_CONTEXT
131  * @param[in] keyPath The decryption key.
132  * @param[in] cipherText The ciphertext to decrypt
133  * @param[in] cipherTextSize The size of the ciphertext to decrypt
134  *
135  * @retval TSS2_RC_SUCCESS: if the function call was a success.
136  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or cipherText is NULL.
137  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
138  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if can’t find the key necessary to decrypt
139  *         the file.
140  * @retval TSS2_FAPI_RC_BAD_KEY: if the decryption key is unsuitable for the
141  *         requested operation.
142  * @retval TSS2_FAPI_RC_BAD_VALUE: if the decryption fails
143  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
144  *         operation already pending.
145  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
146  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
147  *         internal operations or return parameters.
148  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
149  *         config file.
150  */
151 TSS2_RC
Fapi_Decrypt_Async(FAPI_CONTEXT * context,char const * keyPath,uint8_t const * cipherText,size_t cipherTextSize)152 Fapi_Decrypt_Async(
153     FAPI_CONTEXT  *context,
154     char    const *keyPath,
155     uint8_t const *cipherText,
156     size_t         cipherTextSize)
157 {
158     LOG_TRACE("called for context:%p", context);
159     LOG_TRACE("cipherText: %s", cipherText);
160 
161     TSS2_RC r;
162 
163     /* Check for NULL parameters */
164     check_not_null(context);
165     check_not_null(keyPath);
166     check_not_null(cipherText);
167 
168     /* Helpful alias pointers */
169     IFAPI_Data_EncryptDecrypt * command = &(context->cmd.Data_EncryptDecrypt);
170 
171     /* Reset all context-internal session state information. */
172     r = ifapi_session_init(context);
173     return_if_error(r, "Initialize Decrypt");
174 
175     command->object_handle = ESYS_TR_NONE;
176 
177     goto_if_error(r, "Invalid cipher object.", error_cleanup);
178 
179     /* Copy parameters to context for use during _Finish. */
180     uint8_t *inData = malloc(cipherTextSize);
181     goto_if_null(inData, "Out of memory", r, error_cleanup);
182     memcpy(inData, cipherText, cipherTextSize);
183     command->in_data = inData;
184     command->numBytes = cipherTextSize;
185     strdup_check(command->keyPath, keyPath, r, error_cleanup);
186 
187     /* Initialize the context state for this operation. */
188     context->state = DATA_DECRYPT_WAIT_FOR_PROFILE;
189 
190     LOG_TRACE("finished");
191     return r;
192 
193 error_cleanup:
194     SAFE_FREE(command->in_data);
195     SAFE_FREE(command->keyPath);
196     return r;
197 }
198 
199 /** Asynchronous finish function for Fapi_Decrypt
200  *
201  * This function should be called after a previous Fapi_Decrypt.
202  *
203  * @param[in,out] context The FAPI_CONTEXT
204  * @param[out] plainText the decrypted ciphertext. May be NULL
205  *             (callee-allocated)
206  * @param[out] plainTextSize The size of the ciphertext in bytes. May be NULL
207  *
208  * @retval TSS2_RC_SUCCESS: if the function call was a success.
209  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, plainText or plainTextSize
210  *         is NULL.
211  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
212  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
213  *         operation already pending.
214  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
215  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
216  *         internal operations or return parameters.
217  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
218  *         complete. Call this function again later.
219  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
220  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
221  *         the function.
222  * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
223  *         during authorization.
224  * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
225  * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
226  *         is not set.
227  * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
228  * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
229  *         was not successful.
230  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
231  */
232 TSS2_RC
Fapi_Decrypt_Finish(FAPI_CONTEXT * context,uint8_t ** plainText,size_t * plainTextSize)233 Fapi_Decrypt_Finish(
234     FAPI_CONTEXT *context,
235     uint8_t     **plainText,
236     size_t       *plainTextSize)
237 {
238     LOG_TRACE("called for context:%p", context);
239 
240     TSS2_RC r;
241     TPM2B_PUBLIC_KEY_RSA *tpmPlainText = NULL;
242 
243     /* Check for NULL parameters */
244     check_not_null(context);
245 
246     /* Helpful alias pointers */
247     IFAPI_OBJECT *encKeyObject = NULL;
248     IFAPI_Data_EncryptDecrypt * command = &(context->cmd.Data_EncryptDecrypt);
249 
250     switch (context->state) {
251         statecase(context->state, DATA_DECRYPT_WAIT_FOR_PROFILE);
252             /* Retrieve the profile for the provided key in order to get the
253                encryption scheme below. */
254             r = ifapi_profiles_get(&context->profiles, command->keyPath,
255                                    &command->profile);
256             return_try_again(r);
257             goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
258 
259             /* Initialize a session used for authorization and parameter encryption. */
260             r = ifapi_get_sessions_async(context,
261                                          IFAPI_SESSION_GENEK | IFAPI_SESSION1,
262                                          TPMA_SESSION_ENCRYPT | TPMA_SESSION_DECRYPT, 0);
263             goto_if_error_reset_state(r, "Create sessions", error_cleanup);
264 
265             fallthrough;
266 
267         statecase(context->state, DATA_DECRYPT_WAIT_FOR_SESSION);
268             r = ifapi_get_sessions_finish(context, &context->profiles.default_profile,
269                                           context->profiles.default_profile.nameAlg);
270             return_try_again(r);
271             goto_if_error_reset_state(r, " FAPI create session", error_cleanup);
272 
273             /* Load the key used for decryption. */
274             r = ifapi_load_keys_async(context, command->keyPath);
275             return_try_again(r);
276             goto_if_error(r, "Load keys.", error_cleanup);
277 
278             fallthrough;
279 
280         statecase(context->state, DATA_DECRYPT_WAIT_FOR_KEY);
281             r = ifapi_load_keys_finish(context, IFAPI_FLUSH_PARENT,
282                                        &command->key_handle,
283                                        &command->key_object);
284             return_try_again(r);
285             goto_if_error_reset_state(r, " Load key.", error_cleanup);
286 
287             encKeyObject = command->key_object;
288 
289             if (encKeyObject->misc.key.public.publicArea.type != TPM2_ALG_RSA &&
290                  encKeyObject->misc.key.public.publicArea.type != TPM2_ALG_ECC) {
291                 goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Invalid algorithm", error_cleanup);
292             }
293             fallthrough;
294 
295         statecase(context->state, DATA_DECRYPT_AUTHORIZE_KEY);
296             /* Authorize for the key with password or policy. */
297             r = ifapi_authorize_object(context, command->key_object, &command->auth_session);
298             return_try_again(r);
299             goto_if_error(r, "Authorize key.", error_cleanup);
300             TPM2B_DATA null_data = {.size = 0, .buffer = {} };
301 
302             /* Copy cipher data to tpm object */
303             TPM2B_PUBLIC_KEY_RSA *aux_data = (TPM2B_PUBLIC_KEY_RSA *)&context->aux_data;
304             aux_data->size = context->cmd.Data_EncryptDecrypt.numBytes;
305             memcpy(&aux_data->buffer[0], context->cmd.Data_EncryptDecrypt.in_data,
306                    aux_data->size);
307 
308             /* Decrypt the actual data. */
309             r = Esys_RSA_Decrypt_Async(context->esys,
310                                        context->cmd.Data_EncryptDecrypt.key_handle,
311                                        command->auth_session, ESYS_TR_NONE, ESYS_TR_NONE,
312                                        aux_data,
313                                        &command->profile->rsa_decrypt_scheme,
314                                        &null_data);
315             goto_if_error(r, "Error esys rsa decrypt", error_cleanup);
316 
317             fallthrough;
318 
319         statecase(context->state, DATA_DECRYPT_WAIT_FOR_RSA_DECRYPTION);
320             r = Esys_RSA_Decrypt_Finish(context->esys, &tpmPlainText);
321             return_try_again(r);
322             goto_if_error_reset_state(r, "RSA decryption.", error_cleanup);
323 
324             /* Duplicate the decrypted plaintext for returning to the user. */
325             if (plainTextSize)
326                 *plainTextSize = tpmPlainText->size;
327             if (plainText) {
328                 *plainText = malloc(tpmPlainText->size);
329                 goto_if_null(*plainText, "Out of memory", TSS2_FAPI_RC_MEMORY, error_cleanup);
330 
331                 memcpy(*plainText, &tpmPlainText->buffer[0], tpmPlainText->size);
332                 SAFE_FREE(tpmPlainText);
333             }
334 
335             /* Flush the used key. */
336             r = Esys_FlushContext_Async(context->esys,
337                                         command->key_handle);
338             goto_if_error(r, "Error: FlushContext", error_cleanup);
339 
340             fallthrough;
341 
342         statecase(context->state, DATA_DECRYPT_WAIT_FOR_FLUSH);
343             r = Esys_FlushContext_Finish(context->esys);
344             return_try_again(r);
345 
346             goto_if_error(r, "Error: FlushContext", error_cleanup);
347             command->key_handle = ESYS_TR_NONE;
348             fallthrough;
349 
350         statecase(context->state, DATA_DECRYPT_CLEANUP)
351             /* Cleanup session. */
352             r = ifapi_cleanup_session(context);
353             try_again_or_error_goto(r, "Cleanup", error_cleanup);
354 
355             break;
356 
357         statecasedefault(context->state);
358     }
359 
360     context->state = _FAPI_STATE_INIT;
361 
362     /* Cleanup of local objects */
363     SAFE_FREE(tpmPlainText);
364 
365     /* Cleanup of command related objects */
366     ifapi_cleanup_ifapi_object(command->key_object);
367     SAFE_FREE(command->keyPath);
368     SAFE_FREE(command->in_data);
369 
370     /* Cleanup of context related objects */
371     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
372     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
373 
374     LOG_TRACE("finished");
375     return TSS2_RC_SUCCESS;
376 
377 error_cleanup:
378     /* Cleanup of local objects */
379     SAFE_FREE(tpmPlainText);
380 
381     /* Cleanup of command related objects */
382     ifapi_cleanup_ifapi_object(command->key_object);
383     SAFE_FREE(command->keyPath);
384     SAFE_FREE(command->in_data);
385 
386     /* Cleanup of context related objects */
387     if (command->key_handle != ESYS_TR_NONE)
388         Esys_FlushContext(context->esys, command->key_handle);
389     ifapi_session_clean(context);
390     ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
391     ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
392     ifapi_cleanup_ifapi_object(context->loadKey.key_object);
393 
394     return r;
395 }
396