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 "mbed-client/m2mconstants.h" 00035 #include "pal.h" 00036 #include "m2mdevice.h" 00037 #include "m2minterfacefactory.h" 00038 #include <string.h> 00039 00040 #define TRACE_GROUP "mClt" 00041 00042 M2MConnectionSecurityPimpl::M2MConnectionSecurityPimpl(M2MConnectionSecurity::SecurityMode mode) 00043 :_init_done(M2MConnectionSecurityPimpl::INIT_NOT_STARTED), 00044 _conf(0), 00045 _ssl(0), 00046 _sec_mode(mode) 00047 { 00048 memset(&_entropy, 0, sizeof(entropy_cb)); 00049 memset(&_tls_socket, 0, sizeof(palTLSSocket_t)); 00050 } 00051 00052 M2MConnectionSecurityPimpl::~M2MConnectionSecurityPimpl() 00053 { 00054 if(_ssl) { 00055 pal_freeTLS(&_ssl); 00056 } 00057 if(_conf) { 00058 pal_tlsConfigurationFree(&_conf); 00059 } 00060 } 00061 00062 void M2MConnectionSecurityPimpl::reset() 00063 { 00064 if(_ssl) { 00065 pal_freeTLS(&_ssl); 00066 } 00067 if(_conf) { 00068 pal_tlsConfigurationFree(&_conf); 00069 } 00070 _init_done = M2MConnectionSecurityPimpl::INIT_NOT_STARTED; 00071 } 00072 00073 int M2MConnectionSecurityPimpl::init(const M2MSecurity *security, uint16_t security_instance_id) 00074 { 00075 tr_debug("M2MConnectionSecurityPimpl::init"); 00076 00077 if (!security){ 00078 tr_error("M2MConnectionSecurityPimpl::init - security null"); 00079 return M2MConnectionHandler::ERROR_GENERIC; 00080 } 00081 00082 if (_entropy.entropy_source_ptr) { 00083 if (PAL_SUCCESS != pal_addEntropySource(_entropy.entropy_source_ptr)) { 00084 return M2MConnectionHandler::ERROR_GENERIC; 00085 } 00086 } 00087 00088 palTLSTransportMode_t mode = PAL_DTLS_MODE; 00089 if (_sec_mode == M2MConnectionSecurity::TLS) { 00090 mode = PAL_TLS_MODE; 00091 } 00092 00093 if (PAL_SUCCESS != pal_initTLSConfiguration(&_conf, mode)) { 00094 tr_error("M2MConnectionSecurityPimpl::init - pal_initTLSConfiguration failed"); 00095 return M2MConnectionHandler::ERROR_GENERIC; 00096 } 00097 00098 _init_done = M2MConnectionSecurityPimpl::INIT_CONFIGURING; 00099 00100 00101 if (_sec_mode == M2MConnectionSecurity::DTLS) { 00102 // PAL divides the defined MAX_TIMEOUT by 2 00103 pal_setHandShakeTimeOut(_conf, MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT*2); 00104 } 00105 00106 M2MSecurity::SecurityModeType cert_mode = 00107 (M2MSecurity::SecurityModeType)security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id); 00108 00109 if (cert_mode == M2MSecurity::Certificate || cert_mode == M2MSecurity::EST ) { 00110 00111 palX509_t owncert; 00112 palPrivateKey_t privateKey; 00113 palX509_t caChain; 00114 00115 uint8_t certificate[MAX_CERTIFICATE_SIZE]; 00116 uint8_t *certificate_ptr = (uint8_t *)&certificate; 00117 00118 caChain.size = MAX_CERTIFICATE_SIZE; 00119 int ret_code = security->resource_value_buffer(M2MSecurity::ServerPublicKey, certificate_ptr, security_instance_id, (size_t*)&caChain.size); 00120 caChain.buffer = certificate_ptr; 00121 00122 if (ret_code < 0) { 00123 tr_error("M2MConnectionSecurityPimpl::init - failed to read public key"); 00124 return M2MConnectionHandler::FAILED_TO_READ_CREDENTIALS; 00125 } 00126 00127 if (PAL_SUCCESS != pal_setCAChain(_conf, &caChain, NULL)) { 00128 tr_error("M2MConnectionSecurityPimpl::init - pal_setCAChain failed"); 00129 return M2MConnectionHandler::ERROR_GENERIC; 00130 } 00131 00132 privateKey.size = MAX_CERTIFICATE_SIZE; 00133 ret_code = security->resource_value_buffer(M2MSecurity::Secretkey, certificate_ptr, security_instance_id, (size_t*)&privateKey.size); 00134 privateKey.buffer = certificate_ptr; 00135 00136 if (ret_code < 0) { 00137 tr_error("M2MConnectionSecurityPimpl::init - failed to read secret key"); 00138 return M2MConnectionHandler::FAILED_TO_READ_CREDENTIALS; 00139 } 00140 00141 if (PAL_SUCCESS != pal_setOwnPrivateKey(_conf, &privateKey)) { 00142 tr_error("M2MConnectionSecurityPimpl::init - pal_setOwnPrivateKey failed"); 00143 return M2MConnectionHandler::ERROR_GENERIC; 00144 } 00145 00146 void *dummy; 00147 00148 // Open certificate chain, size parameter contains the depth of certificate chain 00149 size_t cert_chain_size = 0; 00150 if (security->resource_value_buffer(M2MSecurity::OpenCertificateChain, (uint8_t *&)dummy, security_instance_id, &cert_chain_size) < 0) { 00151 tr_error("M2MConnectionSecurityPimpl::init - fail to open certificate chain!"); 00152 return M2MConnectionHandler::FAILED_TO_READ_CREDENTIALS; 00153 } else if (cert_chain_size == 0) { 00154 tr_error("M2MConnectionSecurityPimpl::init - no certificate!"); 00155 security->resource_value_buffer(M2MSecurity::CloseCertificateChain, (uint8_t *&)dummy, security_instance_id, &cert_chain_size); 00156 return M2MConnectionHandler::ERROR_GENERIC; 00157 } else { 00158 tr_info("M2MConnectionSecurityPimpl::init - cert chain length: %lu", (unsigned long)cert_chain_size); 00159 size_t index = 0; 00160 00161 while (index < cert_chain_size) { 00162 owncert.size = MAX_CERTIFICATE_SIZE; 00163 ret_code = security->resource_value_buffer(M2MSecurity::ReadDeviceCertificateChain, certificate_ptr, security_instance_id, (size_t*)&owncert.size); 00164 owncert.buffer = certificate_ptr; 00165 00166 if (ret_code < 0) { 00167 tr_error("M2MConnectionSecurityPimpl::init - failed to read device certificate"); 00168 return M2MConnectionHandler::FAILED_TO_READ_CREDENTIALS; 00169 } 00170 00171 if (PAL_SUCCESS != pal_setOwnCertChain(_conf, &owncert)) { 00172 tr_error("M2MConnectionSecurityPimpl::init - pal_setOwnCertChain failed"); 00173 security->resource_value_buffer(M2MSecurity::CloseCertificateChain, (uint8_t *&)dummy, security_instance_id, &cert_chain_size); 00174 return M2MConnectionHandler::ERROR_GENERIC; 00175 } 00176 00177 index++; 00178 } 00179 security->resource_value_buffer(M2MSecurity::CloseCertificateChain, (uint8_t *&)dummy, security_instance_id, &cert_chain_size); 00180 } 00181 00182 } else if (cert_mode == M2MSecurity::Psk) { 00183 00184 uint8_t identity[MAX_CERTIFICATE_SIZE]; 00185 uint8_t *identity_ptr = (uint8_t *)&identity; 00186 uint32_t identity_len = 0; 00187 uint8_t psk[MAX_CERTIFICATE_SIZE]; 00188 uint8_t *psk_ptr = (uint8_t *)&psk; 00189 uint32_t psk_len = 0; 00190 00191 int ret_code = security->resource_value_buffer(M2MSecurity::PublicKey, identity_ptr, security_instance_id, (size_t*)&identity_len); 00192 if (ret_code < 0) { 00193 tr_error("M2MConnectionSecurityPimpl::init - failed to read PSK identity"); 00194 return M2MConnectionHandler::ERROR_GENERIC; 00195 } 00196 00197 ret_code = security->resource_value_buffer(M2MSecurity::Secretkey, psk_ptr, security_instance_id, (size_t*)&psk_len); 00198 if (ret_code < 0) { 00199 tr_error("M2MConnectionSecurityPimpl::init - failed to read PSK key"); 00200 return M2MConnectionHandler::ERROR_GENERIC;; 00201 } 00202 00203 palStatus_t ret = pal_setPSK(_conf, identity_ptr, identity_len, psk_ptr, psk_len); 00204 00205 if (PAL_SUCCESS != ret) { 00206 tr_error("M2MConnectionSecurityPimpl::init - pal_setPSK failed"); 00207 return M2MConnectionHandler::ERROR_GENERIC;; 00208 } 00209 00210 } else { 00211 tr_error("M2MConnectionSecurityPimpl::init - security mode not set"); 00212 return M2MConnectionHandler::ERROR_GENERIC; 00213 } 00214 00215 if (PAL_SUCCESS != pal_initTLS(_conf, &_ssl)) { 00216 tr_error("M2MConnectionSecurityPimpl::init - pal_initTLS failed"); 00217 return M2MConnectionHandler::ERROR_GENERIC; 00218 } 00219 00220 if (PAL_SUCCESS != pal_tlsSetSocket(_conf, &_tls_socket)) { 00221 tr_error("M2MConnectionSecurityPimpl::init - pal_tlsSetSocket failed"); 00222 return M2MConnectionHandler::ERROR_GENERIC; 00223 } 00224 00225 _init_done = M2MConnectionSecurityPimpl::INIT_DONE; 00226 00227 #if MBED_CONF_MBED_TRACE_ENABLE 00228 // Note: This call is not enough, one also needs the MBEDTLS_DEBUG_C to be defined globally 00229 // on build and if using default mbedtls configuration file, the 00230 // "#undef MBEDTLS_DEBUG_C" -line needs to be removed from mbedtls_mbed_client_config.h 00231 pal_sslSetDebugging(_conf, 1); 00232 #endif 00233 00234 return M2MConnectionHandler::ERROR_NONE; 00235 } 00236 00237 int M2MConnectionSecurityPimpl::start_handshake() 00238 { 00239 tr_debug("M2MConnectionSecurityPimpl::start_handshake"); 00240 00241 palStatus_t ret; 00242 00243 ret = pal_handShake(_ssl, _conf); 00244 00245 if (ret == PAL_ERR_TLS_WANT_READ || ret == PAL_ERR_TLS_WANT_WRITE || ret == PAL_ERR_TIMEOUT_EXPIRED ){ 00246 return M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00247 } 00248 else if (ret == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00249 return M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00250 } 00251 else if (ret == PAL_ERR_NO_MEMORY ) { 00252 return M2MConnectionHandler::MEMORY_ALLOCATION_FAILED; 00253 } 00254 00255 if (ret != PAL_SUCCESS){ //We loose the original error here! 00256 tr_error("M2MConnectionScurityPimpl::start_handshake pal_handShake() error %" PRIx32, ret); 00257 return M2MConnectionHandler::ERROR_GENERIC; 00258 } 00259 00260 ret = pal_sslGetVerifyResult(_ssl); 00261 if (PAL_SUCCESS != ret){ 00262 tr_error("M2MConnectionSecurityPimpl::start_handshake pal_sslGetVerifyResult() error %" PRIx32, ret); 00263 return M2MConnectionHandler::ERROR_GENERIC; 00264 } 00265 00266 return ret; 00267 } 00268 00269 int M2MConnectionSecurityPimpl::connect(M2MConnectionHandler* connHandler) 00270 { 00271 tr_debug("M2MConnectionSecurityPimpl::connect"); 00272 int ret = M2MConnectionHandler::ERROR_GENERIC; 00273 00274 if (M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00275 return ret; 00276 } 00277 00278 ret = start_handshake(); 00279 tr_debug("M2MConnectionSecurityPimpl::connect - handshake ret: %d", ret); 00280 return ret; 00281 } 00282 00283 00284 int M2MConnectionSecurityPimpl::send_message(unsigned char *message, int len) 00285 { 00286 tr_debug("M2MConnectionSecurityPimpl::send_message"); 00287 int ret = M2MConnectionHandler::ERROR_GENERIC; 00288 palStatus_t return_value; 00289 uint32_t len_write; 00290 00291 if (M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00292 return ret; 00293 } 00294 00295 if (PAL_SUCCESS == (return_value = pal_sslWrite(_ssl, message, len, &len_write))){ 00296 ret = (int)len_write; 00297 } 00298 else if (return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00299 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00300 } 00301 else if (return_value == PAL_ERR_TLS_WANT_WRITE) { 00302 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE; 00303 } 00304 else if (return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00305 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00306 } 00307 else if (return_value == PAL_ERR_NO_MEMORY ) { 00308 ret = M2MConnectionHandler::MEMORY_ALLOCATION_FAILED; 00309 } 00310 00311 tr_debug("M2MConnectionSecurityPimpl::send_message - ret: %d", ret); 00312 return ret; //bytes written or error 00313 } 00314 00315 int M2MConnectionSecurityPimpl::read(unsigned char* buffer, uint16_t len) 00316 { 00317 int ret = M2MConnectionHandler::ERROR_GENERIC; 00318 palStatus_t return_value; 00319 uint32_t len_read; 00320 00321 if (M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00322 tr_error("M2MConnectionSecurityPimpl::read - init not done!"); 00323 return ret; 00324 } 00325 00326 if (PAL_SUCCESS == (return_value = pal_sslRead(_ssl, buffer, len, &len_read))){ 00327 ret = (int)len_read; 00328 } 00329 else if (return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TLS_WANT_WRITE || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00330 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00331 } 00332 else if (return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00333 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00334 } 00335 else if (return_value == PAL_ERR_NO_MEMORY ) { 00336 ret = M2MConnectionHandler::MEMORY_ALLOCATION_FAILED; 00337 } 00338 00339 return ret; 00340 } 00341 00342 void M2MConnectionSecurityPimpl::set_random_number_callback(random_number_cb callback) 00343 { 00344 (void)callback; 00345 } 00346 00347 void M2MConnectionSecurityPimpl::set_entropy_callback(entropy_cb callback) 00348 { 00349 00350 _entropy = callback; 00351 00352 } 00353 00354 void M2MConnectionSecurityPimpl::set_socket(palSocket_t socket, palSocketAddress_t *address) 00355 { 00356 _tls_socket.socket = socket; 00357 _tls_socket.socketAddress = address; 00358 _tls_socket.addressLength = sizeof(palSocketAddress_t); 00359 00360 if(_sec_mode == M2MConnectionSecurity::TLS){ 00361 _tls_socket.transportationMode = PAL_TLS_MODE; 00362 } 00363 else{ 00364 _tls_socket.transportationMode = PAL_DTLS_MODE; 00365 } 00366 }
Generated on Mon Aug 29 2022 19:53:39 by
