Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FXAS21002 FXOS8700Q
fcc_bundle_handler.c
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2016-2017 ARM Ltd. 00003 // 00004 // Licensed under the Apache License, Version 2.0 (the "License"); 00005 // you may not use this file except in compliance with the License. 00006 // You may obtain a copy of the License at 00007 // 00008 // http://www.apache.org/licenses/LICENSE-2.0 00009 // 00010 // Unless required by applicable law or agreed to in writing, software 00011 // distributed under the License is distributed on an "AS IS" BASIS, 00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 // See the License for the specific language governing permissions and 00014 // limitations under the License. 00015 // ---------------------------------------------------------------------------- 00016 #include "fcc_bundle_handler.h" 00017 #include "cn-cbor.h" 00018 #include "pv_error_handling.h" 00019 #include "factory_configurator_client.h" 00020 #include "fcc_bundle_utils.h" 00021 #include "fcc_output_info_handler.h" 00022 #include "fcc_malloc.h" 00023 #include "general_utils.h" 00024 #include "fcc_time_profiling.h" 00025 #include "fcc_utils.h" 00026 #include "fcc_bundle_fields.h" 00027 #include "storage.h" 00028 00029 /** 00030 * Defines for cbor layer 00031 */ 00032 #ifdef USE_CBOR_CONTEXT 00033 #define CONTEXT_NULL , NULL 00034 #define CONTEXT_NULL_COMMA NULL, 00035 #else 00036 #define CONTEXT_NULL 00037 #define CONTEXT_NULL_COMMA 00038 #endif 00039 00040 /** 00041 * Definition of size and value of current protocol scheme version 00042 */ 00043 #define FCC_SIZE_OF_VERSION_FIELD 5 00044 const char fcc_bundle_scheme_version[] = "0.0.1"; 00045 extern bool g_is_session_finished; 00046 00047 // FIXME: temporary. Will be removed when migration to tinycbor is complete 00048 void g_csr_buf_free(void); 00049 00050 /** 00051 * Types of configuration parameter groups 00052 */ 00053 typedef enum { 00054 FCC_KEY_GROUP_TYPE, //!< Key group type 00055 FCC_CERTIFICATE_GROUP_TYPE, //!< Certificate group type 00056 FCC_CONFIG_PARAM_GROUP_TYPE, //!< Configuration parameter group type 00057 FCC_CERTIFICATE_CHAIN_GROUP_TYPE, //!< Certificate chain group type 00058 FCC_SCHEME_VERSION_TYPE, //!< Scheme version group type 00059 FCC_ENTROPY_TYPE, //!< Entropy group type 00060 FCC_ROT_TYPE, //!< Root of trust group type 00061 FCC_VERIFY_DEVICE_IS_READY_TYPE, //!< Verify device readiness type 00062 FCC_FACTORY_DISABLE_TYPE, //!< Disable FCC flow type 00063 FCC_IS_ALIVE_SESSION_GROUP_TYPE, //!< Indicates current message status - last message or not 00064 FCC_FCU_SESSION_ID_GROUP_TYPE, //!< Session ID sent by the FCU 00065 FCC_CSR_REQUESTS_GROUP_TYPE, //!< CSR requests type 00066 FCC_MAX_CONFIG_PARAM_GROUP_TYPE //!< Max group type 00067 } fcc_bundle_param_group_type_e; 00068 00069 /** 00070 * Group lookup record, correlating group's type and name 00071 */ 00072 typedef struct fcc_bundle_group_lookup_record_ { 00073 fcc_bundle_param_group_type_e group_type; 00074 const char *group_name; 00075 } fcc_bundle_group_lookup_record_s; 00076 /** 00077 * Group lookup table, correlating for each group its type and name. 00078 * Order is important - it is the order that fcc_bundle_handler() reads the cbor fields. 00079 * FCC_ENTROPY_TYPE and FCC_ROT_TYPE Must be processed first and second respectively. 00080 */ 00081 static const fcc_bundle_group_lookup_record_s fcc_groups_lookup_table[FCC_MAX_CONFIG_PARAM_GROUP_TYPE] = { 00082 { FCC_SCHEME_VERSION_TYPE, FCC_BUNDLE_SCHEME_GROUP_NAME }, 00083 { FCC_ENTROPY_TYPE, FCC_ENTROPY_NAME }, 00084 { FCC_ROT_TYPE, FCC_ROT_NAME }, 00085 { FCC_IS_ALIVE_SESSION_GROUP_TYPE, FCC_KEEP_ALIVE_SESSION_GROUP_NAME }, 00086 { FCC_KEY_GROUP_TYPE, FCC_KEY_GROUP_NAME }, 00087 { FCC_CERTIFICATE_GROUP_TYPE, FCC_CERTIFICATE_GROUP_NAME }, 00088 { FCC_CONFIG_PARAM_GROUP_TYPE, FCC_CONFIG_PARAM_GROUP_NAME }, 00089 { FCC_CERTIFICATE_CHAIN_GROUP_TYPE, FCC_CERTIFICATE_CHAIN_GROUP_NAME }, 00090 { FCC_VERIFY_DEVICE_IS_READY_TYPE, FCC_VERIFY_DEVICE_IS_READY_GROUP_NAME }, 00091 { FCC_FACTORY_DISABLE_TYPE, FCC_FACTORY_DISABLE_GROUP_NAME }, 00092 { FCC_FCU_SESSION_ID_GROUP_TYPE, FCC_FCU_SESSION_ID_GROUP_TYPE_NAME }, 00093 { FCC_CSR_REQUESTS_GROUP_TYPE, FCC_CSR_REQUESTS_GROUP_NAME } 00094 }; 00095 00096 00097 00098 00099 /* Response cbor blob structure 00100 00101 { "SchemeVersion": "0.0.1", 00102 "FCUSessionID": uint32_t, 00103 "Csrs": [ {"Name": "__", "Format":"_","Data":"__"}, 00104 {"Name": "__", "Format":"_","Data":"__"}], 00105 "WarningInfo": "string of warnings", 00106 "ReturnStatus": uint32_t, 00107 "InfoMessage": "detailed error string"} 00108 */ 00109 /** Prepare a response message 00110 * 00111 * The function prepare response buffer according to result of bundle buffer processing. 00112 * In case of failure, the function prepare buffer with status,scheme version and error logs, 00113 * in case of success - only the status and scheme version. 00114 * 00115 * @param bundle_response_out[in/out] The pointer to response buffer. 00116 * @param bundle_response_size_out[out/out] The size of response buffer. 00117 * @param fcc_status[in] The result of bundle buffer processing. 00118 * 00119 * @return 00120 * true for success, false otherwise. 00121 */ 00122 static bool prepare_reponse_message(uint8_t **bundle_response_out, size_t *bundle_response_size_out, fcc_status_e fcc_status, cn_cbor *encoder, const uint8_t *session_id, size_t session_id_len) 00123 { 00124 bool status = false; 00125 cn_cbor_errback err; 00126 cn_cbor *cbor_struct_cb = NULL; 00127 int size_of_cbor_buffer = 0; 00128 int size_of_out_buffer = 0; 00129 uint8_t *out_buffer = NULL; 00130 char *error_string_info = NULL; 00131 char *warning_string_info = NULL; 00132 const char success_message[] = { "The Factory process succeeded\n" }; 00133 *bundle_response_out = NULL; 00134 00135 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00136 00137 // If error has occurred during bundle processing - create a new encoder (all that was encoded is not needed) 00138 // If no error occurred - the encoder will already have the scheme version and the FCU session ID inside an open map - therefore, in case of an error, we add them to a new map 00139 if (fcc_status != FCC_STATUS_SUCCESS) { 00140 // Free the old encoder and create a new one 00141 if (encoder) { 00142 cn_cbor_free(encoder CBOR_CONTEXT_PARAM); 00143 } 00144 encoder = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &err); 00145 SA_PV_ERR_RECOVERABLE_RETURN_IF((encoder == NULL), false, "Failed to create cbor map"); 00146 00147 /** 00148 * Create cbor with scheme version 00149 */ 00150 cbor_struct_cb = NULL; 00151 cbor_struct_cb = cn_cbor_text_create((const uint8_t *)fcc_bundle_scheme_version, sizeof(fcc_bundle_scheme_version) CBOR_CONTEXT_PARAM, &err); 00152 SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create scheme_version_cb "); 00153 00154 //Put the cbor scheme version in cbor map with string key "SchemeVersion" 00155 status = cn_cbor_mapput_string(encoder, FCC_BUNDLE_SCHEME_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err); 00156 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed to put return status to cbor map"); 00157 00158 //Put the cbor session ID in cbor map with string key "SID" 00159 if(session_id != NULL) { 00160 cbor_struct_cb = cn_cbor_text_create(session_id, (int)session_id_len CBOR_CONTEXT_PARAM, &err); 00161 SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "CBOR error"); 00162 00163 status = cn_cbor_mapput_string(encoder, FCC_FCU_SESSION_ID_GROUP_TYPE_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err); 00164 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed to put return session ID"); 00165 } 00166 } 00167 00168 00169 /** 00170 * Create cbor with return status 00171 */ 00172 cbor_struct_cb = cn_cbor_int_create(fcc_status CBOR_CONTEXT_PARAM, &err); 00173 SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create return_status_cb "); 00174 00175 //Put the cbor return status in cbor map with string key "ReturnStatus" 00176 status = cn_cbor_mapput_string(encoder, FCC_RETURN_STATUS_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err); 00177 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put return status to cbor map"); 00178 00179 00180 /** 00181 * Create cbor with error info 00182 */ 00183 cbor_struct_cb = NULL; 00184 if (fcc_status == FCC_STATUS_SUCCESS) { 00185 cbor_struct_cb = cn_cbor_text_create((const uint8_t*)success_message, (int)strlen(success_message) CBOR_CONTEXT_PARAM, &err); 00186 } else { 00187 error_string_info = fcc_get_output_error_info(); 00188 if (error_string_info == NULL) { 00189 cbor_struct_cb = cn_cbor_text_create((const uint8_t*)g_fcc_general_status_error_str, (int)strlen(g_fcc_general_status_error_str) CBOR_CONTEXT_PARAM, &err); 00190 } else { 00191 cbor_struct_cb = cn_cbor_text_create((const uint8_t*)error_string_info, (int)strlen(error_string_info) CBOR_CONTEXT_PARAM, &err); 00192 } 00193 } 00194 SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create cbor_struct_cb "); 00195 00196 //Put the cbor info message in cbor map with string key "infoMessage" 00197 status = cn_cbor_mapput_string(encoder, FCC_ERROR_INFO_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err); 00198 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put cbor_struct_cb to cbor map"); 00199 00200 /** 00201 * Create cbor with warning info 00202 */ 00203 cbor_struct_cb = NULL; 00204 status = fcc_get_warning_status(); 00205 warning_string_info = fcc_get_output_warning_info(); 00206 SA_PV_ERR_RECOVERABLE_GOTO_IF(status == true && warning_string_info == NULL, status = false, exit, "Failed to get created warnings"); 00207 if (warning_string_info != NULL) { 00208 cbor_struct_cb = cn_cbor_text_create((const uint8_t *)warning_string_info, (int)strlen(warning_string_info) CBOR_CONTEXT_PARAM, &err); 00209 SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create warning_message_cb "); 00210 00211 //Put the cbor info message in cbor map with string key "WarningInfo" 00212 status = cn_cbor_mapput_string(encoder, FCC_WARNING_INFO_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err); 00213 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put warning_message_cb to cbor map"); 00214 } 00215 00216 status = true; 00217 //Get size of encoded cbor buffer 00218 size_of_cbor_buffer = cn_cbor_get_encoded_size(encoder, &err); 00219 SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_cbor_buffer == -1), status = false, exit, "Failed to get cbor buffer size"); 00220 00221 //Allocate out buffer 00222 out_buffer = fcc_malloc((size_t)size_of_cbor_buffer); 00223 SA_PV_ERR_RECOVERABLE_GOTO_IF((out_buffer == NULL), status = false, exit, "Failed to allocate memory for out buffer"); 00224 00225 //Write cbor blob to output buffer 00226 size_of_out_buffer = cn_cbor_encoder_write(encoder, out_buffer, size_of_cbor_buffer, &err); 00227 SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_out_buffer == -1), status = false, exit_without_out_buffer, "Failed to write cbor buffer to output buffer"); 00228 SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_out_buffer != size_of_cbor_buffer), status = false, exit_without_out_buffer, "Wrong written size for outbut buffer"); 00229 00230 //Update pointer and size of output buffer 00231 *bundle_response_out = out_buffer; 00232 *bundle_response_size_out = (size_t)size_of_out_buffer; 00233 goto exit; 00234 00235 exit_without_out_buffer: 00236 fcc_free(out_buffer); 00237 00238 // Nullify pointer so that the user cannot accidentally double free it. 00239 *bundle_response_out = NULL; 00240 exit: 00241 // FIXME: Free the CSRs buffer after the writing to the encoder buffer. Not needed after migration to tinycbor 00242 g_csr_buf_free(); 00243 fcc_free(warning_string_info); 00244 if (encoder != NULL) { 00245 cn_cbor_free(encoder CBOR_CONTEXT_PARAM); 00246 } 00247 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00248 return status; 00249 } 00250 00251 00252 /** Checks bundle scheme version 00253 * 00254 * @param cbor_blob[in] The pointer to main cbor blob. 00255 * @param encoder[in] Pointer to an encoder that points to the beginning of the CBOR response encoder 00256 * 00257 * FIXME: When we migrate to tinycbor encoder should be pointer to the encoder so that after encoding, the encoder will point to the next available spot in the response CBOR 00258 * @return 00259 * true for success, false otherwise. 00260 */ 00261 static bool check_scheme_version(cn_cbor *cbor_blob, cn_cbor *encoder) 00262 { 00263 cn_cbor *cbor = NULL; 00264 bool status; 00265 int result; 00266 00267 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_blob == NULL), false, "Invalid cbor_blob"); 00268 00269 cbor = cn_cbor_mapget_string(cbor_blob, FCC_BUNDLE_SCHEME_GROUP_NAME); 00270 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor == NULL), false, "Failed to find scheme version group"); 00271 00272 result = is_memory_equal(cbor->v.bytes, (size_t)(cbor->length), fcc_bundle_scheme_version, (size_t)strlen(fcc_bundle_scheme_version)); 00273 SA_PV_ERR_RECOVERABLE_RETURN_IF((!result), false, "Wrong scheme version"); 00274 00275 // append the scheme version key-value into the encoder 00276 cbor = cn_cbor_text_create((const uint8_t *)fcc_bundle_scheme_version, sizeof(fcc_bundle_scheme_version) CBOR_CONTEXT_PARAM, NULL); 00277 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor == NULL), false, "Failed to create scheme_version_cb "); 00278 00279 status = cn_cbor_mapput_string(encoder, FCC_BUNDLE_SCHEME_GROUP_NAME, cbor, CBOR_CONTEXT_PARAM_COMMA NULL); 00280 SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), status, "CBOR error"); 00281 00282 return true; 00283 } 00284 00285 /** Checks the FCU session ID and encodes it into the encoder 00286 * 00287 * @param parser[in] Pointer to cbor containing the FCU session ID (the value of the KV pair where the key is FCC_FCU_SESSION_ID_GROUP_TYPE_NAME). 00288 * @param encoder[in] Pointer to an encoder that points to the beginning of the CBOR response encoder. 00289 * @param session_id[out] Pointer to a pointer that will point to the session ID in the incoming message. 00290 * @param session_id_len[out] The length of the session ID in the incoming message. 00291 * 00292 * FIXME: When we migrate to tinycbor encoder should be pointer to the encoder so that after encoding, the encoder will point to the next available spot in the response CBOR 00293 * @return 00294 * true for success, false otherwise. 00295 */ 00296 static bool fcc_bundle_process_session_id(cn_cbor *parser, cn_cbor *encoder, const uint8_t **session_id, size_t *session_id_len) 00297 { 00298 cn_cbor *cbor = NULL; 00299 bool status; 00300 00301 // Get the session ID from the message and make sure that it is either a text or bytes string 00302 SA_PV_ERR_RECOVERABLE_RETURN_IF((parser->type != CN_CBOR_TEXT), false, "Session ID of wrong type"); 00303 00304 // Output the values for use of the prepare_reponse_message() function in case of an error during the bundle handling process 00305 *session_id = (uint8_t *)parser->v.bytes; 00306 *session_id_len = (size_t)parser->length; 00307 00308 cbor = cn_cbor_text_create(*session_id, (int)*session_id_len CBOR_CONTEXT_PARAM, NULL); 00309 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor == NULL), false, "CBOR error"); 00310 00311 // append the session id key-value into the encoder 00312 status = cn_cbor_mapput_string(encoder, FCC_FCU_SESSION_ID_GROUP_TYPE_NAME, cbor, CBOR_CONTEXT_PARAM_COMMA NULL); 00313 SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), false, "CBOR error"); 00314 00315 return true; 00316 } 00317 00318 00319 00320 /** The function parses group that indicates if current session will be closed after the processing of the message. 00321 * The function checks existence and value of the group and sets the result to global variable g_is_alive_sesssion. 00322 * 00323 * @param cbor_blob[in] The pointer to main cbor blob. 00324 * @return 00325 * true for success, false otherwise. 00326 */ 00327 static bool parse_keep_alive_session_group(cn_cbor *cbor_blob) 00328 { 00329 cn_cbor *is_alive_message = NULL; 00330 00331 is_alive_message = cn_cbor_mapget_string(cbor_blob, FCC_KEEP_ALIVE_SESSION_GROUP_NAME); 00332 //In case current group wasn't found - set g_is_not_last_message to false (for backward compatibility) 00333 if (is_alive_message == NULL) { 00334 g_is_session_finished = true; 00335 return true; 00336 } 00337 SA_PV_ERR_RECOVERABLE_RETURN_IF((is_alive_message->type != CN_CBOR_UINT || is_alive_message->v.uint > 1), false, "Wrong is alive session structure"); 00338 00339 // Session is finished if value is 0, and alive if value is 1 00340 g_is_session_finished = !(is_alive_message->v.uint); 00341 00342 return true; 00343 } 00344 00345 /* CBOR blob structure 00346 { "SchemeVersion": "0.0.1", 00347 "FCUSessionID": uint32_t, 00348 "IsNotLastMessage": 1 or 0, 00349 "Entropy": [byte array - 48 bytes], 00350 "Csrs": [ {"PrivKeyName":"__", 00351 "PubKeyName": "__", -optional 00352 "Extensions": [ 00353 {"TrustLevel": uint32_t }, 00354 { 00355 "KeyUsage": [uint32_t,uint32_t,unit32_t ], 00356 }, 00357 { 00358 "ExtendedKeyUsage": [byte array], 00359 }] 00360 "Subject": "C=__,ST=__ ,L=__, O=__,OU=__,CN=__,", 00361 }, 00362 { ... }, 00363 { ... } 00364 ], 00365 "ROT": "byte array", 00366 "Certificates": [ {"Name": "__", "Format":" _","Data":"__", "ACL" : "__"}, 00367 {..}, 00368 {"Name": "__", "Format":" _","Data":"__", "ACL" : "__"}], 00369 "Keys": [ {"Name": "__", "Type":"__", "Format":"__", "Data":"**","ACL" : "__"}, 00370 {"Name": "__", "Type":"__", "Format":"__", "Data":"**","ACL": "__"}, 00371 ... 00372 {"Name": "__", "Type":"__", "Format":"__", "Data":"**","ACL": "__"}], 00373 "ConfigParams": [ {"Name": "__", "Data":"__", "ACL" : "__"}, 00374 {"Name": "__", "Format":"__", "Data":"__", "ACL": "__"}, 00375 ..., 00376 {"Name": "__", "Format":"__", "Data":"__", "ACL": "__"}], 00377 "CertificateChains": [ {"Name": "mbed.CertificateChain", 00378 "DataArray":[h'3081870.....',h'308187020100...',h'308187020....'], 00379 "Format":"Der", 00380 "ACL":"_____"}, 00381 {"Name": "mbed.LwM2MCertificateChain", 00382 "DataArray":[h'308187...',h'30818702...',h'308187020...',h'308187020...',h'308187020...'], 00383 "Format":"Der", 00384 "ACL":"_____"}], 00385 "Verify":1, 00386 "Disable":1} 00387 */ 00388 fcc_status_e fcc_bundle_handler(const uint8_t *encoded_blob, size_t encoded_blob_size, uint8_t **bundle_response_out, size_t *bundle_response_size_out) 00389 { 00390 bool status = false; 00391 bool is_fcc_factory_disabled = false; 00392 fcc_status_e fcc_status = FCC_STATUS_SUCCESS; 00393 cn_cbor *main_list_cb = NULL; 00394 cn_cbor *group_value_cb = NULL; 00395 cn_cbor *response_cbor = NULL; 00396 cn_cbor_errback err; 00397 size_t group_index; 00398 fcc_bundle_param_group_type_e group_type; 00399 size_t num_of_groups_in_message = 0; 00400 const uint8_t *session_id = NULL; 00401 size_t session_id_len = 0; 00402 bool fcc_verify_status = true; // the default value of verify status is true 00403 bool fcc_disable_status = false;// the default value of disable status is false 00404 kcm_status_e kcm_status; 00405 00406 FCC_SET_START_TIMER(fcc_bundle_timer); 00407 00408 SA_PV_LOG_INFO_FUNC_ENTER("encoded_blob_size = %" PRIu32 "", (uint32_t)encoded_blob_size); 00409 00410 // Set *bundle_response_out to NULL before fcc_is_factory_disabled call so that in case factory is disabled - return FCC_STATUS_FACTORY_DISABLED_ERROR and nullify *bundle_response_out 00411 if (bundle_response_out != NULL) { 00412 // Set to NULL so that the user does not accidentally free a non NULL pointer after the function returns. 00413 *bundle_response_out = NULL; 00414 } 00415 // Check params 00416 SA_PV_ERR_RECOVERABLE_RETURN_IF((!fcc_is_initialized()), FCC_STATUS_NOT_INITIALIZED, "FCC not initialized"); 00417 SA_PV_ERR_RECOVERABLE_RETURN_IF((bundle_response_out == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid bundle_response_out"); 00418 00419 SA_PV_ERR_RECOVERABLE_RETURN_IF((bundle_response_size_out == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid bundle_response_size_out"); 00420 SA_PV_ERR_RECOVERABLE_GOTO_IF((encoded_blob == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, exit, "Invalid encoded_blob"); 00421 SA_PV_ERR_RECOVERABLE_GOTO_IF((encoded_blob_size == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, exit, "Invalid encoded_blob_size"); 00422 00423 /*Initialize fcc_output_info_s structure , in case of error during store process the 00424 function will exit without fcc_verify_device_configured_4mbed_cloud where we perform additional fcc_clean_output_info_handler*/ 00425 fcc_clean_output_info_handler(); 00426 00427 // Create the CBOR encoder, an empty map 00428 response_cbor = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &err); 00429 SA_PV_ERR_RECOVERABLE_GOTO_IF((response_cbor == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, exit, "Failed to instantiate cbor structure"); 00430 00431 /* Decode CBOR message 00432 Check the size of the CBOR structure */ 00433 main_list_cb = cn_cbor_decode(encoded_blob, encoded_blob_size CBOR_CONTEXT_PARAM, &err); 00434 SA_PV_ERR_RECOVERABLE_GOTO_IF((main_list_cb == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, exit, "cn_cbor_decode failed (%" PRIu32 ")", (uint32_t)err.err); 00435 SA_PV_ERR_RECOVERABLE_GOTO_IF((main_list_cb->type != CN_CBOR_MAP), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "Wrong CBOR structure type"); 00436 SA_PV_ERR_RECOVERABLE_GOTO_IF((main_list_cb->length <= 0 || main_list_cb->length > FCC_MAX_CONFIG_PARAM_GROUP_TYPE *FCC_CBOR_MAP_LENGTH), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "Wrong CBOR structure size"); 00437 00438 /* Check scheme version*/ 00439 status = check_scheme_version(main_list_cb, response_cbor); 00440 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), fcc_status = FCC_STATUS_BUNDLE_INVALID_SCHEME, free_cbor_list_and_out, "check_scheme_version failed"); 00441 00442 /* Parse and save is message status */ 00443 status = parse_keep_alive_session_group(main_list_cb); 00444 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), fcc_status = FCC_STATUS_BUNDLE_INVALID_KEEP_ALIVE_SESSION_STATUS, free_cbor_list_and_out, "parse_keep_alive_session_group failed"); 00445 00446 /* 00447 * In order for file functions to work properly, we must first inject the entropy, 00448 * if we have one to inject. If entropy is expected, its existance is required for 00449 * every random number generation in the system. 00450 * If FCC_ENTROPY_NAME not in bundle (and user did not use the fcc_entropy_set()), 00451 * then device must have TRNG or storage functions will fail. 00452 */ 00453 group_value_cb = cn_cbor_mapget_string(main_list_cb, FCC_ENTROPY_NAME); 00454 if (group_value_cb) { 00455 fcc_status = fcc_bundle_process_buffer(group_value_cb, STORAGE_RBP_RANDOM_SEED_NAME, FCC_BUNDLE_BUFFER_TYPE_ENTROPY); 00456 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_buffer failed for entropy"); 00457 } 00458 00459 /* If RoT injection is expected (to derive storage key) it also must be done prior to storage calls */ 00460 group_value_cb = cn_cbor_mapget_string(main_list_cb, FCC_ROT_NAME); 00461 if (group_value_cb) { 00462 fcc_status = fcc_bundle_process_buffer(group_value_cb, STORAGE_RBP_ROT_NAME, FCC_BUNDLE_BUFFER_TYPE_ROT); 00463 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_buffer failed for RoT"); 00464 } 00465 00466 /* 00467 * At this point we assume that if user expects to inject an entropy - it exists 00468 * in storage, and if not - device has TRNG and it is safe to call storage functions. 00469 * The next calls may fail if for some unlikely reason, one of the following is true: 00470 * 1. User expects an entropy (i.e MBEDTLS_ENTROPY_NV_SEED is defined), yet entropy 00471 * was not included in bundle, and fcc_entropy_set() was not called. 00472 * 2. User does not expect an entropy and device does not have a TRNG (PAL_USE_HW_TRNG=0) 00473 */ 00474 00475 // Now we may initialize the KCM, including the secure time and the file systen 00476 kcm_status = kcm_init(); 00477 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = fcc_convert_kcm_to_fcc_status(kcm_status), free_cbor_list_and_out, "Failed for kcm_init"); 00478 00479 // Check if factory flow is disabled (if flag in storage), if it is, do not proceed 00480 // Turn on is_fcc_factory_disabled even if we get an error, so that we know not tp prepare a response 00481 fcc_status = fcc_is_factory_disabled(&is_fcc_factory_disabled); 00482 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), is_fcc_factory_disabled = true, free_cbor_list_and_out, "Failed for fcc_is_factory_disabled"); 00483 SA_PV_ERR_RECOVERABLE_GOTO_IF((is_fcc_factory_disabled), fcc_status = FCC_STATUS_FACTORY_DISABLED_ERROR, free_cbor_list_and_out, "FCC is disabled, service not available"); 00484 00485 //Go over parameter groups 00486 for (group_index = 0; group_index < FCC_MAX_CONFIG_PARAM_GROUP_TYPE; group_index++) { 00487 //Get content of current group (value of map, when key of map is name of group and value is list of params of current group) 00488 SA_PV_LOG_INFO(" fcc_groups_lookup_table[group_index].group_name is %s", fcc_groups_lookup_table[group_index].group_name); 00489 group_value_cb = cn_cbor_mapget_string(main_list_cb, fcc_groups_lookup_table[group_index].group_name); 00490 00491 if (group_value_cb != NULL) { 00492 //Get type of group 00493 group_type = fcc_groups_lookup_table[group_index].group_type; 00494 num_of_groups_in_message++; 00495 00496 switch (group_type) { 00497 // Scheme version, Entropy, RoT and Keep Alive were handled prior to this switch statement 00498 case FCC_SCHEME_VERSION_TYPE: 00499 case FCC_ENTROPY_TYPE: // Non volatile entropy for random generator 00500 case FCC_ROT_TYPE: // Root of trust for deriving secure storage key 00501 case FCC_IS_ALIVE_SESSION_GROUP_TYPE: 00502 break; 00503 case FCC_KEY_GROUP_TYPE: 00504 FCC_SET_START_TIMER(fcc_gen_timer); 00505 fcc_status = fcc_bundle_process_keys(group_value_cb); 00506 FCC_END_TIMER("Total keys process", 0 ,fcc_gen_timer); 00507 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_keys failed"); 00508 break; 00509 case FCC_CERTIFICATE_GROUP_TYPE: 00510 FCC_SET_START_TIMER(fcc_gen_timer); 00511 fcc_status = fcc_bundle_process_certificates(group_value_cb); 00512 FCC_END_TIMER("Total certificates process", 0, fcc_gen_timer); 00513 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_certificates failed"); 00514 break; 00515 case FCC_CONFIG_PARAM_GROUP_TYPE: 00516 FCC_SET_START_TIMER(fcc_gen_timer); 00517 fcc_status = fcc_bundle_process_config_params(group_value_cb); 00518 FCC_END_TIMER("Total config params process", 0, fcc_gen_timer); 00519 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_config_params failed"); 00520 break; 00521 case FCC_CERTIFICATE_CHAIN_GROUP_TYPE: 00522 FCC_SET_START_TIMER(fcc_gen_timer); 00523 fcc_status = fcc_bundle_process_certificate_chains(group_value_cb); 00524 FCC_END_TIMER("Total certificate chains process", 0, fcc_gen_timer); 00525 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_certificate_chains failed"); 00526 break; 00527 case FCC_VERIFY_DEVICE_IS_READY_TYPE: //Check if device need to be verified 00528 fcc_status = bundle_process_status_field(group_value_cb, (char*)FCC_VERIFY_DEVICE_IS_READY_GROUP_NAME, strlen((char*)FCC_VERIFY_DEVICE_IS_READY_GROUP_NAME), &fcc_verify_status); 00529 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "process_device_verify failed"); 00530 break; 00531 case FCC_FACTORY_DISABLE_TYPE://Check if device need to be disabled for factory 00532 fcc_status = bundle_process_status_field(group_value_cb, (char*)FCC_FACTORY_DISABLE_GROUP_NAME, strlen((char*)FCC_FACTORY_DISABLE_GROUP_NAME), &fcc_disable_status); 00533 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_factory_disable failed"); 00534 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_disable_status == true && g_is_session_finished == false), fcc_status = FCC_STATUS_BUNDLE_INVALID_KEEP_ALIVE_SESSION_STATUS, free_cbor_list_and_out, "can not disable fcc for intermidiate message"); 00535 break; 00536 case FCC_FCU_SESSION_ID_GROUP_TYPE: 00537 status = fcc_bundle_process_session_id(group_value_cb, response_cbor, &session_id, &session_id_len); 00538 SA_PV_ERR_RECOVERABLE_GOTO_IF((!status), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "fcc_bundle_process_session_id failed"); 00539 break; 00540 case FCC_CSR_REQUESTS_GROUP_TYPE: 00541 SA_PV_ERR_RECOVERABLE_GOTO_IF((session_id == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "Session ID is required when providing CSR requests"); 00542 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_verify_status || fcc_disable_status), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "Verify and Disable flags must not exist with CSR requests"); 00543 FCC_SET_START_TIMER(fcc_gen_timer); 00544 fcc_status = fcc_bundle_process_csrs(group_value_cb, response_cbor); 00545 FCC_END_TIMER("Total keys and CSR creation process", 0, fcc_gen_timer); 00546 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_csrs failed"); 00547 break; 00548 default: 00549 fcc_status = FCC_STATUS_BUNDLE_UNSUPPORTED_GROUP; 00550 SA_PV_LOG_ERR("Wrong group type"); 00551 goto free_cbor_list_and_out; 00552 } 00553 } 00554 } 00555 00556 SA_PV_ERR_RECOVERABLE_GOTO_IF((num_of_groups_in_message == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, free_cbor_list_and_out, "No groups in message"); 00557 SA_PV_ERR_RECOVERABLE_GOTO_IF(((size_t)(main_list_cb->length/FCC_CBOR_MAP_LENGTH)!= num_of_groups_in_message), fcc_status = FCC_STATUS_BUNDLE_INVALID_GROUP, free_cbor_list_and_out, "One ore more names of groups are invalid"); 00558 00559 // If not keep alive 00560 if (g_is_session_finished) { 00561 // Note that FCC_STATUS_CA_ERROR is being return only in case where the CA already exists 00562 // in SOTP, if in the future more error conditions will be attached to FCC_STATUS_CA_ERROR error code 00563 // then the logic here MUST be change. 00564 // Only if this is the last message - set the certificate ID 00565 fcc_status = fcc_trust_ca_cert_id_set(); 00566 SA_PV_ERR_RECOVERABLE_GOTO_IF(((fcc_status != FCC_STATUS_SUCCESS) && (fcc_status != FCC_STATUS_CA_ERROR)), (fcc_status = fcc_status), free_cbor_list_and_out, "CA store error %u", fcc_status); 00567 00568 } 00569 00570 if (fcc_verify_status == true) { 00571 // device VERIFY group does NOT exist in the CBOR message and device is NOT disabled. 00572 // Perform device verification to keep backward compatibility. 00573 00574 00575 FCC_SET_START_TIMER(fcc_gen_timer); 00576 fcc_status = fcc_verify_device_configured_4mbed_cloud(); 00577 FCC_END_TIMER("Total verify device", 0, fcc_gen_timer); 00578 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_verify_device_configured_4mbed_cloud failed"); 00579 } 00580 00581 if (fcc_disable_status == true) { 00582 fcc_status = fcc_bundle_factory_disable(); 00583 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_factory_disable failed"); 00584 } 00585 00586 free_cbor_list_and_out: 00587 cn_cbor_free(main_list_cb CBOR_CONTEXT_PARAM); 00588 exit: 00589 // If we discovered that factory is disabled (or fcc_is_factory_disabled failed) - do not prepare a response 00590 if (is_fcc_factory_disabled == false) { 00591 //Prepare bundle response message 00592 status = prepare_reponse_message(bundle_response_out, bundle_response_size_out, fcc_status, response_cbor, session_id, session_id_len); 00593 SA_PV_ERR_RECOVERABLE_RETURN_IF((status != true), FCC_STATUS_BUNDLE_RESPONSE_ERROR, "Failed to prepare out response"); 00594 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00595 FCC_END_TIMER("Total fcc_bundle_handler device", 0, fcc_bundle_timer); 00596 } else { 00597 // We may have started encoding the response, but gotten an error, if so - free the encoder 00598 if (response_cbor) { 00599 cn_cbor_free(response_cbor CBOR_CONTEXT_PARAM); 00600 } 00601 } 00602 return fcc_status; 00603 }
Generated on Tue Jul 12 2022 20:20:59 by
