Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fcc_bundle_handler.c Source File

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 }