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.
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 if(_ssl) { 00054 pal_freeTLS(&_ssl); 00055 } 00056 if(_conf) { 00057 pal_tlsConfigurationFree(&_conf); 00058 } 00059 } 00060 00061 void M2MConnectionSecurityPimpl::reset() 00062 { 00063 if(_ssl) { 00064 pal_freeTLS(&_ssl); 00065 } 00066 if(_conf) { 00067 pal_tlsConfigurationFree(&_conf); 00068 } 00069 _init_done = M2MConnectionSecurityPimpl::INIT_NOT_STARTED; 00070 } 00071 00072 int M2MConnectionSecurityPimpl::init(const M2MSecurity *security, uint16_t security_instance_id) 00073 { 00074 tr_debug("M2MConnectionSecurityPimpl::init"); 00075 00076 if(!security){ 00077 tr_error("M2MConnectionSecurityPimpl Security NULL."); 00078 return -1; 00079 } 00080 00081 if(_entropy.entropy_source_ptr) { 00082 if(PAL_SUCCESS != pal_addEntropySource(_entropy.entropy_source_ptr)){ 00083 return -1; 00084 } 00085 } 00086 00087 palTLSTransportMode_t mode = PAL_DTLS_MODE; 00088 if(_sec_mode == M2MConnectionSecurity::TLS){ 00089 mode = PAL_TLS_MODE; 00090 } 00091 00092 if(PAL_SUCCESS != pal_initTLSConfiguration(&_conf, mode)){ 00093 tr_error("pal_initTLSConfiguration failed"); 00094 return -1; 00095 } 00096 00097 _init_done = M2MConnectionSecurityPimpl::INIT_CONFIGURING; 00098 00099 00100 if(_sec_mode == M2MConnectionSecurity::DTLS){ 00101 // PAL divides the defined MAX_TIMEOUT by 2 00102 pal_setHandShakeTimeOut(_conf, MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT*2); 00103 } 00104 00105 M2MSecurity::SecurityModeType cert_mode = 00106 (M2MSecurity::SecurityModeType)security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id); 00107 00108 if( cert_mode == M2MSecurity::Certificate ){ 00109 00110 palX509_t owncert; 00111 palPrivateKey_t privateKey; 00112 palX509_t caChain; 00113 00114 // Check if we are connecting to M2MServer and check if server and device certificates are valid, no need to do this 00115 // for Bootstrap or direct LWM2M server case 00116 if ((security->server_type(security_instance_id) == M2MSecurity::M2MServer) && 00117 (security->get_security_instance_id(M2MSecurity::Bootstrap) >= 0) && 00118 !check_security_object_validity(security, security_instance_id)) { 00119 tr_error("M2MConnectionSecurityPimpl::init - M2MServer certificate invalid or device certificate expired!"); 00120 return -1; 00121 } 00122 00123 owncert.size = 1 + security->resource_value_buffer(M2MSecurity::PublicKey, (const uint8_t*&)owncert.buffer, security_instance_id); 00124 privateKey.size = 1 + security->resource_value_buffer(M2MSecurity::Secretkey, (const uint8_t*&)privateKey.buffer, security_instance_id); 00125 caChain.size = 1 + security->resource_value_buffer(M2MSecurity::ServerPublicKey, (const uint8_t*&)caChain.buffer, security_instance_id); 00126 00127 if(PAL_SUCCESS != pal_setOwnCertAndPrivateKey(_conf, &owncert, &privateKey)){ 00128 tr_error("pal_setOwnCertAndPrivateKey failed"); 00129 return -1; 00130 } 00131 if(PAL_SUCCESS != pal_setCAChain(_conf, &caChain, NULL)){ 00132 tr_error("pal_setCAChain failed"); 00133 return -1; 00134 } 00135 00136 }else if(cert_mode == M2MSecurity::Psk){ 00137 00138 uint8_t *identity = NULL; 00139 uint32_t identity_len; 00140 uint8_t *psk = NULL; 00141 uint32_t psk_len; 00142 00143 identity_len = security->resource_value_buffer(M2MSecurity::PublicKey, identity, security_instance_id); 00144 psk_len = security->resource_value_buffer(M2MSecurity::Secretkey, psk, security_instance_id); 00145 palStatus_t ret = pal_setPSK(_conf, identity, identity_len, psk, psk_len); 00146 free(identity); 00147 free(psk); 00148 00149 if(PAL_SUCCESS != ret){ 00150 tr_error("pal_setPSK failed"); 00151 return -1; 00152 } 00153 00154 }else{ 00155 tr_error("Security mode not set"); 00156 return -1; 00157 00158 } 00159 00160 if(PAL_SUCCESS != pal_initTLS(_conf, &_ssl)){ 00161 tr_error("pal_initTLS failed"); 00162 return -1; 00163 } 00164 00165 if(PAL_SUCCESS != pal_tlsSetSocket(_conf, &_tls_socket)){ 00166 tr_error("pal_tlsSetSocket failed"); 00167 return -1; 00168 } 00169 00170 _init_done = M2MConnectionSecurityPimpl::INIT_DONE; 00171 00172 #ifdef MBED_CONF_MBED_TRACE_ENABLE 00173 // Note: This call is not enough, one also needs the MBEDTLS_DEBUG_C to be defined globally 00174 // on build and if using default mbedtls configuration file, the 00175 // "#undef MBEDTLS_DEBUG_C" -line needs to be removed from mbedtls_mbed_client_config.h 00176 pal_sslDebugging(1); 00177 #endif 00178 00179 tr_debug("M2MConnectionSecurityPimpl::init - out"); 00180 return 0; 00181 } 00182 00183 int M2MConnectionSecurityPimpl::start_handshake() 00184 { 00185 tr_debug("M2MConnectionSecurityPimpl::start_handshake"); 00186 00187 palStatus_t ret; 00188 00189 ret = pal_handShake(_ssl, _conf); 00190 00191 if(ret == PAL_ERR_TLS_WANT_READ || ret == PAL_ERR_TLS_WANT_WRITE || ret == PAL_ERR_TIMEOUT_EXPIRED ){ 00192 return M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00193 } 00194 else if(ret == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00195 return M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00196 } 00197 00198 if(ret != PAL_SUCCESS){ //We loose the original error here! 00199 tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_handShake() error %" PRId32, ret); 00200 return -1; 00201 } 00202 00203 ret = pal_sslGetVerifyResult(_ssl); 00204 if(PAL_SUCCESS != ret){ 00205 tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_sslGetVerifyResult() error %" PRId32, ret); 00206 return -1; 00207 } 00208 00209 return ret; 00210 } 00211 00212 int M2MConnectionSecurityPimpl::connect(M2MConnectionHandler* connHandler) 00213 { 00214 tr_debug("M2MConnectionSecurityPimpl::connect"); 00215 int ret = -1; 00216 00217 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00218 return ret; 00219 } 00220 00221 ret = start_handshake(); 00222 tr_debug("M2MConnectionSecurityPimpl::connect - handshake ret: %d", ret); 00223 return ret; 00224 } 00225 00226 00227 int M2MConnectionSecurityPimpl::send_message(unsigned char *message, int len) 00228 { 00229 tr_debug("M2MConnectionSecurityPimpl::send_message"); 00230 int ret = -1; 00231 palStatus_t return_value; 00232 uint32_t len_write; 00233 00234 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00235 return ret; 00236 } 00237 00238 00239 if(PAL_SUCCESS == (return_value = pal_sslWrite(_ssl, message, len, &len_write))){ 00240 ret = (int)len_write; 00241 } 00242 else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00243 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00244 } 00245 else if(return_value == PAL_ERR_TLS_WANT_WRITE) { 00246 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE; 00247 } 00248 else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00249 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00250 } 00251 00252 tr_debug("M2MConnectionSecurityPimpl::send_message - ret: %d", ret); 00253 return ret; //bytes written 00254 } 00255 00256 int M2MConnectionSecurityPimpl::read(unsigned char* buffer, uint16_t len) 00257 { 00258 int ret = -1; 00259 palStatus_t return_value; 00260 uint32_t len_read; 00261 00262 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00263 tr_error("M2MConnectionSecurityPimpl::read - init not done!"); 00264 return ret; 00265 } 00266 00267 if(PAL_SUCCESS == (return_value = pal_sslRead(_ssl, buffer, len, &len_read))){ 00268 ret = (int)len_read; 00269 } 00270 00271 else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TLS_WANT_WRITE || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00272 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00273 } 00274 00275 else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00276 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00277 } 00278 00279 return ret; 00280 } 00281 00282 void M2MConnectionSecurityPimpl::set_random_number_callback(random_number_cb callback) 00283 { 00284 (void)callback; 00285 } 00286 00287 void M2MConnectionSecurityPimpl::set_entropy_callback(entropy_cb callback) 00288 { 00289 00290 _entropy = callback; 00291 00292 } 00293 00294 void M2MConnectionSecurityPimpl::set_socket(palSocket_t socket, palSocketAddress_t *address) 00295 { 00296 _tls_socket.socket = socket; 00297 _tls_socket.socketAddress = address; 00298 _tls_socket.addressLength = sizeof(palSocketAddress_t); 00299 00300 if(_sec_mode == M2MConnectionSecurity::TLS){ 00301 _tls_socket.transportationMode = PAL_TLS_MODE; 00302 } 00303 else{ 00304 _tls_socket.transportationMode = PAL_DTLS_MODE; 00305 } 00306 } 00307 00308 bool M2MConnectionSecurityPimpl::certificate_parse_valid_time(const char *certificate, uint32_t certificate_len, uint64_t *valid_from, uint64_t *valid_to) 00309 { 00310 palX509Handle_t cert = 0; 00311 size_t len; 00312 palStatus_t ret; 00313 00314 tr_debug("certificate_validfrom_time"); 00315 00316 if(PAL_SUCCESS != (ret = pal_x509Initiate(&cert))) { 00317 tr_error("certificate_validfrom_time - cert init failed: %u", (int)ret); 00318 pal_x509Free(&cert); 00319 return false; 00320 } 00321 if(PAL_SUCCESS != (ret = pal_x509CertParse(cert, (const unsigned char*)certificate, certificate_len))) { 00322 tr_error("certificate_validfrom_time - cert parse failed: %u", (int)ret); 00323 pal_x509Free(&cert); 00324 return false; 00325 } 00326 if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_FROM, valid_from, sizeof(uint64_t), &len))) { 00327 tr_error("certificate_validfrom_time - cert attr get failed: %u", (int)ret); 00328 pal_x509Free(&cert); 00329 return false; 00330 } 00331 if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_TO, valid_to, sizeof(uint64_t), &len))) { 00332 tr_error("certificate_validto_time - cert attr get failed: %u", (int)ret); 00333 pal_x509Free(&cert); 00334 return false; 00335 } 00336 00337 pal_x509Free(&cert); 00338 return true; 00339 } 00340 00341 bool M2MConnectionSecurityPimpl::check_security_object_validity(const M2MSecurity *security, uint16_t security_instance_id) { 00342 // Get time from device object 00343 M2MDevice *device = M2MInterfaceFactory::create_device(); 00344 const uint8_t *certificate = NULL; 00345 int64_t device_time = 0; 00346 uint32_t cert_len = 0; 00347 00348 if (device == NULL || security == NULL) { 00349 tr_error("No time from device object or security object available, fail connector registration %p, %p\n", device, security); 00350 return false; 00351 } 00352 00353 // Get time from device object, returns -1 if resource not found 00354 device_time = device->resource_value_int(M2MDevice::CurrentTime, 0); 00355 00356 tr_debug("Checking client certificate validity"); 00357 00358 // Get client certificate 00359 cert_len = security->resource_value_buffer(M2MSecurity::PublicKey, certificate, security_instance_id); 00360 if (cert_len == 0 || certificate == NULL) { 00361 tr_error("No certificate to check, return fail"); 00362 return false; 00363 } 00364 00365 if (device_time == -1 || !check_certificate_validity(certificate, cert_len, device_time)) { 00366 tr_error("Client certificate not valid!"); 00367 return false; 00368 } 00369 return true; 00370 } 00371 00372 bool M2MConnectionSecurityPimpl::check_certificate_validity(const uint8_t *cert, const uint32_t cert_len, const int64_t device_time) 00373 { 00374 00375 // Get the validFrom and validTo fields from certificate 00376 uint64_t server_validfrom = 0; 00377 uint64_t server_validto = 0; 00378 if(!certificate_parse_valid_time((const char*)cert, cert_len, &server_validfrom, &server_validto)) { 00379 tr_error("Certificate time parsing failed"); 00380 return false; 00381 } 00382 00383 tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - valid from: %" PRIu64, server_validfrom); 00384 tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - valid to: %" PRIu64, server_validto); 00385 // Cast to uint32_t since all platforms does not support PRId64 macro 00386 tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - device time: %" PRIu32, (uint32_t)device_time); 00387 00388 if (device_time < (uint32_t)server_validfrom || device_time > (uint32_t)server_validto) { 00389 tr_error("Invalid certificate validity or device time outside of certificate validity period!"); 00390 return false; 00391 } 00392 00393 return true; 00394 } 00395
Generated on Tue Jul 12 2022 19:01:35 by
1.7.2