Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FXAS21002 FXOS8700Q
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, ¤ttime, 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 }
Generated on Tue Jul 12 2022 20:20:58 by
