Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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 #ifndef USE_TINY_CBOR
00017 #include "fcc_bundle_handler.h"
00018 #include "cn-cbor.h"
00019 #include "pv_error_handling.h"
00020 #include "factory_configurator_client.h"
00021 #include "fcc_bundle_utils.h"
00022 #include "fcc_output_info_handler.h"
00023 #include "fcc_malloc.h"
00024 #include "fcc_sotp.h"
00025 #include "general_utils.h"
00026 #include "fcc_time_profiling.h"
00027 #include "fcc_utils.h"
00028 #include "fcc_bundle_fields.h"
00029 
00030 /**
00031 * Defines for cbor layer
00032 */
00033 #ifdef USE_CBOR_CONTEXT
00034 #define CONTEXT_NULL , NULL
00035 #define CONTEXT_NULL_COMMA NULL,
00036 #else
00037 #define CONTEXT_NULL
00038 #define CONTEXT_NULL_COMMA
00039 #endif
00040 
00041 /**
00042 * Definition of size and value of current protocol scheme version
00043 */
00044 #define FCC_SIZE_OF_VERSION_FIELD 5
00045 const char fcc_bundle_scheme_version[] = "0.0.1";
00046 extern bool g_is_session_finished;
00047 
00048 // FIXME: temporary. Will be removed when migration to tinycbor is complete
00049 void g_csr_buf_free();
00050 
00051 /**
00052 * Types of configuration parameter groups
00053 */
00054 typedef enum {
00055     FCC_KEY_GROUP_TYPE,                //!< Key group type
00056     FCC_CERTIFICATE_GROUP_TYPE,        //!< Certificate group type
00057     FCC_CONFIG_PARAM_GROUP_TYPE,       //!< Configuration parameter group type
00058     FCC_CERTIFICATE_CHAIN_GROUP_TYPE,  //!< Certificate chain group type
00059     FCC_SCHEME_VERSION_TYPE,           //!< Scheme version group type
00060     FCC_ENTROPY_TYPE,                  //!< Entropy group type
00061     FCC_ROT_TYPE,                      //!< Root of trust group type
00062     FCC_VERIFY_DEVICE_IS_READY_TYPE,   //!< Verify device readiness type
00063     FCC_FACTORY_DISABLE_TYPE,          //!< Disable FCC flow type
00064     FCC_IS_ALIVE_SESSION_GROUP_TYPE,   //!< Indicates current message status - last message or not
00065     FCC_FCU_SESSION_ID_GROUP_TYPE,     //!< Session ID sent by the FCU
00066     FCC_CSR_REQUESTS_GROUP_TYPE,       //!< CSR requests type
00067     FCC_MAX_CONFIG_PARAM_GROUP_TYPE    //!< Max group type
00068 } fcc_bundle_param_group_type_e;
00069 
00070 /**
00071 * Group lookup record, correlating group's type and name
00072 */
00073 typedef struct fcc_bundle_group_lookup_record_ {
00074     fcc_bundle_param_group_type_e group_type;
00075     const char *group_name;
00076 } fcc_bundle_group_lookup_record_s;
00077 /**
00078 * Group lookup table, correlating for each group its type and name.
00079 * Order is important - it is the order that fcc_bundle_handler() reads the cbor fields.
00080 * FCC_ENTROPY_TYPE and FCC_ROT_TYPE Must be processed first and second respectively.
00081 */
00082 static const fcc_bundle_group_lookup_record_s fcc_groups_lookup_table[FCC_MAX_CONFIG_PARAM_GROUP_TYPE] = {
00083     { FCC_SCHEME_VERSION_TYPE,           FCC_BUNDLE_SCHEME_GROUP_NAME },
00084     { FCC_ENTROPY_TYPE,                  FCC_ENTROPY_NAME },
00085     { FCC_ROT_TYPE,                      FCC_ROT_NAME },
00086     { FCC_IS_ALIVE_SESSION_GROUP_TYPE,   FCC_KEEP_ALIVE_SESSION_GROUP_NAME },
00087     { FCC_KEY_GROUP_TYPE,                FCC_KEY_GROUP_NAME },
00088     { FCC_CERTIFICATE_GROUP_TYPE,        FCC_CERTIFICATE_GROUP_NAME },
00089     { FCC_CONFIG_PARAM_GROUP_TYPE,       FCC_CONFIG_PARAM_GROUP_NAME },
00090     { FCC_CERTIFICATE_CHAIN_GROUP_TYPE,  FCC_CERTIFICATE_CHAIN_GROUP_NAME },
00091     { FCC_VERIFY_DEVICE_IS_READY_TYPE,   FCC_VERIFY_DEVICE_IS_READY_GROUP_NAME },
00092     { FCC_FACTORY_DISABLE_TYPE,          FCC_FACTORY_DISABLE_GROUP_NAME },
00093     { FCC_FCU_SESSION_ID_GROUP_TYPE,     FCC_FCU_SESSION_ID_GROUP_TYPE_NAME },
00094     { FCC_CSR_REQUESTS_GROUP_TYPE,       FCC_CSR_REQUESTS_GROUP_NAME }
00095 };
00096 
00097 
00098 
00099 
00100 /* Response cbor blob structure
00101 
00102 {  "SchemeVersion": "0.0.1",
00103    "FCUSessionID": uint32_t,
00104    "Csrs": [ {"Name": "__", "Format":"_","Data":"__"},
00105              {"Name": "__", "Format":"_","Data":"__"}],
00106    "WarningInfo": "string of warnings",
00107    "ReturnStatus": uint32_t,
00108    "InfoMessage": "detailed error string"}
00109 */
00110 /** Prepare a response message
00111 *
00112 * The function prepare response buffer according to result of bundle buffer processing.
00113 * In case of failure, the function prepare buffer with status,scheme version and error logs,
00114 * in case of success - only the status and scheme version.
00115 *
00116 * @param bundle_response_out[in/out]   The pointer to response buffer.
00117 * @param bundle_response_size_out[out/out]     The size of response buffer.
00118 * @param fcc_status[in]     The result of bundle buffer processing.
00119 * 
00120 * @return
00121 *     true for success, false otherwise.
00122 */
00123 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)
00124 {
00125     bool status = false;
00126     cn_cbor_errback err;
00127     cn_cbor *cbor_struct_cb = NULL;
00128     int size_of_cbor_buffer = 0;
00129     int size_of_out_buffer = 0;
00130     uint8_t *out_buffer = NULL;
00131     char *error_string_info = NULL;
00132     char *warning_string_info = NULL;
00133     const char success_message[] = { "The Factory process succeeded\n" };
00134     *bundle_response_out = NULL;
00135 
00136     SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS();
00137 
00138     // If error has occurred during bundle processing - create a new encoder (all that was encoded is not needed)
00139     // 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
00140     if (fcc_status != FCC_STATUS_SUCCESS) {
00141         // Free the old encoder and create a new one
00142         if (encoder) {
00143             cn_cbor_free(encoder CBOR_CONTEXT_PARAM);
00144         }
00145         encoder = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &err);
00146         SA_PV_ERR_RECOVERABLE_RETURN_IF((encoder == NULL), false, "Failed to create cbor map");
00147 
00148         /**
00149         * Create cbor with scheme version
00150         */
00151         cbor_struct_cb = NULL;
00152         cbor_struct_cb = cn_cbor_text_create((const uint8_t *)fcc_bundle_scheme_version, sizeof(fcc_bundle_scheme_version) CBOR_CONTEXT_PARAM, &err);
00153         SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create scheme_version_cb ");
00154 
00155         //Put the cbor scheme version in cbor map with string key "SchemeVersion"
00156         status = cn_cbor_mapput_string(encoder, FCC_BUNDLE_SCHEME_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err);
00157         SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed to put return status to cbor map");
00158 
00159         //Put the cbor session ID in cbor map with string key "SID"
00160         if(session_id != NULL) { 
00161             cbor_struct_cb = cn_cbor_text_create(session_id, (int)session_id_len CBOR_CONTEXT_PARAM, &err);
00162             SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "CBOR error");
00163 
00164             status = cn_cbor_mapput_string(encoder, FCC_FCU_SESSION_ID_GROUP_TYPE_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err);
00165             SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed to put return session ID");
00166         }
00167     }
00168 
00169 
00170     /**
00171     * Create cbor with return status
00172     */
00173     cbor_struct_cb = cn_cbor_int_create(fcc_status CBOR_CONTEXT_PARAM, &err);
00174     SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create return_status_cb ");
00175 
00176     //Put the cbor return status in cbor map with string key "ReturnStatus"
00177     status = cn_cbor_mapput_string(encoder, FCC_RETURN_STATUS_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err);
00178     SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put return status to cbor map");
00179 
00180 
00181     /**
00182     * Create cbor with error info
00183     */
00184     cbor_struct_cb = NULL;
00185     if (fcc_status == FCC_STATUS_SUCCESS) {
00186         cbor_struct_cb = cn_cbor_text_create((const uint8_t*)success_message, (int)strlen(success_message) CBOR_CONTEXT_PARAM, &err);
00187     } else {
00188         error_string_info = fcc_get_output_error_info();
00189         if (error_string_info == NULL) {
00190             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);
00191         } else {
00192             cbor_struct_cb = cn_cbor_text_create((const uint8_t*)error_string_info, (int)strlen(error_string_info) CBOR_CONTEXT_PARAM, &err);
00193        }
00194     }
00195     SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create cbor_struct_cb ");
00196 
00197     //Put the cbor info message in cbor map with string key "infoMessage"
00198     status = cn_cbor_mapput_string(encoder, FCC_ERROR_INFO_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err);
00199     SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put cbor_struct_cb to cbor map");
00200 
00201     /**
00202     * Create cbor with warning info
00203     */
00204     cbor_struct_cb = NULL;
00205     status = fcc_get_warning_status();
00206     warning_string_info = fcc_get_output_warning_info();
00207     SA_PV_ERR_RECOVERABLE_GOTO_IF(status == true && warning_string_info == NULL, status = false, exit, "Failed to get created warnings");
00208     if (warning_string_info != NULL) {
00209         cbor_struct_cb = cn_cbor_text_create((const uint8_t *)warning_string_info, (int)strlen(warning_string_info) CBOR_CONTEXT_PARAM, &err);
00210         SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create warning_message_cb ");
00211 
00212         //Put the cbor info message in cbor map with string key "WarningInfo"
00213         status = cn_cbor_mapput_string(encoder, FCC_WARNING_INFO_GROUP_NAME, cbor_struct_cb CBOR_CONTEXT_PARAM, &err);
00214         SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put warning_message_cb to cbor map");
00215     } 
00216 
00217     status = true;
00218     //Get size of encoded cbor buffer
00219     size_of_cbor_buffer = cn_cbor_get_encoded_size(encoder, &err);
00220     SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_cbor_buffer == -1), status = false, exit, "Failed to get cbor buffer size");
00221 
00222     //Allocate out buffer
00223     out_buffer = fcc_malloc((size_t)size_of_cbor_buffer);
00224     SA_PV_ERR_RECOVERABLE_GOTO_IF((out_buffer == NULL), status = false, exit, "Failed to allocate memory for out buffer");
00225 
00226     //Write cbor blob to output buffer
00227     size_of_out_buffer = cn_cbor_encoder_write(encoder, out_buffer, size_of_cbor_buffer, &err);
00228     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");
00229     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");
00230 
00231     //Update pointer and size of output buffer
00232     *bundle_response_out = out_buffer;
00233     *bundle_response_size_out = (size_t)size_of_out_buffer;
00234     goto exit;
00235 
00236 exit_without_out_buffer:
00237     fcc_free(out_buffer);
00238 
00239     // Nullify pointer so that the user cannot accidentally double free it.
00240     *bundle_response_out = NULL;
00241 exit:
00242     // FIXME: Free the CSRs buffer after the writing to the encoder buffer. Not needed after migration to tinycbor
00243     g_csr_buf_free();
00244     fcc_free(warning_string_info);
00245     if (encoder != NULL) {
00246         cn_cbor_free(encoder CBOR_CONTEXT_PARAM);
00247     }
00248     SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
00249     return status;
00250 }
00251 
00252 
00253 /** Checks bundle scheme version
00254 *
00255 * @param cbor_blob[in]   The pointer to main cbor blob.
00256 * @param encoder[in]     Pointer to an encoder that points to the beginning of the CBOR response encoder
00257 *
00258 * 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
00259 * @return
00260 *     true for success, false otherwise.
00261 */
00262 static bool check_scheme_version(cn_cbor *cbor_blob, cn_cbor *encoder)
00263 {
00264     cn_cbor *cbor = NULL;
00265     bool status;
00266     int result;
00267 
00268     SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_blob == NULL), false, "Invalid cbor_blob");
00269 
00270     cbor = cn_cbor_mapget_string(cbor_blob, FCC_BUNDLE_SCHEME_GROUP_NAME);
00271     SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor == NULL), false, "Failed to find scheme version group");
00272 
00273     result = is_memory_equal(cbor->v.bytes, (size_t)(cbor->length), fcc_bundle_scheme_version, (size_t)strlen(fcc_bundle_scheme_version));
00274     SA_PV_ERR_RECOVERABLE_RETURN_IF((!result), false, "Wrong scheme version");
00275 
00276     // append the scheme version key-value into the encoder
00277     cbor = cn_cbor_text_create((const uint8_t *)fcc_bundle_scheme_version, sizeof(fcc_bundle_scheme_version) CBOR_CONTEXT_PARAM, NULL);
00278     SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor == NULL), false, "Failed to create scheme_version_cb ");
00279 
00280     status = cn_cbor_mapput_string(encoder, FCC_BUNDLE_SCHEME_GROUP_NAME, cbor, CBOR_CONTEXT_PARAM_COMMA NULL);
00281     SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), status, "CBOR error");
00282 
00283     return true;
00284 }
00285 
00286 /** Checks the FCU session ID and encodes it into the encoder
00287 *
00288 * @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).
00289 * @param encoder[in]            Pointer to an encoder that points to the beginning of the CBOR response encoder.
00290 * @param session_id[out]        Pointer to a pointer that will point to the session ID in the incoming message.
00291 * @param session_id_len[out]    The length of the session ID in the incoming message.
00292 *
00293 * 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
00294 * @return
00295 *     true for success, false otherwise.
00296 */
00297 static bool fcc_bundle_process_session_id(cn_cbor *parser, cn_cbor *encoder, const uint8_t **session_id, size_t *session_id_len)
00298 {
00299     cn_cbor *cbor = NULL;
00300     bool status;
00301 
00302     // Get the session ID from the message and make sure that it is either a text or bytes string
00303     SA_PV_ERR_RECOVERABLE_RETURN_IF((parser->type != CN_CBOR_TEXT), false, "Session ID of wrong type");
00304 
00305     // Output the values for use of the prepare_reponse_message() function in case of an error during the bundle handling process
00306     *session_id = (uint8_t *)parser->v.bytes;
00307     *session_id_len = (size_t)parser->length;
00308 
00309     cbor = cn_cbor_text_create(*session_id, (int)*session_id_len CBOR_CONTEXT_PARAM, NULL);
00310     SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor == NULL), false, "CBOR error");
00311     
00312     // append the session id key-value into the encoder
00313     status = cn_cbor_mapput_string(encoder, FCC_FCU_SESSION_ID_GROUP_TYPE_NAME, cbor, CBOR_CONTEXT_PARAM_COMMA NULL);
00314     SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), false, "CBOR error");
00315 
00316     return true;
00317 }
00318 
00319 
00320 
00321 /** The function parses group that indicates if current session will be closed after the processing of the message.
00322 *  The function checks existence and value of the group and sets the result to global variable g_is_alive_sesssion.
00323 *
00324 * @param cbor_blob[in]   The pointer to main cbor blob.
00325 * @return
00326 *     true for success, false otherwise.
00327 */
00328 static bool parse_keep_alive_session_group(cn_cbor *cbor_blob)
00329 {
00330     cn_cbor *is_alive_message = NULL;
00331 
00332     is_alive_message = cn_cbor_mapget_string(cbor_blob, FCC_KEEP_ALIVE_SESSION_GROUP_NAME);
00333     //In case current group wasn't found -  set g_is_not_last_message to false (for backward compatibility)
00334     if (is_alive_message == NULL) {
00335         g_is_session_finished = true;
00336         return true;
00337     }
00338     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");
00339 
00340     // Session is finished if value is 0, and alive if value is 1
00341     g_is_session_finished = !(is_alive_message->v.uint);
00342 
00343     return true;
00344 }
00345 
00346 /* CBOR blob structure
00347 {   "SchemeVersion": "0.0.1",
00348     "FCUSessionID": uint32_t,
00349     "IsNotLastMessage": 1 or 0,
00350     "Entropy": [byte array - 48 bytes],
00351     "Csrs": [ {"PrivKeyName":"__",
00352                "PubKeyName": "__", -optional
00353                "Extensions": [
00354                                {"TrustLevel": uint32_t },
00355                                {
00356                                    "KeyUsage":  [uint32_t,uint32_t,unit32_t ],
00357                                },
00358                                {
00359                                    "ExtendedKeyUsage":  [byte array],
00360                                }]
00361                "Subject": "C=__,ST=__ ,L=__, O=__,OU=__,CN=__,",
00362                 },
00363                 { ... },
00364                 { ... }
00365               ],
00366     "ROT": "byte array",
00367     "Certificates": [ {"Name": "__", "Format":" _","Data":"__", "ACL" : "__"},
00368                       {..},
00369                       {"Name": "__", "Format":" _","Data":"__", "ACL" : "__"}],
00370     "Keys": [ {"Name": "__", "Type":"__", "Format":"__", "Data":"**","ACL" : "__"},
00371               {"Name": "__", "Type":"__", "Format":"__", "Data":"**","ACL": "__"},
00372                ...
00373               {"Name": "__", "Type":"__", "Format":"__", "Data":"**","ACL": "__"}],
00374     "ConfigParams": [ {"Name": "__", "Data":"__", "ACL" : "__"},
00375                       {"Name": "__", "Format":"__", "Data":"__", "ACL": "__"},
00376                        ...,
00377                       {"Name": "__", "Format":"__", "Data":"__", "ACL": "__"}],
00378     "CertificateChains": [ {"Name": "mbed.CertificateChain",
00379                             "DataArray":[h'3081870.....',h'308187020100...',h'308187020....'],
00380                             "Format":"Der",
00381                             "ACL":"_____"},
00382                           {"Name": "mbed.LwM2MCertificateChain",
00383                            "DataArray":[h'308187...',h'30818702...',h'308187020...',h'308187020...',h'308187020...'],
00384                            "Format":"Der",
00385                            "ACL":"_____"}],
00386     "Verify":1, 
00387     "Disable":1}
00388 */
00389 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)
00390 {
00391     bool status = false;
00392     bool is_fcc_factory_disabled;
00393     fcc_status_e  fcc_status = FCC_STATUS_SUCCESS;
00394     cn_cbor *main_list_cb = NULL;
00395     cn_cbor *group_value_cb = NULL;
00396     cn_cbor *response_cbor = NULL;
00397     cn_cbor_errback err;
00398     size_t group_index;
00399     fcc_bundle_param_group_type_e group_type;
00400     size_t num_of_groups_in_message = 0;
00401     const uint8_t *session_id = NULL;
00402     size_t session_id_len = 0;
00403     bool fcc_verify_status = true; // the default value of verify status is true
00404     bool fcc_disable_status = false;// the default value of disable status is false
00405 
00406 
00407     FCC_SET_START_TIMER(fcc_bundle_timer);
00408 
00409     SA_PV_LOG_INFO_FUNC_ENTER("encoded_blob_size = %" PRIu32 "", (uint32_t)encoded_blob_size);
00410 
00411     // 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
00412     if (bundle_response_out != NULL) {
00413         // Set to NULL so that the user does not accidentally free a non NULL pointer after the function returns.
00414         *bundle_response_out = NULL;
00415     }
00416 
00417     // Check if factory flow is disabled, if yes, do not proceed
00418     fcc_status = fcc_is_factory_disabled(&is_fcc_factory_disabled);
00419     SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed for fcc_is_factory_disabled");
00420     SA_PV_ERR_RECOVERABLE_RETURN_IF((is_fcc_factory_disabled), FCC_STATUS_FACTORY_DISABLED_ERROR, "FCC is disabled, service not available");
00421 
00422     // Check params
00423     SA_PV_ERR_RECOVERABLE_RETURN_IF((bundle_response_out == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid bundle_response_out");
00424 
00425     SA_PV_ERR_RECOVERABLE_RETURN_IF((bundle_response_size_out == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid bundle_response_size_out");
00426     SA_PV_ERR_RECOVERABLE_GOTO_IF((encoded_blob == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, exit, "Invalid encoded_blob");
00427     SA_PV_ERR_RECOVERABLE_GOTO_IF((encoded_blob_size == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, exit, "Invalid encoded_blob_size");
00428 
00429     /*Initialize fcc_output_info_s structure , in case of error during store process the
00430     function will exit without fcc_verify_device_configured_4mbed_cloud where we perform additional fcc_clean_output_info_handler*/
00431     fcc_clean_output_info_handler();
00432 
00433     // Create the CBOR encoder, an empty map
00434     response_cbor = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &err);
00435     SA_PV_ERR_RECOVERABLE_GOTO_IF((response_cbor == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, exit, "Failed to instatiate cbor structure");
00436 
00437     /* Decode CBOR message
00438     Check the size of the CBOR structure */
00439     main_list_cb = cn_cbor_decode(encoded_blob, encoded_blob_size CBOR_CONTEXT_PARAM, &err);
00440     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);
00441     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");
00442     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");
00443 
00444     /* Check scheme version*/
00445     status = check_scheme_version(main_list_cb, response_cbor);
00446     SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), fcc_status = FCC_STATUS_BUNDLE_INVALID_SCHEME, free_cbor_list_and_out, "check_scheme_version failed");
00447 
00448     /* Parse and save is message status */
00449     status = parse_keep_alive_session_group(main_list_cb);
00450     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");
00451 
00452     //Go over parameter groups
00453     for (group_index = 0; group_index < FCC_MAX_CONFIG_PARAM_GROUP_TYPE; group_index++) {
00454         //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)
00455         SA_PV_LOG_INFO(" fcc_groups_lookup_table[group_index].group_name is %s", fcc_groups_lookup_table[group_index].group_name);
00456         group_value_cb = cn_cbor_mapget_string(main_list_cb, fcc_groups_lookup_table[group_index].group_name);
00457 
00458         if (group_value_cb != NULL) {
00459             //Get type of group
00460             group_type = fcc_groups_lookup_table[group_index].group_type;
00461             num_of_groups_in_message++;
00462 
00463             switch (group_type) {
00464                 case FCC_SCHEME_VERSION_TYPE:
00465                     break;
00466                 case FCC_ENTROPY_TYPE: // Entropy for random generator
00467                     fcc_status = fcc_bundle_process_sotp_buffer(group_value_cb, SOTP_TYPE_RANDOM_SEED);
00468                     SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_sotp_buffer failed for entropy");
00469                     break;
00470                 case FCC_ROT_TYPE: // Key for ESFS
00471                     fcc_status = fcc_bundle_process_sotp_buffer(group_value_cb, SOTP_TYPE_ROT);
00472                     SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_sotp_buffer failed for ROT");
00473                     break;
00474                 case FCC_IS_ALIVE_SESSION_GROUP_TYPE:
00475                     break;
00476                 case FCC_KEY_GROUP_TYPE:
00477                     FCC_SET_START_TIMER(fcc_gen_timer);
00478                     fcc_status = fcc_bundle_process_keys(group_value_cb);
00479                     FCC_END_TIMER("Total keys process", 0 ,fcc_gen_timer);
00480                     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");
00481                     break;
00482                 case FCC_CERTIFICATE_GROUP_TYPE:
00483                     FCC_SET_START_TIMER(fcc_gen_timer);
00484                     fcc_status = fcc_bundle_process_certificates(group_value_cb);
00485                     FCC_END_TIMER("Total certificates process", 0, fcc_gen_timer);
00486                     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");
00487                     break;
00488                 case FCC_CONFIG_PARAM_GROUP_TYPE:
00489                     FCC_SET_START_TIMER(fcc_gen_timer);
00490                     fcc_status = fcc_bundle_process_config_params(group_value_cb);
00491                     FCC_END_TIMER("Total config params process", 0, fcc_gen_timer);
00492                     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");
00493                     break;
00494                 case FCC_CERTIFICATE_CHAIN_GROUP_TYPE:
00495                     FCC_SET_START_TIMER(fcc_gen_timer);
00496                     fcc_status = fcc_bundle_process_certificate_chains(group_value_cb);
00497                     FCC_END_TIMER("Total certificate chains process", 0, fcc_gen_timer);
00498                     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");
00499                     break;
00500                 case FCC_VERIFY_DEVICE_IS_READY_TYPE: //Check if device need to be verified
00501                     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);
00502                     SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "process_device_verify failed");
00503                     break;
00504                 case FCC_FACTORY_DISABLE_TYPE://Check if device need to be disabled for factory
00505                     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);
00506                     SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_factory_disable failed");
00507                     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");
00508                     break;
00509                 case FCC_FCU_SESSION_ID_GROUP_TYPE:
00510                     status = fcc_bundle_process_session_id(group_value_cb, response_cbor, &session_id, &session_id_len);
00511                     SA_PV_ERR_RECOVERABLE_GOTO_IF((!status), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "fcc_bundle_process_session_id failed");
00512                     break;
00513                 case FCC_CSR_REQUESTS_GROUP_TYPE:
00514                     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");
00515                     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");
00516                     fcc_status = fcc_bundle_process_csrs(group_value_cb, response_cbor);
00517                     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");
00518                     break;
00519                 default:
00520                     fcc_status = FCC_STATUS_BUNDLE_UNSUPPORTED_GROUP;
00521                     SA_PV_LOG_ERR("Wrong group type");
00522                     goto free_cbor_list_and_out;
00523             }
00524         }
00525     }
00526 
00527     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");
00528     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");
00529 
00530     // If not keep alive
00531     if (g_is_session_finished) {
00532         // Note that FCC_STATUS_CA_ERROR is being return only in case where the CA already exists
00533         // in SOTP, if in the future more error conditions will be attached to FCC_STATUS_CA_ERROR error code
00534         // then the logic here MUST be change.
00535         // Only if this is the last message - set the certificate ID
00536         fcc_status = fcc_trust_ca_cert_id_set();
00537         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);
00538 
00539     }
00540 
00541     if (fcc_verify_status == true) {
00542         // device VERIFY group does NOT exist in the CBOR message and device is NOT disabled.
00543         // Perform device verification to keep backward compatibility.
00544 
00545 
00546         FCC_SET_START_TIMER(fcc_gen_timer);
00547         fcc_status = fcc_verify_device_configured_4mbed_cloud();
00548         FCC_END_TIMER("Total verify device", 0, fcc_gen_timer);
00549         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");
00550     }
00551 
00552     if (fcc_disable_status == true) {
00553         fcc_status = fcc_bundle_factory_disable();
00554         SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_factory_disable failed");
00555     }
00556 
00557 free_cbor_list_and_out:
00558     cn_cbor_free(main_list_cb CBOR_CONTEXT_PARAM);
00559 exit:
00560     //Prepare bundle response message
00561     status = prepare_reponse_message(bundle_response_out, bundle_response_size_out, fcc_status, response_cbor, session_id, session_id_len);
00562     SA_PV_ERR_RECOVERABLE_RETURN_IF((status != true), FCC_STATUS_BUNDLE_RESPONSE_ERROR, "Failed to prepare out response");
00563     SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS();
00564     FCC_END_TIMER("Total fcc_bundle_handler device", 0, fcc_bundle_timer);
00565     
00566     return fcc_status;
00567 }
00568 #endif