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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
thread_ccm.c
00001 /* 00002 * Copyright (c) 2017-2019, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: BSD-3-Clause 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holder nor the 00014 * names of its contributors may be used to endorse or promote products 00015 * derived from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 /** 00031 * \brief Thread commercial mode implementation for CCM bootstrap. 00032 */ 00033 #include "nsconfig.h" 00034 #include <ns_types.h> 00035 #include <string.h> 00036 #include "nsdynmemLIB.h" 00037 #include "ns_trace.h" 00038 #include "common_functions.h" 00039 #include "coap_service_api.h" 00040 #include "thread_meshcop_lib.h" 00041 #include "randLIB.h" 00042 #include "6LoWPAN/Thread/thread_common.h" 00043 #include "6LoWPAN/Thread/thread_bootstrap.h" 00044 #include "6LoWPAN/Thread/thread_joiner_application.h" 00045 #include "6LoWPAN/Thread/thread_discovery.h" 00046 #include "6LoWPAN/Thread/thread_constants.h" 00047 #include "6LoWPAN/Thread/thread_management_server.h" 00048 #include "6LoWPAN/Thread/thread_nvm_store.h" 00049 #include "6LoWPAN/Thread/thread_ccm.h" 00050 00051 00052 /* 00053 * Thread 1.2 CCM security credentials 00054 */ 00055 #ifdef HAVE_THREAD_V2 00056 00057 #if 1 00058 /* Hardcoded CSR request */ 00059 static const unsigned char csr_request[215] = { 00060 0x30, 0x81, 0xd4, 0x30, 0x7c, 0x02, 0x01, 0x00, 0x30, 0x1a, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 00061 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 00062 0x65, 0x31, 0x32, 0x33, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 00063 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xb1, 00064 0xab, 0xe8, 0xa2, 0xa1, 0xe6, 0x62, 0x5e, 0xae, 0x9e, 0x7e, 0x41, 0xcf, 0x7e, 0x95, 0x58, 0x19, 00065 0x51, 0x47, 0xea, 0x0f, 0xe2, 0xf8, 0xc2, 0x1b, 0x61, 0xa5, 0x30, 0x05, 0xc0, 0x91, 0xb6, 0x07, 00066 0xc2, 0x43, 0x46, 0xda, 0x75, 0xc0, 0x58, 0xd8, 0x08, 0xa5, 0xbb, 0xdb, 0xdc, 0x0e, 0xf2, 0x05, 00067 0x62, 0xfb, 0x28, 0xbb, 0xa7, 0xd2, 0x9e, 0xef, 0x8f, 0xbf, 0xba, 0xcd, 0x51, 0xa5, 0xfd, 0xa0, 00068 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 00069 0x30, 0x45, 0x02, 0x20, 0x4e, 0xb2, 0x25, 0x82, 0x24, 0xf6, 0xe1, 0x51, 0xd6, 0x0c, 0x19, 0x60, 00070 0x88, 0xb8, 0xe2, 0xfd, 0x90, 0xd2, 0xc1, 0x0f, 0xb0, 0x4f, 0x8e, 0x73, 0x13, 0x5c, 0x9f, 0x42, 00071 0x09, 0x68, 0xdf, 0x05, 0x02, 0x21, 0x00, 0xc9, 0xc2, 0x63, 0x83, 0x62, 0x24, 0x15, 0x73, 0xf1, 00072 0x63, 0xea, 0xe3, 0xd2, 0xf1, 0x50, 0x48, 0x56, 0xdf, 0x6b, 0xcf, 0xc4, 0x31, 0xc4, 0xcf, 0xbc, 00073 0x26, 0xe3, 0x5a, 0x74, 0x62, 0x0f, 0x70 00074 }; 00075 #else 00076 /* CSR request with CBOR header*/ 00077 static const unsigned char csr_request[244] = { 00078 0x58, 0xf2, 0x30, 0x81, 0xef, 0x30, 0x81, 0x95, 0x02, 0x01, 0x01, 0x30, 0x33, 0x31, 0x1c, 0x30, 0x1a, 0x06, 00079 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x69, 0x66, 0x79, 0x20, 0x50, 0x72, 0x6f, 00080 0x20, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 00081 0x4f, 0x53, 0x52, 0x41, 0x4d, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 00082 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 00083 0x04, 0xd8, 0x19, 0x64, 0x07, 0xca, 0x38, 0x01, 0x62, 0xfd, 0x7e, 0xe7, 0x07, 0x8d, 0x21, 0x50, 0x0b, 0x9f, 00084 0x00, 0x71, 0x26, 0xaa, 0x55, 0x2a, 0x44, 0x9b, 0xe8, 0xfd, 0xfb, 0x0e, 0x8d, 0x41, 0x01, 0xf2, 0x7b, 0x2e, 00085 0x7b, 0xe4, 0x4f, 0x35, 0x00, 0x0b, 0x1f, 0xbc, 0x86, 0x57, 0xa1, 0x69, 0x32, 0x49, 0xcf, 0xd7, 0x2f, 0x0b, 00086 0xfa, 0x22, 0x44, 0x0b, 0x6f, 0xf4, 0xb5, 0xbd, 0x0f, 0x20, 0xab, 0xa0, 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a, 00087 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xb5, 0xa2, 0x8b, 00088 0xf9, 0xbf, 0x7d, 0x2c, 0x72, 0x3e, 0xf0, 0xad, 0x1e, 0x38, 0x28, 0xc0, 0xa3, 0xe8, 0xd6, 0x70, 0x9a, 0x2a, 00089 0xf8, 0x1d, 0x33, 0x9d, 0xbb, 0x6c, 0x4f, 0x7c, 0x81, 0xb6, 0x71, 0x02, 0x21, 0x00, 0xba, 0x74, 0x50, 0xad, 00090 0x27, 0x2e, 0x00, 0x71, 0x68, 0x7f, 0xe0, 0x2c, 0x8c, 0x1b, 0x6f, 0x95, 0x8c, 0x58, 0x1e, 0xe7, 0xe3, 0xa5, 00091 0x50, 0xca, 0x12, 0x0a, 0x60, 0x56, 0xd2, 0x3a, 0xe2, 0xeb 00092 } 00093 #endif 00094 00095 /* 00096 * Private key for certificate m_device_nxp_sn_and_8021ar.cert.pem -> test registrar will return this as default 00097 */ 00098 static const unsigned char domain_private_key[138] = { 00099 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 00100 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 00101 0x01, 0x01, 0x04, 0x20, 0x49, 0x9c, 0x76, 0x67, 0xd9, 0xae, 0x4e, 0xb6, 0x38, 0xb7, 0xce, 0x25, 00102 0x2b, 0x21, 0xf4, 0x6a, 0x88, 0x28, 0xaa, 0x16, 0x74, 0x6e, 0xc3, 0xbc, 0xbb, 0x37, 0x50, 0xc9, 00103 0x87, 0xbd, 0xff, 0xbf, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x50, 0xe9, 0x5f, 0xd3, 0xb1, 0x72, 00104 0x74, 0xb6, 0xaf, 0x15, 0xae, 0xd7, 0x6d, 0xf9, 0x7f, 0xfa, 0x4f, 0xaf, 0xd6, 0x1f, 0x09, 0x29, 00105 0x37, 0xf8, 0x1d, 0x27, 0xeb, 0x31, 0x41, 0x62, 0x52, 0x4e, 0x6b, 0x51, 0x8e, 0x08, 0x72, 0xce, 00106 0xc2, 0x43, 0x69, 0x0a, 0x57, 0xb5, 0x54, 0xeb, 0x9b, 0x06, 0xad, 0xed, 0x7c, 0x56, 0x6e, 0x0c, 00107 0x23, 0xcb, 0x1e, 0x51, 0x78, 0xe4, 0xae, 0x41, 0x58, 0x15 00108 }; 00109 00110 const uint8_t meshcop_nmkp_resp_ignore[] = { 00111 MESHCOP_TLV_COMM_SIGNATURE, 00112 MESHCOP_TLV_COMM_TOKEN, 00113 MESHCOP_TLV_COMMISSIONER_SESSION_ID, 00114 MESHCOP_TLV_COMMISSIONER_ID, 00115 MESHCOP_TLV_STATE 00116 }; 00117 00118 static NS_LIST_DEFINE(ccm_instance_list, thread_ccm_credentials_t, link); 00119 00120 #define TRACE_GROUP "ccmb" 00121 00122 static int stringlen(const char *s, int n) 00123 { 00124 char *end = memchr(s, 0, n); 00125 return end ? end - s : n; 00126 } 00127 00128 static int8_t thread_ccm_find_id_by_service(int8_t service_id) 00129 { 00130 ns_list_foreach(thread_ccm_credentials_t, cur, &ccm_instance_list) { 00131 if (cur->coap_service_secure_session_id == service_id) { 00132 return cur->interface_id; 00133 } 00134 } 00135 return -1; 00136 } 00137 00138 static thread_ccm_credentials_t *thread_ccm_find_by_service(int8_t service_id) 00139 { 00140 ns_list_foreach(thread_ccm_credentials_t, cur, &ccm_instance_list) { 00141 if (cur->coap_service_secure_session_id == service_id) { 00142 return cur; 00143 } 00144 } 00145 return NULL; 00146 } 00147 00148 static void thread_ccm_attach_cb(void *arg) 00149 { 00150 thread_ccm_credentials_t *this = arg; 00151 tr_debug("Attach to new network"); 00152 if (!this) { 00153 return; 00154 } 00155 if (this->reattach_ongoing) { 00156 this->reattach_ongoing = false; 00157 thread_nvm_store_mleid_rloc_map_remove(); 00158 thread_nvm_store_link_info_clear(); 00159 thread_joiner_application_link_configuration_delete(this->interface_id); 00160 thread_bootstrap_connection_error(this->interface_id, CON_ERROR_NETWORK_KICK, NULL); 00161 } else { 00162 // Cleaning up the joining information 00163 if (this->ccm_done_cb) {// This is successfull 00164 this->ccm_done_cb(this->interface_id); 00165 } 00166 } 00167 } 00168 00169 int8_t thread_ccm_network_reattach(int8_t service_id, uint16_t timeout, bool clear_data) 00170 { 00171 thread_ccm_credentials_t *this = thread_ccm_find_by_service(service_id); 00172 if (!this) { 00173 return -1; 00174 } 00175 00176 this->reattach_ongoing = clear_data; 00177 00178 // re-attach in any case and close the secure connection 00179 this->attach_timeout = eventOS_timeout_ms(thread_ccm_attach_cb, timeout, this); 00180 00181 return 0; 00182 } 00183 00184 static int thread_ccm_security_start_cb(int8_t service_id, uint8_t address[static 16], uint16_t port, uint8_t *pw, uint8_t *pw_len) 00185 { 00186 /* Certificates used, pskd not needed */ 00187 (void) service_id; 00188 (void) address; 00189 (void) port; 00190 (void) pw; 00191 (void) pw_len; 00192 00193 return 0; 00194 } 00195 00196 static int thread_ccm_enroll_parse(protocol_interface_info_entry_t *cur, uint8_t *payload_ptr, uint16_t payload_len) 00197 { 00198 uint8_t *ptr; 00199 uint16_t len, flen; 00200 00201 ptr = payload_ptr; 00202 len = payload_len; 00203 // CBOR format check 00204 if (*ptr == 0x58) { 00205 flen = *(ptr + 1); 00206 ptr += 2; 00207 len -= 2; 00208 } else if (*ptr == 0x59) { 00209 flen = common_read_16_bit(ptr + 1); 00210 ptr += 3; 00211 len -= 3; 00212 } else { 00213 // no shorter than 23 byte certificates supported 00214 flen = 0; 00215 } 00216 00217 if (flen != len || 00218 0 > thread_ccm_network_certificate_set(cur, ptr, len)) { 00219 tr_warn("ae response parse failed, len %d != %d", len, flen); 00220 } 00221 00222 return 0; 00223 } 00224 00225 static int thread_ccm_simple_enroll_response_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 00226 { 00227 (void) source_address; 00228 (void) source_port; 00229 00230 // re-attach in any case and close the secure connection 00231 thread_ccm_network_reattach(service_id, 1000, false); 00232 coap_service_close_secure_connection(service_id, source_address, source_port); 00233 00234 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(thread_ccm_find_id_by_service(service_id)); 00235 00236 tr_debug("Simple enrollment received len:%d - %s", response_ptr->payload_len, trace_array(response_ptr->payload_ptr, response_ptr->payload_len)); 00237 00238 if (!cur || !cur->thread_info || !response_ptr) { 00239 return -1; 00240 } 00241 00242 thread_ccm_enroll_parse(cur, response_ptr->payload_ptr, response_ptr->payload_len); 00243 00244 return 0; 00245 } 00246 00247 static int thread_ccm_csrattrs_response_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 00248 { 00249 (void) response_ptr; 00250 00251 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(thread_ccm_find_id_by_service(service_id)); 00252 00253 if (!cur || !cur->thread_info) { 00254 return -1; 00255 } 00256 tr_info("Receiving csrattrs response sending simpleenroll"); 00257 00258 // TODO Create CSR and private key here... Now we use hardcoded stuff. 00259 thread_ccm_network_private_key_set(cur, domain_private_key, sizeof(domain_private_key)); 00260 00261 coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, source_address, source_port, 00262 COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_SIMPLEENROLL, THREAD_CONTENT_FORMAT_PKCS10, 00263 csr_request, sizeof(csr_request), thread_ccm_simple_enroll_response_cb); 00264 00265 return 0; 00266 } 00267 00268 00269 char *thread_ccm_parse_rat_response(uint8_t *data, uint16_t len) 00270 { 00271 char *ptr; 00272 00273 for (ptr = (char *)data; (ptr - (char *)data) < len; ptr++) { 00274 if (*ptr == 'd') { 00275 if (!strncmp(ptr, "domainCAcert", 12)) { 00276 return ptr; 00277 } 00278 } 00279 } 00280 00281 return NULL; 00282 } 00283 00284 static int thread_ccm_rat_response_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 00285 { 00286 char *ca_cert_ptr = NULL; 00287 uint16_t ca_cert_len = 0; 00288 00289 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(thread_ccm_find_id_by_service(service_id)); 00290 00291 if (!cur || !cur->thread_info) { 00292 return -1; 00293 } 00294 00295 tr_info("Receiving RAT response sending csrattrs request"); 00296 00297 if (!response_ptr || !response_ptr->payload_ptr) { 00298 tr_error("No response payload"); 00299 return -1; 00300 } 00301 00302 // Parse CA certificate from RAT response 00303 // Replace with CBOR library, when the time is right 00304 // Here we receive private key for the CA certi 00305 00306 ca_cert_ptr = thread_ccm_parse_rat_response(response_ptr->payload_ptr, response_ptr->payload_len); 00307 00308 if (ca_cert_ptr) { 00309 ca_cert_ptr += 13; // Jump over "domainCAcert and some cbor format byte... 00310 ca_cert_len = common_read_16_bit((uint8_t *)ca_cert_ptr); // read length 00311 ca_cert_ptr += 2; 00312 tr_debug("CA cert len %d", ca_cert_len); 00313 /* Set domain CA certificate pointer and length */ 00314 00315 if (thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_ptr) { 00316 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_ptr); 00317 } 00318 thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_ptr = ns_dyn_mem_alloc(ca_cert_len); 00319 if (!thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_ptr) { 00320 return -1; 00321 } 00322 memcpy(thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_ptr, ca_cert_ptr, ca_cert_len); 00323 thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_len = ca_cert_len; 00324 } else { 00325 tr_error("Response parse failed"); 00326 } 00327 00328 // TODO Verify nonce 00329 00330 coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, source_address, source_port, 00331 COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_GET, THREAD_URI_CSRATTRS, THREAD_CONTENT_FORMAT_CSRATTRS, NULL, 0, thread_ccm_csrattrs_response_cb); 00332 00333 return 0; 00334 } 00335 /*A2 # map(2) 00336 67 # text(7) 00337 76657273696F6E # "version" 00338 61 # text(1) 00339 31 # "1" 00340 65 # text(5) 00341 6E6F6E6365 # "nonce" 00342 48 # bytes(8) 00343 13ADD904605D973E # "\x13\xAD\xD9\x04`]\x97>" 00344 * 00345 */ 00346 static int thread_ccm_rat_request_build(uint8_t *rat_payload, int length) 00347 { 00348 uint8_t *ptr = rat_payload; 00349 00350 if (length < 30) { 00351 return 0; 00352 } 00353 00354 *rat_payload++ = 0xa2; // map (2) 00355 00356 // text (7) "version" + unsigned (1) "1" 00357 *rat_payload++ = 0x67; 00358 memcpy(rat_payload, "version", 7); 00359 rat_payload += 7; 00360 *rat_payload++ = 0x61; 00361 *rat_payload++ = 0x31; 00362 00363 // text (5) "nonce" + bytes (8) random nonce 00364 // todo: save nonce to verify response against reply. 00365 *rat_payload++ = 0x65; 00366 memcpy(rat_payload, "nonce", 5); 00367 rat_payload += 5; 00368 00369 *rat_payload++ = 0x48; 00370 common_write_64_bit(randLIB_get_64bit(), rat_payload); 00371 rat_payload += 8; 00372 00373 return rat_payload - ptr; 00374 } 00375 00376 static int thread_ccm_ae_commission_start(int8_t interface_id, uint8_t parent_address[16], uint16_t port, thread_commission_done_cb *done_cb) 00377 { 00378 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 00379 uint8_t rat_payload[30]; 00380 int rat_len; 00381 00382 if (!done_cb || !cur) { 00383 return -1; 00384 } 00385 00386 thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id = coap_service_initialize(interface_id, port, COAP_SERVICE_OPTIONS_EPHEMERAL_PORT | COAP_SERVICE_OPTIONS_SECURE | 0x80, thread_ccm_security_start_cb, joiner_application_security_done_cb); 00387 00388 if (0 > coap_service_certificate_set(thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id, cur->thread_info->ccm_credentials_ptr->device_certificate_ptr, cur->thread_info->ccm_credentials_ptr->device_certificate_len, 00389 cur->thread_info->ccm_credentials_ptr->device_pk_ptr, cur->thread_info->ccm_credentials_ptr->device_pk_len)) { 00390 tr_debug("coap service certificate set failed"); 00391 return -1; 00392 } 00393 tr_debug("start ae commissioning: interface %d, parent: %s, port %d", interface_id, trace_ipv6(parent_address), port); 00394 00395 thread_info(cur)->ccm_credentials_ptr->ccm_done_cb = done_cb; 00396 memcpy(thread_info(cur)->ccm_credentials_ptr->ccm_addr, parent_address, 16); 00397 thread_info(cur)->ccm_credentials_ptr->ccm_port = port; 00398 00399 rat_len = thread_ccm_rat_request_build(rat_payload, sizeof(rat_payload)); 00400 if (rat_len == 0) { 00401 tr_debug("RAT request payload build failed"); 00402 return -1; 00403 } 00404 00405 // todo: This might not be needed if no extra certificate processing made by device and should directly call simpleenroll 00406 coap_service_request_send(thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, parent_address, port, 00407 COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_RAT, THREAD_CONTENT_FORMAT_AUDITNONCE, rat_payload, rat_len, thread_ccm_rat_response_cb); 00408 00409 return 0; 00410 } 00411 00412 static int thread_ccm_nmkp_response_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 00413 { 00414 tr_debug("nmkp provisioning done"); 00415 00416 // re-attach in any case and close the secure connection 00417 thread_ccm_network_reattach(service_id, 1000, false); 00418 coap_service_close_secure_connection(service_id, source_address, source_port); 00419 00420 // CoAP message failed - try to reattach 00421 if (!response_ptr || !response_ptr->payload_ptr) { 00422 tr_debug("nmkp provisioning failed - no response"); 00423 return -1; 00424 } 00425 if (thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_NETWORK_MASTER_KEY, NULL) < 16 || 00426 thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_XPANID, NULL) < 8 || 00427 thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_NETWORK_NAME, NULL) == 0 || 00428 thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_CHANNEL, NULL) == 0 || 00429 thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_PANID, NULL) == 0 || 00430 thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_PSKC, NULL) < 16) { 00431 // Absolutely minimum we must have is master secret to attach. 00432 // If commissioner wants to be connected we must have PSKc,Name,Xpanid 00433 // If there is some fields missing we could attach, but timestamp must be set to 0 which will then cause synchronization 00434 tr_error("Not include all TLv's %s", trace_array(response_ptr->payload_ptr, response_ptr->payload_len)); 00435 return -1; 00436 } 00437 00438 thread_joiner_application_active_configuration_update(thread_ccm_find_id_by_service(service_id), response_ptr->payload_ptr, response_ptr->payload_len, meshcop_nmkp_resp_ignore, sizeof(meshcop_nmkp_resp_ignore)); 00439 00440 return 0; 00441 } 00442 static int thread_ccm_nmkp_commission_start(int8_t interface_id, uint8_t parent_address[16], uint16_t port, thread_commission_done_cb *done_cb) 00443 { 00444 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); 00445 00446 if (!done_cb || !cur) { 00447 return -1; 00448 } 00449 00450 thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id = coap_service_initialize(cur->id, port, COAP_SERVICE_OPTIONS_EPHEMERAL_PORT | COAP_SERVICE_OPTIONS_SECURE | 0x80, thread_ccm_security_start_cb, NULL); 00451 00452 if (cur->thread_info->ccm_credentials_ptr) { 00453 //Use certificate if set otherwise use PSKd 00454 if (0 > coap_service_certificate_set(thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id, cur->thread_info->ccm_credentials_ptr->domain_certificate_ptr, cur->thread_info->ccm_credentials_ptr->domain_certificate_len, 00455 cur->thread_info->ccm_credentials_ptr->domain_pk_ptr, cur->thread_info->ccm_credentials_ptr->domain_pk_len)) { 00456 tr_debug("coap service certificate set failed"); 00457 return -1; 00458 } 00459 } 00460 tr_debug("start nmkp commissioning: interface %d, parent: %s, port %d", interface_id, trace_ipv6(parent_address), port); 00461 00462 thread_info(cur)->ccm_credentials_ptr->ccm_done_cb = done_cb; 00463 memcpy(thread_info(cur)->ccm_credentials_ptr->ccm_addr, parent_address, 16); 00464 thread_info(cur)->ccm_credentials_ptr->ccm_port = port; 00465 00466 uint8_t *ptr, *data_ptr; 00467 uint16_t length; 00468 00469 tr_debug("Thread joiner finalisation send"); 00470 length = thread_joiner_application_device_configuration_length(thread_joiner_application_get_device_config(interface_id)); 00471 00472 data_ptr = ptr = ns_dyn_mem_alloc(length); 00473 if (!ptr) { 00474 tr_error("Failed to start Commissioning"); 00475 return -1; 00476 } 00477 ptr = thread_joiner_application_device_configuration_build(ptr, thread_joiner_application_get_device_config(interface_id)); 00478 00479 coap_service_request_send(thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, parent_address, port, 00480 COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_BBR_NMKP_REQ, COAP_CT_OCTET_STREAM, data_ptr, ptr - data_ptr, thread_ccm_nmkp_response_cb); 00481 00482 ns_dyn_mem_free(data_ptr); 00483 00484 return 0; 00485 } 00486 00487 /* 00488 * Allocate thread commercial commission mode (CCM) struct 00489 */ 00490 void thread_ccm_allocate(protocol_interface_info_entry_t *cur) 00491 { 00492 if (thread_info(cur)->ccm_credentials_ptr) { 00493 return; 00494 } 00495 00496 thread_info(cur)->ccm_credentials_ptr = ns_dyn_mem_alloc(sizeof(thread_ccm_credentials_t)); 00497 if (!thread_info(cur)->ccm_credentials_ptr) { 00498 return; 00499 } 00500 memset(thread_info(cur)->ccm_credentials_ptr, 0, sizeof(thread_ccm_credentials_t)); 00501 00502 thread_info(cur)->ccm_credentials_ptr->interface_id = cur->id; 00503 00504 ns_list_add_to_start(&ccm_instance_list, thread_info(cur)->ccm_credentials_ptr); 00505 } 00506 00507 /* 00508 * Free thread commercial commission mode (CCM) struct 00509 */ 00510 00511 void thread_ccm_free(protocol_interface_info_entry_t *cur) 00512 { 00513 if (!cur || !thread_info(cur) || !thread_info(cur)->ccm_credentials_ptr) { 00514 return; 00515 } 00516 00517 if (thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr) { 00518 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr); 00519 } 00520 if (thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr) { 00521 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr); 00522 } 00523 ns_list_remove(&ccm_instance_list, thread_info(cur)->ccm_credentials_ptr); 00524 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr); 00525 thread_info(cur)->ccm_credentials_ptr = NULL; 00526 } 00527 00528 int thread_ccm_device_certificate_set(protocol_interface_info_entry_t *cur, const unsigned char *device_certificate_ptr, uint16_t device_certificate_len, const unsigned char *priv_key_ptr, uint16_t priv_key_len) 00529 { 00530 00531 if (!thread_info(cur)->ccm_credentials_ptr) { 00532 thread_ccm_allocate(cur); 00533 } 00534 00535 thread_info(cur)->ccm_credentials_ptr->device_certificate_ptr = device_certificate_ptr; 00536 thread_info(cur)->ccm_credentials_ptr->device_certificate_len = device_certificate_len; 00537 thread_info(cur)->ccm_credentials_ptr->device_pk_ptr = priv_key_ptr; 00538 thread_info(cur)->ccm_credentials_ptr->device_pk_len = priv_key_len; 00539 00540 return 0; 00541 } 00542 00543 bool thread_ccm_network_certificate_available(protocol_interface_info_entry_t *cur) 00544 { 00545 if (!thread_info(cur)->ccm_credentials_ptr || !thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr) { 00546 return false; 00547 } 00548 00549 return true; 00550 } 00551 00552 int thread_ccm_network_certificate_set(protocol_interface_info_entry_t *cur, const unsigned char *domain_certificate_ptr, uint16_t domain_certificate_len) 00553 { 00554 if (!thread_info(cur)->ccm_credentials_ptr) { 00555 thread_ccm_allocate(cur); 00556 } 00557 00558 if (thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr) { 00559 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr); 00560 thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr = NULL; 00561 thread_info(cur)->ccm_credentials_ptr->domain_certificate_len = 0; 00562 } 00563 00564 /* Set domain certificate pointer and length */ 00565 if (domain_certificate_ptr) { 00566 thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr = ns_dyn_mem_alloc(domain_certificate_len + thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_len); 00567 if (!thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr) { 00568 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr); 00569 return -1; 00570 } 00571 memcpy(thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr, domain_certificate_ptr, domain_certificate_len); 00572 if (thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_ptr) { 00573 memcpy(thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr + domain_certificate_len, thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_ptr, thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_len); 00574 } 00575 thread_info(cur)->ccm_credentials_ptr->domain_certificate_len = domain_certificate_len + thread_info(cur)->ccm_credentials_ptr->domain_ca_certificate_len; 00576 } 00577 00578 return 0; 00579 } 00580 00581 int thread_ccm_network_private_key_set(protocol_interface_info_entry_t *cur, const unsigned char *priv_key_ptr, uint16_t priv_key_len) 00582 { 00583 if (!thread_info(cur)->ccm_credentials_ptr) { 00584 thread_ccm_allocate(cur); 00585 } 00586 00587 if (thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr) { 00588 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr); 00589 thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr = NULL; 00590 thread_info(cur)->ccm_credentials_ptr->domain_pk_len = 0; 00591 } 00592 00593 if (priv_key_ptr) { 00594 thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr = ns_dyn_mem_alloc(priv_key_len); 00595 if (!thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr) { 00596 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr); 00597 ns_dyn_mem_free(thread_info(cur)->ccm_credentials_ptr); 00598 return -1; 00599 } 00600 00601 memcpy(thread_info(cur)->ccm_credentials_ptr->domain_pk_ptr, priv_key_ptr, priv_key_len); 00602 thread_info(cur)->ccm_credentials_ptr->domain_pk_len = priv_key_len; 00603 } 00604 00605 return 0; 00606 } 00607 00608 int thread_ccm_thread_name_set(protocol_interface_info_entry_t *cur, char thread_name[16]) 00609 { 00610 if (!thread_info(cur)->ccm_credentials_ptr) { 00611 thread_info(cur)->ccm_credentials_ptr = ns_dyn_mem_alloc(sizeof(thread_ccm_credentials_t)); 00612 if (!thread_info(cur)->ccm_credentials_ptr) { 00613 return -1; 00614 } 00615 memset(thread_info(cur)->ccm_credentials_ptr, 0, sizeof(thread_ccm_credentials_t)); 00616 } 00617 memset(thread_info(cur)->ccm_credentials_ptr->domain_name, 0, 16); 00618 memcpy(thread_info(cur)->ccm_credentials_ptr->domain_name, thread_name, 16); 00619 00620 return 0; 00621 } 00622 00623 int thread_ccm_commission_start(protocol_interface_info_entry_t *cur, uint8_t parent_address[16], discovery_response_list_t *nwk_info, thread_commission_done_cb *done_cb) 00624 { 00625 00626 if (thread_info(cur)->version >= THREAD_VERSION_1_2 && thread_info(cur)->ccm_credentials_ptr) { 00627 if (thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr && nwk_info->ccm_info.nmk_port) { 00628 return thread_ccm_nmkp_commission_start(cur->id, parent_address, nwk_info->ccm_info.nmk_port, done_cb); 00629 } else if (thread_info(cur)->ccm_credentials_ptr->device_certificate_ptr && nwk_info->ccm_info.ae_port) { 00630 return thread_ccm_ae_commission_start(cur->id, parent_address, nwk_info->ccm_info.ae_port, done_cb); 00631 } else if (nwk_info->joiner_port) { 00632 return thread_joiner_application_pskd_commission_start(cur->id, parent_address, nwk_info->joiner_port, nwk_info->pan_id, nwk_info->extented_pan_id, nwk_info->channel, done_cb); 00633 } else { 00634 return -1; 00635 } 00636 } 00637 return -1; 00638 } 00639 00640 discovery_response_list_t *thread_ccm_network_select(protocol_interface_info_entry_t *cur, thread_nwk_discovery_response_list_t *discover_response) 00641 { 00642 discovery_response_list_t *discovered_network_ptr = NULL; 00643 00644 if (thread_info(cur)->version >= THREAD_VERSION_1_2 && thread_info(cur)->ccm_credentials_ptr) { 00645 /* If we have domain certificate, search for domain to join */ 00646 if (thread_info(cur)->ccm_credentials_ptr->domain_certificate_ptr) { 00647 ns_list_foreach_safe(discovery_response_list_t, cur_class, discover_response) { 00648 if ((stringlen((const char *) cur_class->ccm_info.domain_name, 16)) && 00649 (!memcmp(cur_class->ccm_info.domain_name, thread_info(cur)->ccm_credentials_ptr->domain_name, stringlen((const char *) cur_class->ccm_info.domain_name, 16)))) { 00650 discovered_network_ptr = cur_class; 00651 break; 00652 } 00653 } 00654 } 00655 00656 /* No domain, use device certificate*/ 00657 if (!discovered_network_ptr) { 00658 ns_list_foreach_safe(discovery_response_list_t, cur_class, discover_response) { 00659 if (cur_class->ccm_info.ccm_supported) { 00660 discovered_network_ptr = cur_class; 00661 break; 00662 } 00663 } 00664 } 00665 } 00666 00667 return discovered_network_ptr; 00668 } 00669 00670 uint8_t thread_ccm_thread_name_length_get(protocol_interface_info_entry_t *cur) 00671 { 00672 if (!thread_info(cur)->ccm_credentials_ptr) { 00673 return 0; 00674 } 00675 00676 return stringlen((const char *)thread_info(cur)->ccm_credentials_ptr->domain_name, 16); 00677 } 00678 00679 uint8_t *thread_ccm_thread_name_ptr_get(protocol_interface_info_entry_t *cur) 00680 { 00681 if (!thread_info(cur)->ccm_credentials_ptr) { 00682 return NULL; 00683 } 00684 00685 return thread_info(cur)->ccm_credentials_ptr->domain_name; 00686 } 00687 00688 int thread_ccm_network_certificate_enable(protocol_interface_info_entry_t *cur, int8_t coap_service_id) 00689 { 00690 // SET certificates 00691 if (cur->thread_info->ccm_credentials_ptr && cur->thread_info->ccm_credentials_ptr->domain_certificate_ptr) { 00692 if (0 > coap_service_certificate_set(coap_service_id, cur->thread_info->ccm_credentials_ptr->domain_certificate_ptr, cur->thread_info->ccm_credentials_ptr->domain_certificate_len, 00693 cur->thread_info->ccm_credentials_ptr->domain_pk_ptr, cur->thread_info->ccm_credentials_ptr->domain_pk_len)) { 00694 tr_debug("pBBR certificate set failed"); 00695 return -1; 00696 } 00697 } 00698 return 0; 00699 } 00700 00701 00702 static int thread_ccm_reenroll_resp_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 00703 { 00704 (void) service_id; 00705 (void) source_address; 00706 (void) source_port; 00707 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(thread_ccm_find_id_by_service(service_id)); 00708 00709 // Close secure connection 00710 coap_service_close_secure_connection(service_id, source_address, source_port); 00711 00712 if (!response_ptr || !cur) { 00713 tr_debug("re-enroll failed"); 00714 return -1; 00715 } 00716 00717 tr_debug("re-enroll resp len %d", response_ptr->payload_len); 00718 00719 // todo:check new certificate 00720 // Update certificate 00721 if (0 == thread_ccm_enroll_parse(cur, response_ptr->payload_ptr, response_ptr->payload_len)) { 00722 // start NMKP with new certificates 00723 thread_ccm_network_reattach(service_id, 5000, true); 00724 } 00725 00726 return 0; 00727 } 00728 static int thread_ccm_reenroll_csrattrs_resp_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 00729 { 00730 (void) service_id; 00731 00732 if (!response_ptr) { 00733 tr_debug("No response to re-enroll csrattr req"); 00734 return -1; 00735 } 00736 00737 coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, source_address, source_port, 00738 COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, THREAD_URI_SIMPLEREENROLL, THREAD_CONTENT_FORMAT_PKCS10, 00739 csr_request, sizeof(csr_request), thread_ccm_reenroll_resp_cb); 00740 00741 return 0; 00742 00743 } 00744 00745 static int thread_ccm_reenroll_registrar_addr_resp_cb(int8_t service_id, uint8_t source_address[static 16], uint16_t source_port, sn_coap_hdr_s *response_ptr) 00746 { 00747 (void) service_id; 00748 (void) source_address; 00749 (void) source_port; 00750 00751 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(thread_management_server_interface_id_get(service_id)); 00752 uint8_t *addr_ptr = NULL; 00753 00754 if (!response_ptr) { 00755 tr_debug("No response to registrar addr get"); 00756 return -1; 00757 } 00758 00759 if (!thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_REGISTRAR_IPV6_ADDRESS, &addr_ptr)) { 00760 tr_debug("Registrar addr get failed"); 00761 return -1; 00762 } 00763 00764 tr_debug("Received registrar address %s", trace_ipv6(addr_ptr)); 00765 00766 //todo: what port? 00767 thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id = coap_service_initialize(cur->id, 5684, COAP_SERVICE_OPTIONS_EPHEMERAL_PORT | COAP_SERVICE_OPTIONS_SECURE, thread_ccm_security_start_cb, NULL); 00768 00769 if (cur->thread_info->ccm_credentials_ptr) { 00770 //Use certificate if set otherwise use PSKd 00771 if (0 > coap_service_certificate_set(thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id, cur->thread_info->ccm_credentials_ptr->domain_certificate_ptr, cur->thread_info->ccm_credentials_ptr->domain_certificate_len, 00772 cur->thread_info->ccm_credentials_ptr->domain_pk_ptr, cur->thread_info->ccm_credentials_ptr->domain_pk_len)) { 00773 tr_debug("coap service certificate set failed"); 00774 return -1; 00775 } 00776 } 00777 00778 coap_service_request_send(thread_info(cur)->ccm_credentials_ptr->coap_service_secure_session_id, COAP_REQUEST_OPTIONS_SECURE_BYPASS, addr_ptr, THREAD_DEFAULT_REGISTRAR_PORT, // TBD: get port from somewhere 00779 COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_GET, THREAD_URI_CSRATTRS, THREAD_CONTENT_FORMAT_CSRATTRS, NULL, 0, thread_ccm_reenroll_csrattrs_resp_cb); 00780 00781 return 0; 00782 } 00783 00784 int thread_ccm_reenrollment_start(protocol_interface_info_entry_t *cur, int8_t service_id, uint8_t *pbbr_addr) 00785 { 00786 (void) cur; 00787 uint8_t get_tlv[3] = {0}; 00788 uint8_t *ptr = get_tlv; 00789 uint8_t type = MESHCOP_TLV_REGISTRAR_IPV6_ADDRESS; 00790 00791 //Payload = get tlv including registrar IPV6 address TLV (68) 00792 ptr = thread_meshcop_tlv_data_write(get_tlv, MESHCOP_TLV_GET, 1, &type); 00793 00794 // Send MGMT_BBR_GET.req message to the Primary BBR, requesting the Registrar IPv6 Address TLV 00795 coap_service_request_send(service_id, COAP_REQUEST_OPTIONS_NONE, pbbr_addr, THREAD_MANAGEMENT_PORT, COAP_MSG_TYPE_CONFIRMABLE, 00796 COAP_MSG_CODE_REQUEST_GET, THREAD_URI_BBR_DATA_REQ, COAP_CT_NONE, get_tlv, ptr - get_tlv, thread_ccm_reenroll_registrar_addr_resp_cb); 00797 00798 return 0; 00799 } 00800 00801 #endif /* HAVE_THREAD_V2 */
Generated on Tue Jul 12 2022 13:54:58 by
