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 #define LOGMODULE fapi
23 #include "util/log.h"
24 #include "util/aux_util.h"
25
26 /** One-Call function for Fapi_VerifyQuote
27 *
28 * Verifies that the data returned by a quote is valid.
29 *
30 * @param[in,out] context The FAPI_CONTEXT
31 * @param[in] publicKeyPath The path to the signing key
32 * @param[in] qualifyingData The qualifying data nonce. May be NULL
33 * @param[in] qualifyingDataSize The size of qualifyingData in bytes. Must be 0
34 * if qualifyingData is NULL
35 * @param[in] quoteInfo The quote information
36 * @param[in] signature The quote's signature
37 * @param[in] signatureSize The size of signature in bytes
38 * @param[in] pcrLog The PCR's log. May be NULL
39 *
40 * @retval TSS2_RC_SUCCESS: if the function call was a success.
41 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, publicKeyPath, quoteInfo,
42 * or signature is NULL.
43 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
44 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if path does not map to a FAPI entity.
45 * @retval TSS2_FAPI_RC_BAD_KEY: if the entity at path is not a key, or is a key
46 * that is unsuitable for the requested operation.
47 * @retval TSS2_FAPI_RC_BAD_VALUE: if quoteInfo, pcrEventLog, qualifyingData, or
48 * signature is invalid.
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_PATH_NOT_FOUND if a FAPI object path was not found
55 * during authorization.
56 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
57 * this function needs to be called again.
58 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
59 * @retval TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED if the signature could not
60 * be verified
61 */
62 TSS2_RC
Fapi_VerifyQuote(FAPI_CONTEXT * context,char const * publicKeyPath,uint8_t const * qualifyingData,size_t qualifyingDataSize,char const * quoteInfo,uint8_t const * signature,size_t signatureSize,char const * pcrLog)63 Fapi_VerifyQuote(
64 FAPI_CONTEXT *context,
65 char const *publicKeyPath,
66 uint8_t const *qualifyingData,
67 size_t qualifyingDataSize,
68 char const *quoteInfo,
69 uint8_t const *signature,
70 size_t signatureSize,
71 char const *pcrLog)
72 {
73 LOG_TRACE("called for context:%p", context);
74
75 TSS2_RC r;
76
77 /* Check for NULL parameters */
78 check_not_null(context);
79 check_not_null(publicKeyPath);
80 check_not_null(quoteInfo);
81 check_not_null(signature);
82
83 r = Fapi_VerifyQuote_Async(context, publicKeyPath,
84 qualifyingData, qualifyingDataSize,
85 quoteInfo, signature,
86 signatureSize, pcrLog);
87 return_if_error_reset_state(r, "Key_VerifyQuote");
88
89 do {
90 /* We wait for file I/O to be ready if the FAPI state automata
91 are in a file I/O state. */
92 r = ifapi_io_poll(&context->io);
93 return_if_error(r, "Something went wrong with IO polling");
94
95 /* Repeatedly call the finish function, until FAPI has transitioned
96 through all execution stages / states of this invocation. */
97 r = Fapi_VerifyQuote_Finish(context);
98 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
99
100 return_if_error_reset_state(r, "Key_VerifyQuote");
101
102 LOG_TRACE("finished");
103 return TSS2_RC_SUCCESS;
104 }
105
106 /** Asynchronous function for Fapi_VerifyQuote
107 *
108 * Verifies that the data returned by a quote is valid.
109 * Call Fapi_VerifyQuote_Finish to finish the execution of this command.
110 *
111 * @param[in,out] context The FAPI_CONTEXT
112 * @param[in] publicKeyPath The path to the signing key
113 * @param[in] qualifyingData The qualifying data nonce. May be NULL
114 * @param[in] qualifyingDataSize The size of qualifyingData in bytes. Must be 0
115 * if qualifyingData is NULL
116 * @param[in] quoteInfo The quote information
117 * @param[in] signature The quote's signature
118 * @param[in] signatureSize The size of signature in bytes
119 * @param[in] pcrLog The PCR's log. May be NULL
120 *
121 * @retval TSS2_RC_SUCCESS: if the function call was a success.
122 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context, publicKeyPath, quoteInfo,
123 * or signature is NULL.
124 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
125 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if path does not map to a FAPI entity.
126 * @retval TSS2_FAPI_RC_BAD_KEY: if the entity at path is not a key, or is a key
127 * that is unsuitable for the requested operation.
128 * @retval TSS2_FAPI_RC_BAD_VALUE: if quoteInfo, pcrEventLog, qualifyingData, or
129 * signature is invalid.
130 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
131 * operation already pending.
132 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
133 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
134 * internal operations or return parameters.
135 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
136 * during authorization.
137 */
138 TSS2_RC
Fapi_VerifyQuote_Async(FAPI_CONTEXT * context,char const * publicKeyPath,uint8_t const * qualifyingData,size_t qualifyingDataSize,char const * quoteInfo,uint8_t const * signature,size_t signatureSize,char const * pcrLog)139 Fapi_VerifyQuote_Async(
140 FAPI_CONTEXT *context,
141 char const *publicKeyPath,
142 uint8_t const *qualifyingData,
143 size_t qualifyingDataSize,
144 char const *quoteInfo,
145 uint8_t const *signature,
146 size_t signatureSize,
147 char const *pcrLog)
148 {
149 LOG_TRACE("called for context:%p", context);
150 LOG_TRACE("publicKeyPath: %s", publicKeyPath);
151 if (qualifyingData) {
152 LOGBLOB_TRACE(qualifyingData, qualifyingDataSize, "qualifyingData");
153 } else {
154 LOG_TRACE("qualifyingData: (null) qualifyingDataSize: %zi", qualifyingDataSize);
155 }
156 LOG_TRACE("quoteInfo: %s", quoteInfo);
157 if (signature) {
158 LOGBLOB_TRACE(signature, signatureSize, "signature");
159 } else {
160 LOG_TRACE("signature: (null) signatureSize: %zi", signatureSize);
161 }
162 LOG_TRACE("pcrLog: %s", pcrLog);
163
164 TSS2_RC r;
165
166 /* Check for NULL parameters */
167 check_not_null(context);
168 check_not_null(publicKeyPath);
169 check_not_null(quoteInfo);
170 check_not_null(signature);
171
172 /* Check for invalid parameters */
173 if (qualifyingData == NULL && qualifyingDataSize != 0) {
174 LOG_ERROR("qualifyingData is NULL but qualifyingDataSize is not 0");
175 return TSS2_FAPI_RC_BAD_VALUE;
176 }
177
178 /* Helpful alias pointers */
179 IFAPI_PCR * command = &context->cmd.pcr;
180
181 r = ifapi_non_tpm_mode_init(context);
182 return_if_error(r, "Initialize VerifyQuote");
183
184 /* Copy parameters to context for use during _Finish. */
185 uint8_t * signatureBuffer = malloc(signatureSize);
186 goto_if_null2(signatureBuffer, "Out of memory",
187 r, TSS2_FAPI_RC_MEMORY, error_cleanup);
188 memcpy(signatureBuffer, signature, signatureSize);
189 command->signature = signatureBuffer;
190 command->signatureSize = signatureSize;
191
192 strdup_check(command->keyPath, publicKeyPath, r, error_cleanup);
193 strdup_check(command->quoteInfo, quoteInfo, r, error_cleanup);
194 strdup_check(command->logData, pcrLog, r, error_cleanup);
195
196 if (qualifyingData != NULL) {
197 FAPI_COPY_DIGEST(&command->qualifyingData.buffer[0],
198 command->qualifyingData.size,
199 qualifyingData, qualifyingDataSize);
200 }
201
202 /* Load the key for verification from the keystore. */
203 r = ifapi_keystore_load_async(&context->keystore, &context->io, publicKeyPath);
204 return_if_error2(r, "Could not open: %s", publicKeyPath);
205
206 /* Initialize the context state for this operation. */
207 context->state = VERIFY_QUOTE_READ;
208 LOG_TRACE("finished");
209 return TSS2_RC_SUCCESS;
210
211 error_cleanup:
212 /* Cleanup duplicated input parameters that were copied before. */
213 SAFE_FREE(command->keyPath);
214 SAFE_FREE(signatureBuffer);
215 command->signature = NULL;
216 SAFE_FREE(command->quoteInfo);
217 SAFE_FREE(command->logData);
218 return r;
219 }
220
221 /** Asynchronous finish function for Fapi_VerifyQuote
222 *
223 * This function should be called after a previous Fapi_VerifyQuote_Async.
224 *
225 * @param[in,out] context The FAPI_CONTEXT
226 *
227 * @retval TSS2_RC_SUCCESS: if the function call was a success.
228 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
229 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
230 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
231 * operation already pending.
232 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
233 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
234 * internal operations or return parameters.
235 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
236 * complete. Call this function again later.
237 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
238 * the function.
239 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
240 * @retval TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED if the signature could not
241 * be verified
242 */
243 TSS2_RC
Fapi_VerifyQuote_Finish(FAPI_CONTEXT * context)244 Fapi_VerifyQuote_Finish(
245 FAPI_CONTEXT *context)
246 {
247 LOG_TRACE("called for context:%p", context);
248
249 TSS2_RC r;
250 IFAPI_OBJECT key_object;
251 TPM2B_ATTEST attest2b;
252 TPM2B_DIGEST pcr_digest;
253
254 /* Check for NULL parameters */
255 check_not_null(context);
256
257 /* Helpful alias pointers */
258 IFAPI_PCR * command = &context->cmd.pcr;
259
260 memset(&key_object, 0, sizeof(IFAPI_OBJECT));
261
262 switch (context->state) {
263 statecase(context->state, VERIFY_QUOTE_READ);
264 r = ifapi_keystore_load_finish(&context->keystore, &context->io, &key_object);
265 return_try_again(r);
266 return_if_error_reset_state(r, "read_finish failed");
267
268 /* Recalculate the quote-info and attest2b buffer. */
269 r = ifapi_get_quote_info(command->quoteInfo, &attest2b,
270 &command->fapi_quote_info);
271 goto_if_error(r, "Get quote info.", error_cleanup);
272
273 /* Verify the signature over the attest2b structure. */
274 r = ifapi_verify_signature_quote(&key_object,
275 command->signature,
276 command->signatureSize,
277 &attest2b.attestationData[0],
278 attest2b.size,
279 &command->fapi_quote_info.sig_scheme);
280 goto_if_error(r, "Verify signature.", error_cleanup);
281
282 /* If no logData was provided then the operation is done. */
283 if (!command->logData) {
284 context->state = _FAPI_STATE_INIT;
285 break;
286 }
287
288 /* If logData was provided then the pcr_digests need to be recalculated
289 and verified against the quote_info. */
290
291 /* Parse the logData JSON. */
292 command->event_list = json_tokener_parse(context->cmd.pcr.logData);
293 return_if_null(command->event_list, "Json error.", TSS2_FAPI_RC_BAD_VALUE);
294
295 /* Recalculate and verify the PCR digests. */
296 r = ifapi_calculate_pcr_digest(command->event_list,
297 &command->fapi_quote_info, &pcr_digest);
298
299 goto_if_error(r, "Verify event list.", error_cleanup);
300
301 context->state = _FAPI_STATE_INIT;
302 break;
303
304 statecasedefault(context->state);
305 }
306
307 error_cleanup:
308 /* Cleanup any intermediate results and state stored in the context. */
309 if (key_object.objectType)
310 ifapi_cleanup_ifapi_object(&key_object);
311 if (command->event_list)
312 json_object_put(command->event_list);
313 ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
314 ifapi_cleanup_ifapi_object(context->loadKey.key_object);
315 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
316 SAFE_FREE(command->keyPath);
317 SAFE_FREE(command->signature);
318 SAFE_FREE(command->quoteInfo);
319 SAFE_FREE(command->logData);
320 LOG_TRACE("finished");
321 return r;
322 }
323