Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ConnectorClient.cpp Source File

ConnectorClient.cpp

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 // fixup the compilation on ARMCC for PRId32
00020 #define __STDC_FORMAT_MACROS
00021 #include <inttypes.h>
00022 
00023 #include "include/ConnectorClient.h"
00024 #include "include/CloudClientStorage.h"
00025 #include "include/CertificateParser.h"
00026 
00027 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
00028 #include "include/EstClient.h"
00029 #endif // !MBED_CLIENT_DISABLE_EST_FEATURE
00030 
00031 #include "MbedCloudClient.h"
00032 #include "mbed-client/m2mconstants.h"
00033 #include "mbed-client/m2minterfacefactory.h"
00034 #include "mbed-client/m2mdevice.h"
00035 #include "mbed-client/m2mconstants.h"
00036 #include "mbed-trace/mbed_trace.h"
00037 #include "factory_configurator_client.h"
00038 #include "key_config_manager.h"
00039 #include "mbed-client/uriqueryparser.h"
00040 #include "randLIB.h"
00041 
00042 #include <assert.h>
00043 #include <string.h>
00044 #include <stdio.h>
00045 
00046 #include "ns_hal_init.h"
00047 
00048 #ifdef MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE
00049 #define MBED_CLIENT_EVENT_LOOP_SIZE MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE
00050 #else
00051 #define MBED_CLIENT_EVENT_LOOP_SIZE 1024
00052 #endif
00053 
00054 #define TRACE_GROUP "mClt"
00055 
00056 #define INTERNAL_ENDPOINT_PARAM     "&iep="
00057 #define DEFAULT_ENDPOINT            "endpoint"
00058 #define INTERFACE_ERROR             "Client interface is not created. Restart"
00059 #define CREDENTIAL_ERROR            "Failed to read credentials from storage"
00060 #define DEVICE_NOT_PROVISIONED      "Device not provisioned"
00061 #define CONNECTOR_ERROR_NO_MEMORY   "Not enough memory to store LWM2M credentials"
00062 #define CONNECTOR_BOOTSTRAP_AGAIN   "Re-bootstrapping"
00063 
00064 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
00065 #define ERROR_EST_ENROLLMENT_REQUEST_FAILED   "EST enrollment request failed"
00066 #define LWM2M_CSR_SUBJECT_FORMAT              "L=%s,OU=%s,CN=%s"
00067 #endif // !MBED_CLIENT_DISABLE_EST_FEATURE
00068 
00069 #define MAX_REBOOTSTRAP_TIMEOUT 21600 // 6 hours
00070 
00071 // XXX: nothing here yet
00072 class EventData {
00073 
00074 };
00075 
00076 static int read_callback_helper(const char *key, void *buffer, size_t *buffer_len)
00077 {
00078     size_t cert_size = 0;
00079     if (strcmp(key, g_fcc_lwm2m_device_private_key_name) == 0 ||
00080         strcmp(key, g_fcc_bootstrap_device_private_key_name) == 0) {
00081         if (ccs_item_size(key, buffer_len, CCS_PRIVATE_KEY_ITEM) != CCS_STATUS_SUCCESS) {
00082             *buffer_len = 0;
00083             return CCS_STATUS_ERROR;
00084         }
00085 
00086         if (ccs_get_item(key, (uint8_t*)buffer, *buffer_len, &cert_size, CCS_PRIVATE_KEY_ITEM) != CCS_STATUS_SUCCESS) {
00087             *buffer_len = 0;
00088             return CCS_STATUS_ERROR;
00089         }
00090     } else {
00091         if (ccs_item_size(key, buffer_len, CCS_CERTIFICATE_ITEM) != CCS_STATUS_SUCCESS) {
00092             *buffer_len = 0;
00093             return CCS_STATUS_ERROR;
00094         }
00095 
00096         if (ccs_get_item(key, (uint8_t*)buffer, *buffer_len, &cert_size, CCS_CERTIFICATE_ITEM) != CCS_STATUS_SUCCESS) {
00097             *buffer_len = 0;
00098             return CCS_STATUS_ERROR;
00099         }
00100     }
00101 
00102     *buffer_len = cert_size;
00103 
00104     return CCS_STATUS_SUCCESS;
00105 }
00106 
00107 static bool write_security_object_data_to_kcm(const M2MResourceBase& resource, const uint8_t *buffer, const size_t buffer_size, void */*client_args*/)
00108 {
00109     ccs_status_e status = CCS_STATUS_ERROR;
00110     uint32_t resource_id = resource.name_id();
00111     uint16_t object_instance_id = resource.object_instance_id();
00112 
00113     switch (resource_id) {
00114         case M2MSecurity::PublicKey:
00115             if (object_instance_id == M2MSecurity::Bootstrap) {
00116                 ccs_delete_item(g_fcc_bootstrap_device_certificate_name, CCS_CERTIFICATE_ITEM);
00117                 status = ccs_set_item(g_fcc_bootstrap_device_certificate_name, buffer, buffer_size, CCS_CERTIFICATE_ITEM);
00118             } else {
00119                 ccs_delete_item(g_fcc_lwm2m_device_certificate_name, CCS_CERTIFICATE_ITEM);
00120                 status = ccs_set_item(g_fcc_lwm2m_device_certificate_name, buffer, buffer_size, CCS_CERTIFICATE_ITEM);
00121             }
00122             break;
00123 
00124         case M2MSecurity::ServerPublicKey:
00125             if (object_instance_id == M2MSecurity::Bootstrap) {
00126                 ccs_delete_item(g_fcc_bootstrap_server_ca_certificate_name, CCS_CERTIFICATE_ITEM);
00127                 status = ccs_set_item(g_fcc_bootstrap_server_ca_certificate_name, buffer, buffer_size, CCS_CERTIFICATE_ITEM);
00128             } else {
00129                 ccs_delete_item(g_fcc_lwm2m_server_ca_certificate_name, CCS_CERTIFICATE_ITEM);
00130                 status = ccs_set_item(g_fcc_lwm2m_server_ca_certificate_name, buffer, buffer_size, CCS_CERTIFICATE_ITEM);
00131             }
00132             break;
00133 
00134         case M2MSecurity::Secretkey:
00135             if (object_instance_id == M2MSecurity::Bootstrap) {
00136                 ccs_delete_item(g_fcc_bootstrap_device_private_key_name, CCS_PRIVATE_KEY_ITEM);
00137                 status = ccs_set_item(g_fcc_bootstrap_device_private_key_name, buffer, buffer_size, CCS_PRIVATE_KEY_ITEM);
00138             } else {
00139                 ccs_delete_item(g_fcc_lwm2m_device_private_key_name, CCS_PRIVATE_KEY_ITEM);
00140                 status = ccs_set_item(g_fcc_lwm2m_device_private_key_name, buffer, buffer_size, CCS_PRIVATE_KEY_ITEM);
00141             }
00142             break;
00143 
00144         default:
00145             break;
00146     }
00147 
00148     return (status == CCS_STATUS_SUCCESS) ? true : false;
00149 }
00150 
00151 static int read_security_object_data_from_kcm(const M2MResourceBase& resource, void *buffer, size_t *buffer_len, void */*client_args*/)
00152 {
00153     uint32_t resource_id = resource.name_id();
00154     uint16_t object_instance_id = resource.object_instance_id();
00155     switch (resource_id) {
00156         case M2MSecurity::PublicKey:
00157             if (object_instance_id == M2MSecurity::Bootstrap) {
00158                 return read_callback_helper(g_fcc_bootstrap_device_certificate_name, buffer, buffer_len);
00159             } else {
00160                 return read_callback_helper(g_fcc_lwm2m_device_certificate_name, buffer, buffer_len);
00161             }
00162 
00163         case M2MSecurity::ServerPublicKey:
00164             if (object_instance_id == M2MSecurity::Bootstrap) {
00165                 return read_callback_helper(g_fcc_bootstrap_server_ca_certificate_name, buffer, buffer_len);
00166             } else {
00167                 return read_callback_helper(g_fcc_lwm2m_server_ca_certificate_name, buffer, buffer_len);
00168             }
00169 
00170         case M2MSecurity::Secretkey:
00171             if (object_instance_id == M2MSecurity::Bootstrap) {
00172                 return read_callback_helper(g_fcc_bootstrap_device_private_key_name, buffer, buffer_len);
00173             } else {
00174                 return read_callback_helper(g_fcc_lwm2m_device_private_key_name, buffer, buffer_len);
00175             }
00176 
00177         default:
00178             break;
00179     }
00180 
00181     return CCS_STATUS_ERROR;
00182 }
00183 
00184 static int open_certificate_chain_callback(const M2MResourceBase& resource, void */*buffer*/, size_t *chain_size, void *client_args)
00185 {
00186     void *handle = NULL;
00187     uint16_t object_instance_id = resource.object_instance_id();
00188     ConnectorClient *client = (ConnectorClient*)client_args;
00189     if (object_instance_id == M2MSecurity::Bootstrap) {
00190         handle = ccs_open_certificate_chain(g_fcc_bootstrap_device_certificate_name, chain_size);
00191         client->set_certificate_chain_handle(handle);
00192     } else {
00193         handle = ccs_open_certificate_chain(g_fcc_lwm2m_device_certificate_name, chain_size);
00194         client->set_certificate_chain_handle(handle);
00195     }
00196 
00197     return (handle) ? CCS_STATUS_SUCCESS : CCS_STATUS_ERROR;
00198 }
00199 
00200 static int read_certificate_chain_callback(const M2MResourceBase& /*resource*/, void *buffer, size_t *buffer_len, void *client_args)
00201 {
00202     ConnectorClient *client = (ConnectorClient*) client_args;
00203     ccs_status_e status = CCS_STATUS_ERROR;
00204     if (client->certificate_chain_handle()) {
00205         status = ccs_get_next_cert_chain(client->certificate_chain_handle(), buffer, buffer_len);
00206     }
00207 
00208     return status;
00209 }
00210 
00211 static int close_certificate_chain_callback(const M2MResourceBase& /*resource*/, void */*buffer*/, size_t *, void *client_args)
00212 {
00213     ccs_status_e status = CCS_STATUS_ERROR;
00214     ConnectorClient *client = (ConnectorClient*) client_args;
00215     if (client->certificate_chain_handle()) {
00216         status = ccs_close_certificate_chain(client->certificate_chain_handle());
00217         client->set_certificate_chain_handle(NULL);
00218     }
00219     return status;
00220 }
00221 
00222 ConnectorClient::ConnectorClient(ConnectorClientCallback* callback)
00223 : _callback(callback),
00224   _current_state(State_Bootstrap_Start),
00225   _event_generated(false), _state_engine_running(false),
00226   _setup_complete(false),
00227   _interface(NULL), _security(NULL),
00228   _endpoint_info(M2MSecurity::Certificate), _client_objs(NULL),
00229   _rebootstrap_timer(*this), _bootstrap_security_instance(1),
00230   _lwm2m_security_instance(0), _certificate_chain_handle(NULL)
00231 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
00232   ,_est_client(*this)
00233 #endif // !MBED_CLIENT_DISABLE_EST_FEATURE
00234 
00235 {
00236     assert(_callback != NULL);
00237 
00238     _rebootstrap_time = randLIB_get_random_in_range(1, 10);
00239 }
00240 
00241 
00242 ConnectorClient::~ConnectorClient()
00243 {
00244     uninitialize_storage();
00245     M2MDevice::delete_instance();
00246     M2MSecurity::delete_instance();
00247     delete _interface;
00248 }
00249 
00250 bool ConnectorClient::setup()
00251 {
00252     // the setup() may be called again after connection has been closed so let's avoid leaks
00253     if (_setup_complete == false) {
00254 
00255         // The ns_hal_init() needs to be called by someone before create_interface(),
00256         // as it will also initialize the tasklet.
00257         ns_hal_init(NULL, MBED_CLIENT_EVENT_LOOP_SIZE, NULL, NULL);
00258 
00259         // Create the lwm2m server security object we need always
00260         M2MSecurity *security = M2MInterfaceFactory::create_security(M2MSecurity::M2MServer);
00261         M2MInterface *interface = M2MInterfaceFactory::create_interface(*this,
00262                                                           DEFAULT_ENDPOINT,                     // endpoint name string
00263                                                           MBED_CLOUD_CLIENT_ENDPOINT_TYPE,      // endpoint type string
00264                                                           MBED_CLOUD_CLIENT_LIFETIME,           // lifetime
00265                                                           MBED_CLOUD_CLIENT_LISTEN_PORT,        // listen port
00266                                                           _endpoint_info.account_id,            // domain string
00267                                                           transport_mode(),                     // binding mode
00268                                                           M2MInterface::LwIP_IPv4);             // network stack
00269 
00270         if ((security == NULL) || (interface == NULL)) {
00271             M2MSecurity::delete_instance();
00272             delete interface;
00273         } else {
00274             if (initialize_storage() == CCS_STATUS_SUCCESS) {
00275                 _security = security;
00276                 _interface = interface;
00277                 _setup_complete = true;
00278             }
00279         }
00280     }
00281 
00282     return _setup_complete;
00283 }
00284 
00285 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
00286 const EstClient &ConnectorClient::est_client()
00287 {
00288     return _est_client;
00289 }
00290 #endif // !MBED_CLIENT_DISABLE_EST_FEATURE
00291 
00292 void ConnectorClient::start_bootstrap()
00293 {
00294     tr_debug("ConnectorClient::start_bootstrap()");
00295 
00296     assert(_callback != NULL);
00297     assert(_setup_complete);
00298 
00299     init_security_object();
00300     // Stop rebootstrap timer if it was running
00301     _rebootstrap_timer.stop_timer();
00302 
00303     if (create_bootstrap_object()) {
00304         _interface->update_endpoint(_endpoint_info.endpoint_name);
00305         _interface->update_domain(_endpoint_info.account_id);
00306         internal_event(State_Bootstrap_Start);
00307     } else {
00308         tr_error("ConnectorClient::start_bootstrap() - bootstrap object fail");
00309     }
00310     state_engine();
00311 }
00312 
00313 void ConnectorClient::start_registration(M2MBaseList* client_objs)
00314 {
00315     tr_debug("ConnectorClient::start_registration()");
00316 
00317     assert(_callback != NULL);
00318     assert(_setup_complete);
00319 
00320     init_security_object();
00321     _client_objs = client_objs;
00322 
00323     // XXX: actually this call should be external_event() to match the pattern used in other m2m classes
00324     if (create_register_object()) {
00325         if(_security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) {
00326             _interface->update_endpoint(_endpoint_info.endpoint_name);
00327             _interface->update_domain(_endpoint_info.account_id);
00328             internal_event(State_Registration_Start);
00329         } else {
00330             tr_error("ConnectorClient::start_registration(): failed to create objs");
00331             _callback->connector_error(M2MInterface::InvalidParameters, INTERFACE_ERROR);
00332         }
00333     } else {
00334         tr_error("ConnectorClient::start_registration - failed to read credentials");
00335         _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials, CREDENTIAL_ERROR);
00336     }
00337     state_engine();
00338 }
00339 
00340 M2MInterface * ConnectorClient::m2m_interface()
00341 {
00342     return _interface;
00343 }
00344 
00345 void ConnectorClient::update_registration()
00346 {
00347     if(_interface && _security && _security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) {
00348         if (_client_objs != NULL) {
00349             _interface->update_registration(_security, *_client_objs);
00350         }
00351         else {
00352             _interface->update_registration(_security);
00353         }
00354     }
00355 }
00356 
00357 // generates an internal event. called from within a state
00358 // function to transition to a new state
00359 void ConnectorClient::internal_event(StartupSubStateRegistration new_state)
00360 {
00361     tr_debug("ConnectorClient::internal_event: state: %d -> %d", _current_state, new_state);
00362     _event_generated = true;
00363     _current_state = new_state;
00364 
00365     // Avoid recursive chain which eats too much of stack
00366     if (!_state_engine_running) {
00367         state_engine();
00368     }
00369 }
00370 
00371 // the state engine executes the state machine states
00372 void ConnectorClient::state_engine(void)
00373 {
00374     tr_debug("ConnectorClient::state_engine");
00375 
00376     // this simple flagging gets rid of recursive calls to this method
00377     _state_engine_running = true;
00378 
00379     // while events are being generated keep executing states
00380     while (_event_generated) {
00381         _event_generated = false;  // event used up, reset flag
00382 
00383         state_function(_current_state);
00384     }
00385 
00386     _state_engine_running = false;
00387 }
00388 
00389 void ConnectorClient::state_function(StartupSubStateRegistration current_state)
00390 {
00391     switch (current_state) {
00392         case State_Bootstrap_Start:
00393             state_bootstrap_start();
00394             break;
00395         case State_Bootstrap_Started:
00396             state_bootstrap_started();
00397             break;
00398         case State_Bootstrap_Success:
00399             state_bootstrap_success();
00400             break;
00401         case State_Bootstrap_Failure:
00402             state_bootstrap_failure();
00403             break;
00404 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
00405         case State_EST_Start:
00406             state_est_start();
00407             break;
00408         case State_EST_Started:
00409             state_est_started();
00410             break;
00411         case State_EST_Success:
00412             state_est_success();
00413             break;
00414         case State_EST_Failure:
00415             state_est_failure();
00416             break;
00417 #endif // !MBED_CLIENT_DISABLE_EST_FEATURE
00418         case State_Registration_Start:
00419             state_registration_start();
00420             break;
00421         case State_Registration_Started:
00422             state_registration_started();
00423             break;
00424         case State_Registration_Success:
00425             state_registration_success();
00426             break;
00427         case State_Registration_Failure:
00428             state_registration_failure();
00429             break;
00430         case State_Unregistered:
00431             state_unregistered();
00432             break;
00433         default:
00434             break;
00435     }
00436 }
00437 
00438 /*
00439 *  Creates register server object with mbed device server address and other parameters
00440 *  required for client to connect to mbed device server.
00441 */
00442 bool ConnectorClient::create_register_object()
00443 {
00444     tr_debug("ConnectorClient::create_register_object()");
00445     int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00446     if (m2m_id == -1) {
00447         init_security_object();
00448     }
00449 
00450     m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00451     if (m2m_id == -1) {
00452         tr_error("ConnectorClient::create_register_object() - failed to read security object!");
00453         return false;
00454     }
00455 
00456     // Allocate scratch buffer, this will be used to copy parameters from storage to security object
00457     const int max_size = MAX_CERTIFICATE_SIZE;
00458     uint8_t *buffer = (uint8_t*)malloc(max_size);
00459     size_t real_size = 0;
00460     bool success = false;
00461 
00462     if (_security->set_resource_value(M2MSecurity::BootstrapServer, M2MSecurity::M2MServer, m2m_id)) {
00463         success = true;
00464     }
00465 
00466     // Add ResourceID's and values to the security ObjectID/ObjectInstance
00467     if (success) {
00468         success = false;
00469         if (_security->set_resource_value(M2MSecurity::SecurityMode, _endpoint_info.mode, m2m_id)) {
00470             success = true;
00471         }
00472     }
00473 
00474     if (success && buffer == NULL) {
00475         success = false;
00476     }
00477 
00478     // Endpoint
00479     if (success) {
00480         success = false;
00481         char device_id[64];
00482 
00483         size_t cert_size = max_size;
00484         uint8_t certificate[MAX_CERTIFICATE_SIZE];
00485         uint8_t *certificate_ptr = (uint8_t*)&certificate;
00486 
00487         // TODO! Update to use chain api
00488         if (_security->resource_value_buffer(M2MSecurity::PublicKey, certificate_ptr, m2m_id, &cert_size) == 0) {
00489             real_size = cert_size;
00490             if (extract_field_from_certificate((uint8_t*)certificate, real_size, "CN", device_id)) {
00491                 tr_info("ConnectorClient::create_register_object - CN - endpoint_name : %s", device_id);
00492                 _endpoint_info.endpoint_name = String(device_id);
00493                 success = true;
00494             } else {
00495                 tr_error("KEY_ENDPOINT_NAME failed.");
00496             }
00497         }
00498     }
00499 
00500     // Connector URL
00501     if (success) {
00502         success = false;
00503         if (ccs_get_item(g_fcc_lwm2m_server_uri_name, buffer, max_size, &real_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00504             tr_info("ConnectorClient::create_register_object - M2MServerUri %.*s", (int)real_size, buffer);
00505             if (_security->set_resource_value(M2MSecurity::M2MServerUri, buffer, (uint32_t)real_size, m2m_id)) {
00506                 success = true;
00507             }
00508 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
00509             _endpoint_info.lwm2m_server_uri = _security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id);
00510 #endif
00511         }
00512         else {
00513             tr_error("KEY_CONNECTOR_URL failed.");
00514         }
00515     }
00516 
00517     // Try to get internal endpoint name
00518     if (success) {
00519         if (ccs_get_item(KEY_INTERNAL_ENDPOINT, buffer, max_size, &real_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00520             _endpoint_info.internal_endpoint_name = String((const char*)buffer, real_size);
00521             tr_info("ConnectorClient::create_register_object - internal endpoint name : %s", _endpoint_info.internal_endpoint_name.c_str());
00522         }
00523         else {
00524             tr_debug("KEY_INTERNAL_ENDPOINT failed.");
00525         }
00526     }
00527 
00528     if (success) {
00529         success = false;
00530         if (ccs_get_item(KEY_ACCOUNT_ID, buffer, max_size, &real_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00531             tr_info("ConnectorClient::create_register_object - AccountId %.*s", (int)real_size, buffer);
00532             _endpoint_info.account_id = String((const char*)buffer, real_size);
00533             success = true;
00534         } else {
00535             if (ccs_get_item(g_fcc_lwm2m_server_uri_name, buffer, max_size, &real_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00536                 String address((const char*)buffer, real_size);
00537                 if (address.size() > 0) {
00538                     const char *aid = NULL;
00539                     const int aid_size = parse_query_parameter_value_from_uri((const char*)address.c_str(), QUERY_PARAM_AID, &aid);
00540                     if (aid_size > 0) {
00541                         _endpoint_info.account_id.clear();
00542                         _endpoint_info.account_id.append_raw(aid, aid_size);
00543                         if (ccs_set_item(KEY_ACCOUNT_ID,
00544                                 (const uint8_t*)_endpoint_info.account_id.c_str(),
00545                                 (size_t)_endpoint_info.account_id.size(), CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00546                             success = true;
00547                             tr_info("ConnectorClient::create_register_object - aid from uri %s", _endpoint_info.account_id.c_str());
00548                         } else {
00549                             tr_error("ConnectorClient::create_register_object - failed to store aid");
00550                         }
00551 
00552                     }
00553                 }
00554             }
00555         }
00556     }
00557 
00558     free(buffer);
00559 
00560     return success;
00561 }
00562 
00563 /*
00564 *  Creates bootstrap server object with bootstrap server address and other parameters
00565 *  required for connecting to mbed Cloud bootstrap server.
00566 */
00567 bool ConnectorClient::create_bootstrap_object()
00568 {
00569     tr_debug("ConnectorClient::create_bootstrap_object");
00570     bool success = false;
00571 
00572     // Check if bootstrap credentials are already stored in KCM
00573     if (bootstrap_credentials_stored_in_kcm() && _security) {
00574         int32_t bs_id = _security->get_security_instance_id(M2MSecurity::Bootstrap);
00575         if (_security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::Certificate, bs_id)) {
00576             success = true;
00577         }
00578 
00579         tr_info("ConnectorClient::create_bootstrap_object - bs_id = %" PRId32, bs_id);
00580         tr_info("ConnectorClient::create_bootstrap_object - use credentials from storage");
00581 
00582         // Allocate scratch buffer, this will be used to copy parameters from storage to security object
00583         size_t real_size = 0;
00584         const int max_size = MAX_CERTIFICATE_SIZE;
00585         uint8_t *buffer = NULL;
00586         if (success) {
00587             success = false;
00588             buffer = (uint8_t*)malloc(max_size);
00589             if (buffer != NULL) {
00590                 success = true;
00591             }
00592         }
00593 
00594         // Read internal endpoint name if it exists, we need to append
00595         // it to bootstrap uri if device already bootstrapped
00596         uint8_t *iep = NULL;
00597         if (success && ccs_get_string_item(KEY_INTERNAL_ENDPOINT, buffer, max_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00598             iep = (uint8_t*)malloc(strlen((const char*)buffer) + strlen(INTERNAL_ENDPOINT_PARAM) + 1);
00599             if (iep != NULL) {
00600                 strcpy((char*)iep, INTERNAL_ENDPOINT_PARAM);
00601                 strcat((char*)iep, (const char*)buffer);
00602                 tr_info("ConnectorClient::create_bootstrap_object - iep: %s", buffer);
00603             }
00604             //TODO: Should handle error if iep exists but allocation fails?
00605         }
00606 
00607         // Bootstrap URI
00608         if (success) {
00609             success = false;
00610             if (ccs_get_string_item(g_fcc_bootstrap_server_uri_name, buffer, max_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00611                 real_size = strlen((const char*)buffer);
00612 
00613                 // Append iep if we 1. have it 2. it doesn't already exist in uri 3. it fits
00614                 if (iep &&
00615                     strstr((const char*)buffer, (const char*)iep) == NULL &&
00616                     (real_size + strlen((const char*)iep) + 1) <= max_size) {
00617                     strcat((char*)buffer, (const char*)iep);
00618                     real_size += strlen((const char*)iep) + 1;
00619                 }
00620 
00621                 tr_info("ConnectorClient::create_bootstrap_object - M2MServerUri %.*s", (int)real_size, buffer);
00622                 if (_security->set_resource_value(M2MSecurity::M2MServerUri, buffer, real_size, bs_id)) {
00623                     success = true;
00624                 }
00625             }
00626         }
00627 
00628         free(iep);
00629 
00630         // Endpoint
00631         if (success) {
00632             success = false;
00633             if (ccs_get_item(g_fcc_endpoint_parameter_name, buffer, max_size, &real_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00634                 success = true;
00635                 _endpoint_info.endpoint_name = String((const char*)buffer, real_size);
00636                 tr_info("ConnectorClient::create_bootstrap_object - Endpoint %s", _endpoint_info.endpoint_name.c_str());
00637             }
00638         }
00639 
00640         // Account ID, not mandatory
00641         if (success) {
00642             if (ccs_get_item(KEY_ACCOUNT_ID, buffer, max_size, &real_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00643                 _endpoint_info.account_id = String((const char*)buffer, real_size);
00644                 tr_info("ConnectorClient::create_bootstrap_object - AccountId %s", _endpoint_info.account_id.c_str());
00645             }
00646         }
00647 
00648         free(buffer);
00649 
00650         if (!success) {
00651             tr_error("ConnectorClient::create_bootstrap_object - Failed to read credentials");
00652             _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials,CREDENTIAL_ERROR);
00653             _security->remove_object_instance(bs_id);
00654         }
00655     } else {
00656         success = true;
00657         tr_info("ConnectorClient::create_bootstrap_object - bootstrap object already done");
00658     }
00659 
00660 
00661     return success;
00662 }
00663 
00664 void ConnectorClient::state_bootstrap_start()
00665 {
00666     tr_info("ConnectorClient::state_bootstrap_start()");
00667     assert(_interface != NULL);
00668     assert(_security != NULL);
00669 
00670     _interface->bootstrap(_security);
00671 
00672     internal_event(State_Bootstrap_Started);
00673 }
00674 
00675 void ConnectorClient::state_bootstrap_started()
00676 {
00677     // this state may be useful only for verifying the callbacks?
00678 }
00679 
00680 void ConnectorClient::state_bootstrap_success()
00681 {
00682     assert(_callback != NULL);
00683     // Parse internal endpoint name from mDS cert
00684     _callback->registration_process_result(State_Bootstrap_Success);
00685 }
00686 
00687 void ConnectorClient::state_bootstrap_failure()
00688 {
00689     assert(_callback != NULL);
00690     // maybe some additional canceling and/or leanup is needed here?
00691     _callback->registration_process_result(State_Bootstrap_Failure);
00692 }
00693 
00694 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
00695 void ConnectorClient::state_est_start()
00696 {
00697     // - Generate CSR from data during bootstrap phase
00698     // - Call EST enrollment API from InterfaceImpl
00699 
00700     // Update the internal endpoint name and account id to endpoint info structure
00701     // as we get those during bootstrap phase
00702     _endpoint_info.internal_endpoint_name = _interface->internal_endpoint_name();
00703 
00704     int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00705     int32_t sec_mode = M2MSecurity::SecurityNotSet;
00706     if (m2m_id >= 0) {
00707         sec_mode = _security->resource_value_int(M2MSecurity::SecurityMode, m2m_id);
00708 
00709         // We need to parse account id from lwm2m server uri query if it is not yet
00710         // set in endpoint info structure
00711         if (_endpoint_info.account_id.length() <= 0) {
00712             String address = _security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id);
00713             tr_debug("ConnectorClient::state_est_start - address: %s", address.c_str());
00714             if (address.size() > 0) {
00715                 const char *aid = NULL;
00716                 const int aid_size = parse_query_parameter_value_from_uri((const char*)address.c_str(), QUERY_PARAM_AID, &aid);
00717                 if (aid_size > 0) {
00718                     _endpoint_info.account_id.append_raw(aid, aid_size);
00719                 }
00720             }
00721         }
00722     }
00723 
00724     tr_debug("ConnectorClient::state_est_start - security instance id: %" PRId32, m2m_id);
00725     tr_debug("ConnectorClient::state_est_start - ep: %s", _endpoint_info.internal_endpoint_name.c_str());
00726     tr_debug("ConnectorClient::state_est_start - iep: %s", _endpoint_info.endpoint_name.c_str());
00727     tr_debug("ConnectorClient::state_est_start - aid: %s", _endpoint_info.account_id.c_str());
00728 
00729     // Check EST required parameters are in place
00730     if (m2m_id < 0 ||
00731         _endpoint_info.endpoint_name.length() <= 0 ||
00732         _endpoint_info.internal_endpoint_name.length() <= 0 ||
00733         _endpoint_info.account_id.length() <= 0) {
00734         tr_error("ConnectorClient::state_est_start - Missing parameters for EST enrollment!");
00735         internal_event(State_EST_Failure);
00736         return;
00737     }
00738 
00739     uint32_t is_bs_server = _security->resource_value_int(M2MSecurity::BootstrapServer, m2m_id);
00740     size_t public_key_size = MAX_CERTIFICATE_SIZE;
00741     size_t server_key_size = MAX_CERTIFICATE_SIZE;
00742     size_t private_key_size = MAX_CERTIFICATE_SIZE;
00743 
00744     // Temp buffer for storing CSR and certificates
00745     uint8_t *buffer = (uint8_t*)malloc(MAX_CERTIFICATE_SIZE);
00746     size_t real_size = 0;
00747     if (buffer == NULL) {
00748         tr_error("ConnectorClient::state_est_start - Allocating temp buffer failed!");
00749         internal_event(State_EST_Failure);
00750         return;
00751     }
00752     uint8_t *buffer_ptr = buffer;
00753 
00754     // TODO! Update to use chain api
00755     if (_security->resource_value_buffer(M2MSecurity::PublicKey, buffer_ptr, m2m_id, &public_key_size) != 0) {
00756         public_key_size = 0;
00757     }
00758     if (_security->resource_value_buffer(M2MSecurity::ServerPublicKey, buffer_ptr, m2m_id, &server_key_size) != 0) {
00759         server_key_size = 0;
00760     }
00761     if (_security->resource_value_buffer(M2MSecurity::Secretkey, buffer_ptr, m2m_id, &private_key_size) != 0) {
00762         private_key_size = 0;
00763     }
00764 
00765     tr_info("est check - is bs server /0/1: %" PRIu32, is_bs_server);
00766     tr_info("est check - Security Mode /0/2: %" PRIu32, sec_mode);
00767     tr_info("est check - Public key size /0/3: %lu", (unsigned long)public_key_size);
00768     tr_info("est check - Server Public key size /0/4: %lu", (unsigned long)server_key_size);
00769     tr_info("est check - Secret key size /0/5: %lu", (unsigned long)private_key_size);
00770 
00771     // Configure CSR params
00772     kcm_csr_params_s csr_params;
00773     int subject_size = snprintf(NULL, 0, LWM2M_CSR_SUBJECT_FORMAT,
00774                                 _endpoint_info.internal_endpoint_name.c_str(),
00775                                 _endpoint_info.account_id.c_str(),
00776                                 _endpoint_info.endpoint_name.c_str());
00777     if (subject_size <= 0) {
00778         tr_error("ConnectorClient::state_est_start - CSR Subject formatting failed!");
00779         free(buffer);
00780         internal_event(State_EST_Failure);
00781         return;
00782     }
00783 
00784     // For null-terminator
00785     subject_size++;
00786 
00787     csr_params.subject = (char*)malloc(subject_size);
00788     if (csr_params.subject == NULL) {
00789         tr_error("ConnectorClient::state_est_start - CSR Subject formatting failed!");
00790         free(buffer);
00791         internal_event(State_EST_Failure);
00792         return;
00793     }
00794 
00795     snprintf(csr_params.subject, subject_size, LWM2M_CSR_SUBJECT_FORMAT,
00796              _endpoint_info.internal_endpoint_name.c_str(),
00797              _endpoint_info.account_id.c_str(),
00798              _endpoint_info.endpoint_name.c_str());
00799 
00800     csr_params.md_type = KCM_MD_SHA256;
00801     csr_params.key_usage = KCM_CSR_KU_NONE;
00802     csr_params.ext_key_usage = KCM_CSR_EXT_KU_NONE;
00803 
00804     // Delete existing keys
00805     ccs_delete_item(g_fcc_lwm2m_device_certificate_name, CCS_CERTIFICATE_ITEM);
00806     ccs_delete_item(g_fcc_lwm2m_device_private_key_name, CCS_PRIVATE_KEY_ITEM);
00807 
00808     kcm_status_e  status = kcm_generate_keys_and_csr(KCM_SCHEME_EC_SECP256R1,
00809                                                     (const uint8_t*)g_fcc_lwm2m_device_private_key_name,
00810                                                     strlen(g_fcc_lwm2m_device_private_key_name),
00811                                                     NULL,
00812                                                     0,
00813                                                     false,
00814                                                     &csr_params,
00815                                                     buffer,
00816                                                     MAX_CERTIFICATE_SIZE,
00817                                                     &real_size,
00818                                                     NULL);
00819 
00820     free(csr_params.subject);
00821 
00822     if (status != KCM_STATUS_SUCCESS) {
00823         tr_error("ConnectorClient::state_est_start - Generating keys and csr failed!");
00824         free(buffer);
00825         internal_event(State_EST_Failure);
00826         return;
00827     }
00828 
00829     // Update state and start the enrollment by sending the enroll request
00830     internal_event(State_EST_Started);
00831     est_status_e est_status = _est_client.est_request_enrollment(NULL,
00832                                                                  0,
00833                                                                  buffer,
00834                                                                  real_size,
00835                                                                  ConnectorClient::est_enrollment_result,
00836                                                                  this);
00837 
00838     if (est_status != EST_STATUS_SUCCESS) {
00839         tr_error("ConnectorClient::state_est_start - EST enrollment failed with error %d", (int)est_status);
00840         internal_event(State_EST_Failure);
00841     }
00842 
00843     free(buffer);
00844 }
00845 
00846 void ConnectorClient::state_est_started()
00847 {
00848 }
00849 
00850 void ConnectorClient::state_est_success()
00851 {
00852     tr_info("ConnectorClient::state_est_success()");
00853     _interface->finish_bootstrap();
00854 }
00855 
00856 void ConnectorClient::state_est_failure()
00857 {
00858     tr_info("ConnectorClient::state_est_failure()");
00859     internal_event(State_Bootstrap_Failure);
00860     //Failed to store credentials, bootstrap failed
00861     _callback->connector_error(M2MInterface::ESTEnrollmentFailed, ERROR_EST_ENROLLMENT_REQUEST_FAILED); // Translated to error code ConnectMemoryConnectFail
00862 }
00863 #endif /* !MBED_CLIENT_DISABLE_EST_FEATURE */
00864 
00865 void ConnectorClient::state_registration_start()
00866 {
00867     tr_info("ConnectorClient::state_registration_start()");
00868     assert(_interface != NULL);
00869     assert(_security != NULL);
00870     _interface->register_object(_security, *_client_objs);
00871     internal_event(State_Registration_Started);
00872 }
00873 
00874 void ConnectorClient::state_registration_started()
00875 {
00876     // this state may be useful only for verifying the callbacks?
00877 }
00878 
00879 void ConnectorClient::state_registration_success()
00880 {
00881     assert(_callback != NULL);
00882     _endpoint_info.internal_endpoint_name = _interface->internal_endpoint_name();
00883 
00884     //The endpoint is maximum 32 character long, we put bigger buffer for future extensions
00885     const int max_size = 64;
00886     uint8_t *buffer = NULL;
00887     buffer = (uint8_t*)malloc(max_size);
00888 
00889     if(!buffer) {
00890          _callback->registration_process_result(State_Registration_Failure);
00891          return;
00892     }
00893     bool no_param_update = true;
00894 
00895     if(ccs_get_string_item(KEY_INTERNAL_ENDPOINT, buffer, max_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
00896         if (strcmp((const char*)buffer, _endpoint_info.internal_endpoint_name.c_str()) != 0) {
00897             // Update is required as the stored KCM entry is different than _endpoint_info.internal_endpoint_name.
00898             no_param_update = false;
00899         }
00900     }
00901     free(buffer);
00902 
00903     // Update INTERNAL_ENDPOINT setting only if there is no such entry or the value is not matching the
00904     // _endpoint_info.internal_endpoint_name.
00905     if(!no_param_update) {
00906         ccs_delete_item(KEY_INTERNAL_ENDPOINT, CCS_CONFIG_ITEM);
00907         ccs_set_item(KEY_INTERNAL_ENDPOINT, (const uint8_t*)_endpoint_info.internal_endpoint_name.c_str(),
00908                              (size_t)_endpoint_info.internal_endpoint_name.size(),
00909                              CCS_CONFIG_ITEM);
00910     }
00911 
00912     _rebootstrap_time = randLIB_get_random_in_range(1, 10);
00913     _callback->registration_process_result(State_Registration_Success);
00914 }
00915 
00916 void ConnectorClient::state_registration_failure()
00917 {
00918     assert(_callback != NULL);
00919     // maybe some additional canceling and/or leanup is needed here?
00920     _callback->registration_process_result(State_Registration_Failure);
00921 }
00922 
00923 void ConnectorClient::state_unregistered()
00924 {
00925     assert(_callback != NULL);
00926     _callback->registration_process_result(State_Unregistered);
00927 }
00928 
00929 void ConnectorClient::bootstrap_data_ready(M2MSecurity *security_object)
00930 {
00931     tr_info("ConnectorClient::bootstrap_data_ready");
00932     if(security_object) {
00933         // Update bootstrap credentials (we could skip this if we knew whether they were updated)
00934         // This will also update the address in case of first to claim
00935         ccs_status_e status = set_bootstrap_credentials(security_object);
00936         if (status != CCS_STATUS_SUCCESS) {
00937             // TODO: what now?
00938             tr_error("ConnectorClient::bootstrap_data_ready - could not store bootstrap credentials");
00939         }
00940 
00941         // Clear the first to claim flag if it's active
00942         if (is_first_to_claim()) {
00943             status = clear_first_to_claim();
00944             if (status != CCS_STATUS_SUCCESS) {
00945                 // TODO: what now?
00946                 tr_error("ConnectorClient::bootstrap_data_ready - couldn't clear first to claim flag!");
00947             }
00948         }
00949 
00950         // Bootstrap might delete m2mserver security object instance completely to force bootstrap
00951         // with new credentials, in that case delete the stored lwm2m credentials as well and re-bootstrap
00952         if (security_object->get_security_instance_id(M2MSecurity::M2MServer) == -1) {
00953             bootstrap_again();
00954             return;
00955         }
00956         // Bootstrap wrote M2MServer credentials, store them and also update first to claim status if it's configured
00957         else {
00958 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
00959             int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00960             if (m2m_id >= 0 &&
00961                 _security->resource_value_int(M2MSecurity::SecurityMode, m2m_id) == M2MSecurity::EST) {
00962                 // If EST is supported, continue to EST state to start EST enrollment
00963                 tr_info("ConnectorClient::bootstrap_data_ready() - Continue to EST enrollment");
00964                 internal_event(State_EST_Start);
00965                 return;
00966             }
00967 #endif // MBED_CLIENT_DISABLE_EST_FEATURE
00968             // Security mode was not EST, in that case just store the received credentials
00969             tr_info("ConnectorClient::bootstrap_data_ready() - Storing lwm2m credentials");
00970             status = set_connector_credentials(security_object);
00971         }
00972 
00973         if (status != CCS_STATUS_SUCCESS) {
00974             internal_event(State_Bootstrap_Failure);
00975             //Failed to store credentials, bootstrap failed
00976             _callback->connector_error(M2MInterface::MemoryFail, CONNECTOR_ERROR_NO_MEMORY); // Translated to error code ConnectMemoryConnectFail
00977             return;
00978         } else {
00979             tr_info("ConnectorClient::bootstrap_data_ready - set_credentials status %d", status);
00980         }
00981     }
00982 }
00983 
00984 void ConnectorClient::bootstrap_done(M2MSecurity *security_object)
00985 {
00986     tr_info("ConnectorClient::bootstrap_done");
00987     internal_event(State_Bootstrap_Success);
00988 }
00989 
00990 void ConnectorClient::object_registered(M2MSecurity *security_object, const M2MServer &server_object)
00991 {
00992     internal_event(State_Registration_Success);
00993 }
00994 
00995 void ConnectorClient::object_unregistered(M2MSecurity *server_object)
00996 {
00997     internal_event(State_Unregistered);
00998 }
00999 
01000 void ConnectorClient::registration_updated(M2MSecurity *security_object, const M2MServer & server_object)
01001 {
01002     _callback->registration_process_result(State_Registration_Updated);
01003 }
01004 
01005 void ConnectorClient::error(M2MInterface::Error error)
01006 {
01007     tr_error("ConnectorClient::error() - error: %d", error);
01008     assert(_callback != NULL);
01009 
01010     if (_current_state >= State_Registration_Start &&
01011         use_bootstrap() &&
01012         (error == M2MInterface::SecureConnectionFailed ||
01013          error == M2MInterface::InvalidParameters)) {
01014         tr_info("ConnectorClient::error() - Error during lwm2m registration");
01015 
01016         // Delete the lwm2m security instance
01017         int32_t id = _security->get_security_instance_id(M2MSecurity::M2MServer);
01018         if (id >= 0) {
01019             _security->remove_object_instance(id);
01020         }
01021 
01022         bootstrap_again();
01023     }
01024     else {
01025         _callback->connector_error(error, _interface->error_description());
01026     }
01027 }
01028 
01029 void ConnectorClient::value_updated(M2MBase *base, M2MBase::BaseType type)
01030 {
01031     assert(_callback != NULL);
01032     _callback->value_updated(base, type);
01033 }
01034 
01035 bool ConnectorClient::connector_credentials_available()
01036 {
01037     tr_debug("ConnectorClient::connector_credentials_available");
01038     if (ccs_check_item(g_fcc_lwm2m_server_uri_name, CCS_CONFIG_ITEM) != CCS_STATUS_SUCCESS) {
01039         return false;
01040     }
01041     return true;
01042 }
01043 
01044 bool ConnectorClient::use_bootstrap()
01045 {
01046     tr_debug("ConnectorClient::use_bootstrap");
01047     size_t real_size = 0;
01048     uint8_t data[CONFIG_BOOLEAN_ITEM_SIZE] = {0};
01049     uint32_t value = 0;
01050     ccs_status_e status = ccs_get_item(g_fcc_use_bootstrap_parameter_name, data, CONFIG_BOOLEAN_ITEM_SIZE, &real_size, CCS_CONFIG_ITEM);
01051     if (status == CCS_STATUS_SUCCESS) {
01052         memcpy(&value, data, CONFIG_BOOLEAN_ITEM_SIZE);
01053         // Return true if use_bootstrap is set
01054         if (value == 1) {
01055             return true;
01056         }
01057     }
01058     return false;
01059 }
01060 
01061 
01062 bool ConnectorClient::get_key(const char *key, const char *endpoint, char *&key_name)
01063 {
01064     if(key_name) {
01065         free(key_name);
01066         key_name = NULL;
01067     }
01068 
01069     key_name = (char*)malloc(strlen(key)+strlen(endpoint)+1);
01070     if(key_name) {
01071         strcpy(key_name, key);
01072         strcat(key_name, endpoint);
01073         tr_debug("key %s", key_name);
01074         return true;
01075     }
01076     return false;
01077 }
01078 
01079 ccs_status_e ConnectorClient::set_connector_credentials(M2MSecurity *security)
01080 {
01081     tr_debug("ConnectorClient::set_connector_credentials");
01082     ccs_status_e status = CCS_STATUS_ERROR;
01083 
01084     int32_t m2m_id = security->get_security_instance_id(M2MSecurity::M2MServer);
01085     if (m2m_id == -1) {
01086         return status;
01087     }
01088 
01089     size_t buffer_size = MAX_CERTIFICATE_SIZE;
01090     uint8_t public_key[MAX_CERTIFICATE_SIZE];
01091     uint8_t *public_key_ptr = (uint8_t*)&public_key;
01092 
01093     // TODO! Update to use chain api
01094     if (security->resource_value_buffer(M2MSecurity::PublicKey, public_key_ptr, m2m_id, &buffer_size) != 0) {
01095         return status;
01096     }
01097 
01098     char device_id[64];
01099     memset(device_id, 0, 64);
01100     if (extract_field_from_certificate(public_key, buffer_size, "L", device_id)) {
01101         tr_info("ConnectorClient::set_connector_credentials - L internal_endpoint_name : %s", device_id);
01102         _endpoint_info.internal_endpoint_name = String(device_id);
01103         ccs_delete_item(KEY_INTERNAL_ENDPOINT, CCS_CONFIG_ITEM);
01104         status = ccs_set_item(KEY_INTERNAL_ENDPOINT,(uint8_t*)device_id, strlen(device_id), CCS_CONFIG_ITEM);
01105     }
01106 
01107     memset(device_id, 0, 64);
01108     if (extract_field_from_certificate(public_key, buffer_size, "CN", device_id)) {
01109         tr_info("ConnectorClient::set_connector_credentials - CN endpoint_name : %s", device_id);
01110         _endpoint_info.endpoint_name = String(device_id);
01111     }
01112 
01113     if(status == CCS_STATUS_SUCCESS) {
01114         ccs_delete_item(KEY_ACCOUNT_ID, CCS_CONFIG_ITEM);
01115         // AccountID optional so don't fail if unable to store
01116         ccs_set_item(KEY_ACCOUNT_ID,
01117                      (const uint8_t*)_endpoint_info.account_id.c_str(),
01118                      (size_t)_endpoint_info.account_id.size(),
01119                      CCS_CONFIG_ITEM);
01120     }
01121 
01122     if (status == CCS_STATUS_SUCCESS) {
01123 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
01124         _endpoint_info.lwm2m_server_uri = security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id);
01125 #endif
01126         ccs_delete_item(g_fcc_lwm2m_server_uri_name, CCS_CONFIG_ITEM);
01127         status = ccs_set_item(g_fcc_lwm2m_server_uri_name,
01128                               (const uint8_t*)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).c_str(),
01129                               (size_t)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).size(),
01130                               CCS_CONFIG_ITEM);
01131     }
01132 
01133     M2MDevice *device = M2MInterfaceFactory::create_device();
01134     if (status == CCS_STATUS_SUCCESS && device) {
01135         String temp = "";
01136         uint32_t currenttime = (uint32_t)device->resource_value_int(M2MDevice::CurrentTime, 0);
01137         uint8_t data[4];
01138         memcpy(data, &currenttime, 4);
01139         ccs_delete_item(g_fcc_current_time_parameter_name, CCS_CONFIG_ITEM);
01140         ccs_set_item(g_fcc_current_time_parameter_name, data, 4, CCS_CONFIG_ITEM);
01141 
01142         temp = device->resource_value_string(M2MDevice::Timezone, 0);
01143         if (temp.size() > 0) {
01144             ccs_delete_item(g_fcc_device_time_zone_parameter_name, CCS_CONFIG_ITEM);
01145             ccs_set_item(g_fcc_device_time_zone_parameter_name, (const uint8_t*)temp.c_str(), temp.size(), CCS_CONFIG_ITEM);
01146         }
01147 
01148         temp = device->resource_value_string(M2MDevice::UTCOffset, 0);
01149         if (temp.size() > 0) {
01150             ccs_delete_item(g_fcc_offset_from_utc_parameter_name, CCS_CONFIG_ITEM);
01151             ccs_set_item(g_fcc_offset_from_utc_parameter_name, (const uint8_t*)temp.c_str(), temp.size(), CCS_CONFIG_ITEM);
01152         }
01153 
01154         status = CCS_STATUS_SUCCESS;
01155     }
01156     else {
01157         tr_debug("No device object to store!");
01158     }
01159 
01160     return status;
01161 }
01162 
01163 ccs_status_e ConnectorClient::set_bootstrap_credentials(M2MSecurity *security)
01164 {
01165     tr_debug("ConnectorClient::set_bootstrap_credentials");
01166     ccs_status_e status = CCS_STATUS_ERROR;
01167 
01168     size_t uri_size = MAX_CERTIFICATE_SIZE;
01169     uint8_t bootstrap_uri[MAX_CERTIFICATE_SIZE];
01170     uint8_t *bootstrap_uri_ptr = (uint8_t*)&bootstrap_uri;
01171 
01172     int32_t bs_id = security->get_security_instance_id(M2MSecurity::Bootstrap);
01173     if (bs_id == -1) {
01174         return status;
01175     }
01176 
01177     String bs_uri = security->resource_value_string(M2MSecurity::M2MServerUri, bs_id);
01178     if (bs_uri.size() <= 0) {
01179         return status;
01180     }
01181 
01182     // Update BS uri only if it has changed.
01183     // If uri is missing or some other error while reading the item --> return error.
01184     if (ccs_get_string_item(g_fcc_bootstrap_server_uri_name, bootstrap_uri_ptr, uri_size, CCS_CONFIG_ITEM) == CCS_STATUS_SUCCESS) {
01185         if (strcmp((const char*)bootstrap_uri_ptr, bs_uri.c_str()) != 0) {
01186             tr_info("ConnectorClient::set_bootstrap_credentials - update uri from: %s to: %s", (char*)bootstrap_uri_ptr, bs_uri.c_str());
01187             ccs_delete_item(g_fcc_bootstrap_server_uri_name, CCS_CONFIG_ITEM);
01188             status = ccs_set_item(g_fcc_bootstrap_server_uri_name,
01189                               (const uint8_t*)bs_uri.c_str(),
01190                               strlen(bs_uri.c_str()),
01191                               CCS_CONFIG_ITEM);
01192         } else {
01193             status = CCS_STATUS_SUCCESS;
01194         }
01195     }
01196 
01197     return status;
01198 }
01199 
01200 ccs_status_e ConnectorClient::clear_first_to_claim()
01201 {
01202     tr_debug("ConnectorClient::clear_first_to_claim");
01203     return ccs_delete_item(KEY_FIRST_TO_CLAIM, CCS_CONFIG_ITEM);
01204 }
01205 
01206 
01207 const ConnectorClientEndpointInfo *ConnectorClient::endpoint_info() const
01208 {
01209     return &_endpoint_info;
01210 }
01211 
01212 bool ConnectorClient::bootstrap_credentials_stored_in_kcm()
01213 {
01214     size_t real_size = 0;
01215     ccs_status_e success = ccs_item_size(g_fcc_bootstrap_server_uri_name, &real_size, CCS_CONFIG_ITEM);
01216     // Return true if bootstrap uri exists in KCM
01217     if ((success == CCS_STATUS_SUCCESS) && real_size > 0) {
01218         return true;
01219     } else {
01220         return false;
01221     }
01222 }
01223 
01224 bool ConnectorClient::is_first_to_claim()
01225 {
01226     size_t real_size = 0;
01227     uint8_t data[CONFIG_BOOLEAN_ITEM_SIZE] = {0};
01228     uint32_t value = 0;
01229     ccs_status_e status = ccs_get_item(KEY_FIRST_TO_CLAIM, data, CONFIG_BOOLEAN_ITEM_SIZE, &real_size, CCS_CONFIG_ITEM);
01230     if (status == CCS_STATUS_SUCCESS) {
01231         memcpy(&value, data, CONFIG_BOOLEAN_ITEM_SIZE);
01232         // Return true if first to claim is set
01233         if (value == 1) {
01234             return true;
01235         }
01236     }
01237     return false;
01238 }
01239 
01240 void ConnectorClient::timer_expired(M2MTimerObserver::Type type)
01241 {
01242     if (type == M2MTimerObserver::BootstrapFlowTimer) {
01243         start_bootstrap();
01244     }
01245 }
01246 
01247 #ifndef MBED_CLIENT_DISABLE_EST_FEATURE
01248 void ConnectorClient::est_enrollment_result(est_enrollment_result_e result,
01249                                             cert_chain_context_s *cert_chain,
01250                                             void *context)
01251 {
01252     tr_debug("ConnectorClient::est_enrollment_result - %s", result == EST_ENROLLMENT_SUCCESS ? "successful" : "failed");
01253     if (result == EST_ENROLLMENT_SUCCESS) {
01254         tr_debug("ConnectorClient::est_enrollment_result - PublicKey size %d", cert_chain->chain_length);
01255     }
01256 
01257     ConnectorClient *cc = static_cast<ConnectorClient*>(context);
01258     assert(cc);
01259     assert(cc->_security != NULL);
01260 
01261     int32_t m2m_id = cc->_security->get_security_instance_id(M2MSecurity::M2MServer);
01262     StartupSubStateRegistration state = State_EST_Failure;
01263 
01264     if (result == EST_ENROLLMENT_SUCCESS &&
01265         m2m_id >= 0 &&
01266         cert_chain != NULL &&
01267         cert_chain->chain_length > 0)
01268     {
01269 
01270         kcm_cert_chain_handle chain_handle;
01271         kcm_status_e  status = kcm_cert_chain_create(&chain_handle,
01272                                        (const uint8_t*)g_fcc_lwm2m_device_certificate_name,
01273                                        strlen(g_fcc_lwm2m_device_certificate_name),
01274                                        cert_chain->chain_length,
01275                                        false);
01276         tr_debug("Cert chain create %d", status);
01277         if (status == KCM_STATUS_SUCCESS) {
01278             cert_context_s *cert = cert_chain->certs;
01279             while (cert != NULL) {
01280 
01281                 // Store certificate
01282                 status = kcm_cert_chain_add_next(chain_handle, cert->cert, cert->cert_length);
01283                 if (status != KCM_STATUS_SUCCESS) {
01284                     break;
01285                 }
01286 
01287                 cert = cert->next;
01288             }
01289 
01290             status = kcm_cert_chain_close(chain_handle);
01291             if (status == KCM_STATUS_SUCCESS) {
01292                 tr_info("ConnectorClient::est_enrollment_result() - Certificates stored successfully");
01293                 tr_info("ConnectorClient::est_enrollment_result() - Storing lwm2m credentials");
01294                 if (cc->set_connector_credentials(cc->_security) == CCS_STATUS_SUCCESS) {
01295                     state = State_EST_Success;
01296                 }
01297             }
01298             else {
01299                 tr_error("ConnectorClient::est_enrollment_result - storing certificate chain failed!");
01300             }
01301         }
01302     }
01303 
01304     // Finally free the certificate chain context
01305     EstClient::free_cert_chain_context(cert_chain);
01306 
01307     cc->internal_event(state);
01308 }
01309 #endif /* !MBED_CLIENT_DISABLE_EST_FEATURE */
01310 
01311 
01312 M2MInterface::BindingMode ConnectorClient::transport_mode()
01313 {
01314 #ifdef MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP
01315     return M2MInterface::UDP;
01316 #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP
01317     return M2MInterface::TCP;
01318 #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE
01319     return M2MInterface::UDP_QUEUE;
01320 #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE
01321     return M2MInterface::TCP_QUEUE;
01322 #else
01323     return M2MInterface::UDP;
01324 #endif
01325 }
01326 
01327 void ConnectorClient::init_security_object()
01328 {
01329     if (_security) {
01330         for (int i = 0; i <= M2MSecurity::Bootstrap; i++) {
01331             // _security->create_object_instance() returns NULL if object already exists
01332             if (_security->create_object_instance((M2MSecurity::ServerType)i)) {
01333                 M2MResource* res = _security->get_resource(M2MSecurity::ServerPublicKey, i);
01334                 if (res) {
01335                     res->set_resource_read_callback(read_security_object_data_from_kcm, this);
01336                     res->set_resource_write_callback(write_security_object_data_to_kcm, this);
01337                 }
01338 
01339                 res = _security->get_resource(M2MSecurity::PublicKey, i);
01340                 if (res) {
01341                     res->set_resource_read_callback(read_security_object_data_from_kcm, this);
01342                     res->set_resource_write_callback(write_security_object_data_to_kcm, this);
01343                 }
01344 
01345                 res = _security->get_resource(M2MSecurity::Secretkey, i);
01346                 if (res) {
01347                     res->set_resource_read_callback(read_security_object_data_from_kcm, this);
01348                     res->set_resource_write_callback(write_security_object_data_to_kcm, this);
01349                 }
01350 
01351                 res = _security->get_resource(M2MSecurity::OpenCertificateChain, i);
01352                 if (res) {
01353                     res->set_resource_read_callback(open_certificate_chain_callback, this);
01354                 }
01355 
01356                 res = _security->get_resource(M2MSecurity::ReadDeviceCertificateChain, i);
01357                 if (res) {
01358                     res->set_resource_read_callback(read_certificate_chain_callback, this);
01359                 }
01360 
01361                 res = _security->get_resource(M2MSecurity::CloseCertificateChain, i);
01362                 if (res) {
01363                     res->set_resource_read_callback(close_certificate_chain_callback, this);
01364                 }
01365             }
01366         }
01367     }
01368 }
01369 
01370 void *ConnectorClient::certificate_chain_handle() const
01371 {
01372     return _certificate_chain_handle;
01373 }
01374 
01375 void ConnectorClient::set_certificate_chain_handle(void *cert_handle)
01376 {
01377     _certificate_chain_handle = cert_handle;
01378 }
01379 
01380 void ConnectorClient::bootstrap_again()
01381 {
01382     // delete the old connector credentials
01383     ccs_delete_item(g_fcc_lwm2m_server_uri_name, CCS_CONFIG_ITEM);
01384     ccs_delete_item(g_fcc_lwm2m_server_ca_certificate_name, CCS_CERTIFICATE_ITEM);
01385     ccs_delete_item(g_fcc_lwm2m_device_certificate_name, CCS_CERTIFICATE_ITEM);
01386     ccs_delete_item(g_fcc_lwm2m_device_private_key_name, CCS_PRIVATE_KEY_ITEM);
01387 
01388     tr_error("ConnectorClient::bootstrap_again in %d seconds", _rebootstrap_time);
01389 
01390     _rebootstrap_timer.start_timer(_rebootstrap_time * 1000, M2MTimerObserver::BootstrapFlowTimer, true);
01391     _rebootstrap_time *= 2;
01392     if (_rebootstrap_time > MAX_REBOOTSTRAP_TIMEOUT) {
01393         _rebootstrap_time = MAX_REBOOTSTRAP_TIMEOUT;
01394     }
01395 
01396     _callback->connector_error(M2MInterface::SecureConnectionFailed, CONNECTOR_BOOTSTRAP_AGAIN);
01397 }