Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers thread_ccm.c Source File

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 */