• 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 "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