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.
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 Mon Aug 29 2022 19:53:38 by
