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
18 #include "tss2_fapi.h"
19 #include "fapi_int.h"
20 #include "fapi_util.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_SetCertificate
28 *
29 * Sets an x509 cert into the path of a key.
30 *
31 * @param[in,out] context The FAPI_CONTEXT
32 * @param[in] path The path of the entity to be associated with the
33 * certificate
34 * @param[in] x509certData The certificate that is associated with the entity.
35 * If this is NULL an existing certificate will be removed from
36 * the entity
37 *
38 * @retval TSS2_RC_SUCCESS: if the function call was a success.
39 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
40 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
41 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if path does not map to a FAPI entity.
42 * @retval TSS2_FAPI_RC_BAD_KEY: if x509certData is invalid.
43 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
44 * operation already pending.
45 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
46 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
47 * internal operations or return parameters.
48 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
49 * during authorization.
50 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
51 * the function.
52 * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
53 * this function needs to be called again.
54 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
55 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
56 */
57 TSS2_RC
Fapi_SetCertificate(FAPI_CONTEXT * context,char const * path,char const * x509certData)58 Fapi_SetCertificate(
59 FAPI_CONTEXT *context,
60 char const *path,
61 char const *x509certData)
62 {
63 LOG_TRACE("called for context:%p", context);
64
65 TSS2_RC r;
66
67 /* Check for NULL parameters */
68 check_not_null(context);
69 check_not_null(path);
70
71 r = Fapi_SetCertificate_Async(context, path, x509certData);
72 return_if_error_reset_state(r, "Key_SetCertificate");
73
74 do {
75 /* We wait for file I/O to be ready if the FAPI state automata
76 are in a file I/O state. */
77 r = ifapi_io_poll(&context->io);
78 return_if_error(r, "Something went wrong with IO polling");
79
80 /* Repeatedly call the finish function, until FAPI has transitioned
81 through all execution stages / states of this invocation. */
82 r = Fapi_SetCertificate_Finish(context);
83 } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
84
85 return_if_error_reset_state(r, "Key_SetCertificate");
86
87 LOG_TRACE("finished");
88 return TSS2_RC_SUCCESS;
89 }
90
91 /** Asynchronous function for Fapi_SetCertificate
92 *
93 * Sets an x509 cert into the path of a key.
94 *
95 * Call Fapi_SetCertificate_Finish to finish the execution of this command.
96 *
97 * @param[in,out] context The FAPI_CONTEXT
98 * @param[in] path The path of the entity to be associated with the
99 * certificate
100 * @param[in] x509certData The certificate that is associated with the entity.
101 * If this is NULL an existing certificate will be removed from
102 * the entity
103 *
104 * @retval TSS2_RC_SUCCESS: if the function call was a success.
105 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or path is NULL.
106 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
107 * @retval TSS2_FAPI_RC_KEY_NOT_FOUND: if path does not map to a FAPI entity.
108 * @retval TSS2_FAPI_RC_BAD_KEY: if x509certData is invalid.
109 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
110 * operation already pending.
111 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
112 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
113 * internal operations or return parameters.
114 * @retval TSS2_FAPI_RC_PATH_NOT_FOUND if a FAPI object path was not found
115 * during authorization.
116 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
117 * the function.
118 */
119 TSS2_RC
Fapi_SetCertificate_Async(FAPI_CONTEXT * context,char const * path,char const * x509certData)120 Fapi_SetCertificate_Async(
121 FAPI_CONTEXT *context,
122 char const *path,
123 char const *x509certData)
124 {
125 LOG_TRACE("called for context:%p", context);
126 LOG_TRACE("path: %s", path);
127 LOG_TRACE("x509certData: %s", x509certData);
128
129 TSS2_RC r;
130
131 /* Check for NULL parameters */
132 check_not_null(context);
133 check_not_null(path);
134
135 /* Helpful alias pointers */
136 IFAPI_Key_SetCertificate * command = &context->cmd.Key_SetCertificate;
137
138 r = ifapi_non_tpm_mode_init(context);
139 goto_if_error(r, "Initialize SetCertificate", error_cleanup);
140
141 /* Copy parameters to context for use during _Finish. */
142 if (x509certData) {
143 strdup_check(command->pem_cert, x509certData, r, error_cleanup);
144 } else {
145 command->pem_cert = NULL;
146 }
147 strdup_check(command->key_path, path, r, error_cleanup);
148 context->state = KEY_SET_CERTIFICATE_READ;
149 memset(&command->key_object, 0, sizeof(IFAPI_OBJECT));
150
151 /* Load the object's current metadata from the keystore. */
152 r = ifapi_keystore_load_async(&context->keystore, &context->io, path);
153 goto_if_error2(r, "Could not open: %s", error_cleanup, path);
154
155 LOG_TRACE("finished");
156 return TSS2_RC_SUCCESS;
157
158 error_cleanup:
159 /* Initialize the context state for this operation. */
160 SAFE_FREE(command->pem_cert);
161 SAFE_FREE(command->key_path);
162 return r;
163 }
164
165 /** Asynchronous finish function for Fapi_SetCertificate
166 *
167 * This function should be called after a previous Fapi_SetCertificate_Async.
168 *
169 * @param[in,out] context The FAPI_CONTEXT
170 *
171 * @retval TSS2_RC_SUCCESS: if the function call was a success.
172 * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
173 * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
174 * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
175 * operation already pending.
176 * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
177 * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
178 * internal operations or return parameters.
179 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
180 * complete. Call this function again later.
181 * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
182 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
183 * the function.
184 * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
185 */
186 TSS2_RC
Fapi_SetCertificate_Finish(FAPI_CONTEXT * context)187 Fapi_SetCertificate_Finish(
188 FAPI_CONTEXT *context)
189 {
190 LOG_TRACE("called for context:%p", context);
191
192 TSS2_RC r;
193
194 /* Check for NULL parameters */
195 check_not_null(context);
196
197 /* Helpful alias pointers */
198 IFAPI_Key_SetCertificate * command = &context->cmd.Key_SetCertificate;
199 IFAPI_OBJECT *key_object = &command->key_object;
200 const char ** pem_cert = &command->pem_cert;
201 char ** pem_cert_dup = &command->pem_cert_dup;
202
203 switch (context->state) {
204 statecase(context->state, KEY_SET_CERTIFICATE_READ)
205 r = ifapi_keystore_load_finish(&context->keystore, &context->io, key_object);
206 return_try_again(r);
207 return_if_error_reset_state(r, "read_finish failed");
208
209 /* Duplicate and store the certificate in the key object. */
210 if (!*pem_cert) {
211 strdup_check(*pem_cert_dup, "", r, error_cleanup);
212 } else {
213 strdup_check(*pem_cert_dup, *pem_cert, r, error_cleanup);
214 }
215 if (key_object->objectType == IFAPI_EXT_PUB_KEY_OBJ) {
216 SAFE_FREE(key_object->misc.ext_pub_key.certificate);
217 key_object->misc.ext_pub_key.certificate = *pem_cert_dup;
218 } else {
219 SAFE_FREE(key_object->misc.key.certificate);
220 key_object->misc.key.certificate = *pem_cert_dup;
221 }
222
223 /* Perform esys serialization if necessary */
224 r = ifapi_esys_serialize_object(context->esys, key_object);
225 goto_if_error(r, "Prepare serialization", error_cleanup);
226
227 /* Start writing the NV object to the key store */
228 r = ifapi_keystore_store_async(&context->keystore, &context->io,
229 command->key_path, key_object);
230 goto_if_error_reset_state(r, "Could not open: %sh", error_cleanup,
231 command->key_path);
232
233 context->state = KEY_SET_CERTIFICATE_WRITE;
234 fallthrough;
235
236 statecase(context->state, KEY_SET_CERTIFICATE_WRITE)
237 /* Finish writing the object to the key store */
238 r = ifapi_keystore_store_finish(&context->keystore, &context->io);
239 return_try_again(r);
240 return_if_error_reset_state(r, "write_finish failed");
241
242 context->state = _FAPI_STATE_INIT;
243 r = TSS2_RC_SUCCESS;
244 break;
245
246 statecasedefault(context->state);
247 }
248
249 error_cleanup:
250 /* Cleanup any intermediate results and state stored in the context. */
251 SAFE_FREE(command->pem_cert);
252 SAFE_FREE(command->key_path);
253 if (key_object->objectType) {
254 ifapi_cleanup_ifapi_object(key_object);
255 }
256 ifapi_cleanup_ifapi_object(&context->loadKey.auth_object);
257 ifapi_cleanup_ifapi_object(context->loadKey.key_object);
258 ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object);
259 LOG_TRACE("finished");
260 return r;
261 }
262