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 "fapi_policy.h"
21 #include "tss2_esys.h"
22 #define LOGMODULE fapi
23 #include "util/log.h"
24 #include "util/aux_util.h"
25 #include "fapi_crypto.h"
26
27 /** One-Call function for Fapi_Sign
28 *
29 * Uses a key, identified by its path, to sign a digest and puts the result in a
30 * TPM2B bytestream.
31 *
32 * @param[in,out] context The FAPI_CONTEXT
33 * @param[in] keyPath The path of the signature key
34 * @param[in] padding A padding algorithm. Must be either "RSA_SSA" or
35 * "RSA_PSS" or NULL
36 * @param[in] digest The digest to sign. Must be already hashed
37 * @param[in] digestSize The size of the digest in bytes
38 * @param[out] signature The signature
39 * @param[out] signatureSize The size of signature in bytes. May be NULL
40 * @param[out] publicKey The public key that can be used to verify signature
41 * in PEM format. May be NULL
42 * @param[out] certificate The certificate associated with the signing key in PEM
43 * format. May be NULL
44 *
45 * @retval TSS2_RC_SUCCESS: if the function call was a success.
46 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, keyPath, digest or signature
47 * is NULL.
48 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
49 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if keyPath does not map to a FAPI key.
50 * @retval TSS2_FAPI_RC_BAD_KEY: if the object at keyPath is not a key, or is a
51 * key that is unsuitable for the requested operation.
52 * @retval TSS2_FAPI_RC_BAD_VALUE: if the digestSize is zero.
53 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
54 * operation already pending.
55 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
56 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
57 * internal operations or return parameters.
58 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
59 * config file.
60 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
61 * this function needs to be called again.
62 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
63 * during authorization.
64 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
65 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
66 * is not set.
67 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
68 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
69 * was not successful.
70 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
71 */
72 TSS2_RC
Fapi_Sign(FAPI_CONTEXT * context,char const * keyPath,char const * padding,uint8_t const * digest,size_t digestSize,uint8_t ** signature,size_t * signatureSize,char ** publicKey,char ** certificate)73 Fapi_Sign(
74 FAPI_CONTEXT *context,
75 char const *keyPath,
76 char const *padding,
77 uint8_t const *digest,
78 size_t digestSize,
79 uint8_t **signature,
80 size_t *signatureSize,
81 char **publicKey,
82 char **certificate)
83 {
84 LOG_TRACE("called for context:%p", context);
85
86 TSS2_RC r, r2;
87
88 /* Check for NULL parameters */
89 check_not_null(context);
90 check_not_null(keyPath);
91 check_not_null(digest);
92 check_not_null(signature);
93
94 /* Check whether TCTI and ESYS are initialized */
95 return_if_null(context->esys, "Command can't be executed in none TPM mode.",
96 TSS2_FAPI_RC_NO_TPM);
97
98 /* If the async state automata of FAPI shall be tested, then we must not set
99 the timeouts of ESYS to blocking mode.
100 During testing, the mssim tcti will ensure multiple re-invocations.
101 Usually however the synchronous invocations of FAPI shall instruct ESYS
102 to block until a result is available. */
103 #ifndef TEST_FAPI_ASYNC
104 r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
105 return_if_error_reset_state(r, "Set Timeout to blocking");
106 #endif /* TEST_FAPI_ASYNC */
107
108 r = Fapi_Sign_Async(context, keyPath, padding, digest, digestSize);
109 return_if_error_reset_state(r, "Key_Sign");
110
111 do {
112 /* We wait for file I/O to be ready if the FAPI state automata
113 are in a file I/O state. */
114 r = ifapi_io_poll(&context->io);
115 return_if_error(r, "Something went wrong with IO polling");
116
117 /* Repeatedly call the finish function, until FAPI has transitioned
118 through all execution stages / states of this invocation. */
119 r = Fapi_Sign_Finish(context, signature, signatureSize, publicKey,
120 certificate);
121 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
122
123 /* Reset the ESYS timeout to non-blocking, immediate response. */
124 r2 = Esys_SetTimeout(context->esys, 0);
125 return_if_error(r2, "Set Timeout to non-blocking");
126
127 return_if_error_reset_state(r, "Key_Sign");
128
129 LOG_TRACE("finished");
130 return TSS2_RC_SUCCESS;
131 }
132
133 /** Asynchronous function for Fapi_Sign
134 *
135 * Uses a key, identified by its path, to sign a digest and puts the result in a
136 * TPM2B bytestream.
137 *
138 * Call Fapi_Sign_Finish to finish the execution of this command.
139 *
140 * @param[in,out] context The FAPI_CONTEXT
141 * @param[in] keyPath The path of the signature key
142 * @param[in] padding A padding algorithm. Must be either "RSA_SSA" or
143 * "RSA_PSS" or NULL
144 * @param[in] digest The digest to sign. Must be already hashed
145 * @param[in] digestSize The size of the digest in bytes
146 *
147 * @retval TSS2_RC_SUCCESS: if the function call was a success.
148 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, keyPath or digest
149 * is NULL.
150 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
151 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if keyPath does not map to a FAPI key.
152 * @retval TSS2_FAPI_RC_BAD_KEY: if the object at keyPath is not a key, or is a
153 * key that is unsuitable for the requested operation.
154 * @retval TSS2_FAPI_RC_BAD_VALUE: if the digestSize is zero.
155 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
156 * operation already pending.
157 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
158 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
159 * internal operations or return parameters.
160 * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
161 * config file.
162 */
163 TSS2_RC
Fapi_Sign_Async(FAPI_CONTEXT * context,char const * keyPath,char const * padding,uint8_t const * digest,size_t digestSize)164 Fapi_Sign_Async(
165 FAPI_CONTEXT *context,
166 char const *keyPath,
167 char const *padding,
168 uint8_t const *digest,
169 size_t digestSize)
170 {
171 LOG_TRACE("called for context:%p", context);
172 LOG_TRACE("keyPath: %s", keyPath);
173 LOG_TRACE("padding: %s", padding);
174 if (digest) {
175 LOGBLOB_TRACE(digest, digestSize, "digest");
176 } else {
177 LOG_TRACE("digest: (null) digestSize: %zi", digestSize);
178 }
179
180 TSS2_RC r;
181
182 /* Check for NULL parameters */
183 check_not_null(context);
184 check_not_null(keyPath);
185 check_not_null(digest);
186
187 /* Check for invalid parameters */
188 if (padding) {
189 if (strcasecmp("RSA_SSA", padding) != 0 &&
190 strcasecmp("RSA_PSS", padding) != 0) {
191 return_error(TSS2_FAPI_RC_BAD_VALUE,
192 "Only padding RSA_SSA or RSA_PSS allowed.");
193 }
194 }
195
196 /* Helpful alias pointers */
197 IFAPI_Key_Sign * command = &context->Key_Sign;
198
199 /* Reset all context-internal session state information. */
200 r = ifapi_session_init(context);
201 return_if_error(r, "Initialize Sign");
202
203 /* Copy parameters to context for use during _Finish. */
204 FAPI_COPY_DIGEST(&command->digest.buffer[0],
205 command->digest.size, digest, digestSize);
206 strdup_check(command->keyPath, keyPath, r, error_cleanup);
207 strdup_check(command->padding, padding, r, error_cleanup);
208
209 /* Initialize the context state for this operation. */
210 context->state = KEY_SIGN_WAIT_FOR_KEY;
211 LOG_TRACE("finished");
212 return TSS2_RC_SUCCESS;
213
214 error_cleanup:
215 /* Cleanup duplicated input parameters that were copied before. */
216 SAFE_FREE(command->keyPath);
217 SAFE_FREE(command->padding);
218 return r;
219 }
220
221 /** Asynchronous finish function for Fapi_Sign
222 *
223 * This function should be called after a previous Fapi_Sign_Async.
224 *
225 * @param[in,out] context The FAPI_CONTEXT
226 * @param[out] signature The signature
227 * @param[out] signatureSize The size of signature in bytes. May be NULL
228 * @param[out] publicKey The public key that can be used to verify signature
229 * in PEM format. May be NULL
230 * @param[out] certificate The certificate associated with the signing key in PEM
231 * format. May be NULL
232 *
233 * @retval TSS2_RC_SUCCESS: if the function call was a success.
234 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or signature is NULL.
235 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
236 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
237 * operation already pending.
238 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
239 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
240 * internal operations or return parameters.
241 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
242 * complete. Call this function again later.
243 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
244 * during authorization.
245 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND if a key was not found.
246 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
247 * the function.
248 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
249 * @retval TSS2_FAPI_RC_AUTHORIZATION_UNKNOWN if a required authorization callback
250 * is not set.
251 * @retval TSS2_FAPI_RC_AUTHORIZATION_FAILED if the authorization attempt fails.
252 * @retval TSS2_FAPI_RC_POLICY_UNKNOWN if policy search for a certain policy digest
253 * was not successful.
254 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
255 */
256 TSS2_RC
Fapi_Sign_Finish(FAPI_CONTEXT * context,uint8_t ** signature,size_t * signatureSize,char ** publicKey,char ** certificate)257 Fapi_Sign_Finish(
258 FAPI_CONTEXT *context,
259 uint8_t **signature,
260 size_t *signatureSize,
261 char **publicKey,
262 char **certificate)
263 {
264 LOG_TRACE("called for context:%p", context);
265
266 TSS2_RC r;
267 size_t resultSignatureSize;
268
269 /* Check for NULL parameters */
270 check_not_null(context);
271 check_not_null(signature);
272
273 /* Helpful alias pointers */
274 IFAPI_Key_Sign * command = &context->Key_Sign;
275
276 switch (context->state) {
277 statecase(context->state, KEY_SIGN_WAIT_FOR_KEY);
278 /* Load the key used for signing with a helper. */
279 r = ifapi_load_key(context, command->keyPath,
280 &command->key_object);
281 return_try_again(r);
282 goto_if_error(r, "Fapi load key.", error_cleanup);
283
284 fallthrough;
285
286 statecase(context->state, KEY_SIGN_WAIT_FOR_SIGN);
287 /* Perform the signing operation using a helper. */
288 r = ifapi_key_sign(context, command->key_object,
289 command->padding, &command->digest, &command->tpm_signature,
290 publicKey, certificate);
291 return_try_again(r);
292 goto_if_error(r, "Fapi sign.", error_cleanup);
293
294 /* Convert the TPM datatype signature to something useful for the caller. */
295 r = ifapi_tpm_to_fapi_signature(command->key_object,
296 command->tpm_signature, signature, &resultSignatureSize);
297 goto_if_error(r, "Create FAPI signature.", error_cleanup);
298
299 if (signatureSize)
300 *signatureSize = resultSignatureSize;
301 fallthrough;
302
303 statecase(context->state, KEY_SIGN_CLEANUP)
304 /* Cleanup the session used for authorization. */
305 r = ifapi_cleanup_session(context);
306 try_again_or_error_goto(r, "Cleanup", error_cleanup);
307
308 context->state = _FAPI_STATE_INIT;
309 break;
310
311 statecasedefault(context->state);
312 }
313
314 error_cleanup:
315 /* Cleanup any intermediate results and state stored in the context. */
316 SAFE_FREE(command->tpm_signature);
317 SAFE_FREE(command->keyPath);
318 SAFE_FREE(command->padding);
319 ifapi_session_clean(context);
320 ifapi_cleanup_ifapi_object(command->key_object);
321 ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
322 ifapi_cleanup_ifapi_object(context->loadKey.key_object);
323 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
324 LOG_TRACE("finished");
325 return r;
326 }
327