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