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