Toyomasa Watarai
/
Mbed-example-WS-W27
Mbed Cloud example program for workshop in W27 2018.
Embed:
(wiki syntax)
Show/hide line numbers
m2mconnectionsecuritypimpl.cpp
00001 /* 00002 * Copyright (c) 2015 - 2017 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 // Needed for PRIu64 on FreeRTOS 00018 #include <stdio.h> 00019 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX 00020 #ifndef __STDC_LIMIT_MACROS 00021 #define __STDC_LIMIT_MACROS 00022 #endif 00023 00024 // Note: this macro is needed on armcc to get the the PRI*32 macros 00025 // from inttypes.h in a C++ code. 00026 #ifndef __STDC_FORMAT_MACROS 00027 #define __STDC_FORMAT_MACROS 00028 #endif 00029 00030 #include "mbed-client/m2mconnectionhandler.h" 00031 #include "mbed-client-mbedtls/m2mconnectionsecuritypimpl.h" 00032 #include "mbed-client/m2msecurity.h" 00033 #include "mbed-trace/mbed_trace.h" 00034 #include "pal.h" 00035 #include "m2mdevice.h" 00036 #include "m2minterfacefactory.h" 00037 #include <string.h> 00038 00039 #define TRACE_GROUP "mClt" 00040 00041 M2MConnectionSecurityPimpl::M2MConnectionSecurityPimpl(M2MConnectionSecurity::SecurityMode mode) 00042 :_init_done(M2MConnectionSecurityPimpl::INIT_NOT_STARTED), 00043 _conf(0), 00044 _ssl(0), 00045 _sec_mode(mode) 00046 { 00047 memset(&_entropy, 0, sizeof(entropy_cb)); 00048 memset(&_tls_socket, 0, sizeof(palTLSSocket_t)); 00049 } 00050 00051 M2MConnectionSecurityPimpl::~M2MConnectionSecurityPimpl() 00052 { 00053 pal_freeTLS(&_ssl); 00054 pal_tlsConfigurationFree(&_conf); 00055 } 00056 00057 void M2MConnectionSecurityPimpl::reset() 00058 { 00059 pal_freeTLS(&_ssl); 00060 pal_tlsConfigurationFree(&_conf); 00061 _init_done = M2MConnectionSecurityPimpl::INIT_NOT_STARTED; 00062 } 00063 00064 int M2MConnectionSecurityPimpl::init(const M2MSecurity *security, uint16_t security_instance_id) 00065 { 00066 tr_debug("M2MConnectionSecurityPimpl::init"); 00067 00068 if(!security){ 00069 tr_error("M2MConnectionSecurityPimpl Security NULL."); 00070 return -1; 00071 } 00072 00073 if(_entropy.entropy_source_ptr) { 00074 if(PAL_SUCCESS != pal_addEntropySource(_entropy.entropy_source_ptr)){ 00075 return -1; 00076 } 00077 } 00078 00079 palTLSTransportMode_t mode = PAL_DTLS_MODE; 00080 if(_sec_mode == M2MConnectionSecurity::TLS){ 00081 mode = PAL_TLS_MODE; 00082 } 00083 00084 if(PAL_SUCCESS != pal_initTLSConfiguration(&_conf, mode)){ 00085 tr_error("pal_initTLSConfiguration failed"); 00086 return -1; 00087 } 00088 00089 _init_done = M2MConnectionSecurityPimpl::INIT_CONFIGURING; 00090 00091 00092 if(_sec_mode == M2MConnectionSecurity::DTLS){ 00093 // PAL divides the defined MAX_TIMEOUT by 2 00094 pal_setHandShakeTimeOut(_conf, MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT*2); 00095 } 00096 00097 M2MSecurity::SecurityModeType cert_mode = 00098 (M2MSecurity::SecurityModeType)security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id); 00099 00100 if( cert_mode == M2MSecurity::Certificate ){ 00101 00102 palX509_t owncert; 00103 palPrivateKey_t privateKey; 00104 palX509_t caChain; 00105 00106 // Check if we are connecting to M2MServer and check if server and device certificates are valid, no need to do this 00107 // for Bootstrap or direct LWM2M server case 00108 if ((security->server_type(security_instance_id) == M2MSecurity::M2MServer) && 00109 (security->get_security_instance_id(M2MSecurity::Bootstrap) >= 0) && 00110 !check_security_object_validity(security, security_instance_id)) { 00111 tr_error("M2MConnectionSecurityPimpl::init - M2MServer certificate invalid or device certificate expired!"); 00112 return -1; 00113 } 00114 00115 owncert.size = 1 + security->resource_value_buffer(M2MSecurity::PublicKey, (const uint8_t*&)owncert.buffer, security_instance_id); 00116 privateKey.size = 1 + security->resource_value_buffer(M2MSecurity::Secretkey, (const uint8_t*&)privateKey.buffer, security_instance_id); 00117 caChain.size = 1 + security->resource_value_buffer(M2MSecurity::ServerPublicKey, (const uint8_t*&)caChain.buffer, security_instance_id); 00118 00119 if(PAL_SUCCESS != pal_setOwnCertAndPrivateKey(_conf, &owncert, &privateKey)){ 00120 tr_error("pal_setOwnCertAndPrivateKey failed"); 00121 return -1; 00122 } 00123 if(PAL_SUCCESS != pal_setCAChain(_conf, &caChain, NULL)){ 00124 tr_error("pal_setCAChain failed"); 00125 return -1; 00126 } 00127 00128 }else if(cert_mode == M2MSecurity::Psk){ 00129 00130 uint8_t *identity = NULL; 00131 uint32_t identity_len; 00132 uint8_t *psk = NULL; 00133 uint32_t psk_len; 00134 00135 identity_len = security->resource_value_buffer(M2MSecurity::PublicKey, identity, security_instance_id); 00136 psk_len = security->resource_value_buffer(M2MSecurity::Secretkey, psk, security_instance_id); 00137 palStatus_t ret = pal_setPSK(_conf, identity, identity_len, psk, psk_len); 00138 free(identity); 00139 free(psk); 00140 00141 if(PAL_SUCCESS != ret){ 00142 tr_error("pal_setPSK failed"); 00143 return -1; 00144 } 00145 00146 }else{ 00147 tr_error("Security mode not set"); 00148 return -1; 00149 00150 } 00151 00152 if(PAL_SUCCESS != pal_initTLS(_conf, &_ssl)){ 00153 tr_error("pal_initTLS failed"); 00154 return -1; 00155 } 00156 00157 if(PAL_SUCCESS != pal_tlsSetSocket(_conf, &_tls_socket)){ 00158 tr_error("pal_tlsSetSocket failed"); 00159 return -1; 00160 } 00161 00162 _init_done = M2MConnectionSecurityPimpl::INIT_DONE; 00163 00164 #ifdef MBED_CONF_MBED_TRACE_ENABLE 00165 // Note: This call is not enough, one also needs the MBEDTLS_DEBUG_C to be defined globally 00166 // on build and if using default mbedtls configuration file, the 00167 // "#undef MBEDTLS_DEBUG_C" -line needs to be removed from mbedtls_mbed_client_config.h 00168 pal_sslDebugging(1); 00169 #endif 00170 00171 tr_debug("M2MConnectionSecurityPimpl::init - out"); 00172 return 0; 00173 } 00174 00175 int M2MConnectionSecurityPimpl::start_handshake() 00176 { 00177 tr_debug("M2MConnectionSecurityPimpl::start_handshake"); 00178 00179 palStatus_t ret; 00180 00181 ret = pal_handShake(_ssl, _conf); 00182 00183 if(ret == PAL_ERR_TLS_WANT_READ || ret == PAL_ERR_TLS_WANT_WRITE || ret == PAL_ERR_TIMEOUT_EXPIRED ){ 00184 return M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00185 } 00186 else if(ret == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00187 return M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00188 } 00189 00190 if(ret != PAL_SUCCESS){ //We loose the original error here! 00191 tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_handShake() error %" PRId32, ret); 00192 return -1; 00193 } 00194 00195 ret = pal_sslGetVerifyResult(_ssl); 00196 if(PAL_SUCCESS != ret){ 00197 tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_sslGetVerifyResult() error %" PRId32, ret); 00198 return -1; 00199 } 00200 00201 return ret; 00202 } 00203 00204 int M2MConnectionSecurityPimpl::connect(M2MConnectionHandler* connHandler) 00205 { 00206 tr_debug("M2MConnectionSecurityPimpl::connect"); 00207 int ret = -1; 00208 00209 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00210 return ret; 00211 } 00212 00213 ret = start_handshake(); 00214 tr_debug("M2MConnectionSecurityPimpl::connect - handshake ret: %d", ret); 00215 return ret; 00216 } 00217 00218 00219 int M2MConnectionSecurityPimpl::send_message(unsigned char *message, int len) 00220 { 00221 tr_debug("M2MConnectionSecurityPimpl::send_message"); 00222 int ret = -1; 00223 palStatus_t return_value; 00224 uint32_t len_write; 00225 00226 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00227 return ret; 00228 } 00229 00230 00231 if(PAL_SUCCESS == (return_value = pal_sslWrite(_ssl, message, len, &len_write))){ 00232 ret = (int)len_write; 00233 } 00234 else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00235 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00236 } 00237 else if(return_value == PAL_ERR_TLS_WANT_WRITE) { 00238 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE; 00239 } 00240 else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00241 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00242 } 00243 00244 tr_debug("M2MConnectionSecurityPimpl::send_message - ret: %d", ret); 00245 return ret; //bytes written 00246 } 00247 00248 int M2MConnectionSecurityPimpl::read(unsigned char* buffer, uint16_t len) 00249 { 00250 int ret = -1; 00251 palStatus_t return_value; 00252 uint32_t len_read; 00253 00254 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00255 tr_error("M2MConnectionSecurityPimpl::read - init not done!"); 00256 return ret; 00257 } 00258 00259 if(PAL_SUCCESS == (return_value = pal_sslRead(_ssl, buffer, len, &len_read))){ 00260 ret = (int)len_read; 00261 } 00262 00263 else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TLS_WANT_WRITE || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00264 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00265 } 00266 00267 else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00268 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00269 } 00270 00271 return ret; 00272 } 00273 00274 void M2MConnectionSecurityPimpl::set_random_number_callback(random_number_cb callback) 00275 { 00276 (void)callback; 00277 } 00278 00279 void M2MConnectionSecurityPimpl::set_entropy_callback(entropy_cb callback) 00280 { 00281 00282 _entropy = callback; 00283 00284 } 00285 00286 void M2MConnectionSecurityPimpl::set_socket(palSocket_t socket, palSocketAddress_t *address) 00287 { 00288 _tls_socket.socket = socket; 00289 _tls_socket.socketAddress = address; 00290 _tls_socket.addressLength = sizeof(palSocketAddress_t); 00291 00292 if(_sec_mode == M2MConnectionSecurity::TLS){ 00293 _tls_socket.transportationMode = PAL_TLS_MODE; 00294 } 00295 else{ 00296 _tls_socket.transportationMode = PAL_DTLS_MODE; 00297 } 00298 } 00299 00300 bool M2MConnectionSecurityPimpl::certificate_parse_valid_time(const char *certificate, uint32_t certificate_len, uint64_t *valid_from, uint64_t *valid_to) 00301 { 00302 palX509Handle_t cert = 0; 00303 size_t len; 00304 palStatus_t ret; 00305 00306 tr_debug("certificate_validfrom_time"); 00307 00308 if(PAL_SUCCESS != (ret = pal_x509Initiate(&cert))) { 00309 tr_error("certificate_validfrom_time - cert init failed: %u", (int)ret); 00310 pal_x509Free(&cert); 00311 return false; 00312 } 00313 if(PAL_SUCCESS != (ret = pal_x509CertParse(cert, (const unsigned char*)certificate, certificate_len))) { 00314 tr_error("certificate_validfrom_time - cert parse failed: %u", (int)ret); 00315 pal_x509Free(&cert); 00316 return false; 00317 } 00318 if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_FROM, valid_from, sizeof(uint64_t), &len))) { 00319 tr_error("certificate_validfrom_time - cert attr get failed: %u", (int)ret); 00320 pal_x509Free(&cert); 00321 return false; 00322 } 00323 if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_TO, valid_to, sizeof(uint64_t), &len))) { 00324 tr_error("certificate_validto_time - cert attr get failed: %u", (int)ret); 00325 pal_x509Free(&cert); 00326 return false; 00327 } 00328 00329 pal_x509Free(&cert); 00330 return true; 00331 } 00332 00333 bool M2MConnectionSecurityPimpl::check_security_object_validity(const M2MSecurity *security, uint16_t security_instance_id) { 00334 // Get time from device object 00335 M2MDevice *device = M2MInterfaceFactory::create_device(); 00336 const uint8_t *certificate = NULL; 00337 int64_t device_time = 0; 00338 uint32_t cert_len = 0; 00339 00340 if (device == NULL || security == NULL) { 00341 tr_error("No time from device object or security object available, fail connector registration %p, %p\n", device, security); 00342 return false; 00343 } 00344 00345 // Get time from device object, returns -1 if resource not found 00346 device_time = device->resource_value_int(M2MDevice::CurrentTime, 0); 00347 00348 tr_debug("Checking client certificate validity"); 00349 00350 // Get client certificate 00351 cert_len = security->resource_value_buffer(M2MSecurity::PublicKey, certificate, security_instance_id); 00352 if (cert_len == 0 || certificate == NULL) { 00353 tr_error("No certificate to check, return fail"); 00354 return false; 00355 } 00356 00357 if (device_time == -1 || !check_certificate_validity(certificate, cert_len, device_time)) { 00358 tr_error("Client certificate not valid!"); 00359 return false; 00360 } 00361 return true; 00362 } 00363 00364 bool M2MConnectionSecurityPimpl::check_certificate_validity(const uint8_t *cert, const uint32_t cert_len, const int64_t device_time) 00365 { 00366 00367 // Get the validFrom and validTo fields from certificate 00368 uint64_t server_validfrom = 0; 00369 uint64_t server_validto = 0; 00370 if(!certificate_parse_valid_time((const char*)cert, cert_len, &server_validfrom, &server_validto)) { 00371 tr_error("Certificate time parsing failed"); 00372 return false; 00373 } 00374 00375 tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - valid from: %" PRIu64, server_validfrom); 00376 tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - valid to: %" PRIu64, server_validto); 00377 // Cast to uint32_t since all platforms does not support PRId64 macro 00378 tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - device time: %" PRIu32, (uint32_t)device_time); 00379 00380 if (device_time < (uint32_t)server_validfrom || device_time > (uint32_t)server_validto) { 00381 tr_error("Invalid certificate validity or device time outside of certificate validity period!"); 00382 return false; 00383 } 00384 00385 return true; 00386 } 00387
Generated on Tue Jul 12 2022 16:22:06 by 1.7.2