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 Security NULL."); 00079 return -1; 00080 } 00081 00082 if(_entropy.entropy_source_ptr) { 00083 if(PAL_SUCCESS != pal_addEntropySource(_entropy.entropy_source_ptr)){ 00084 return -1; 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("pal_initTLSConfiguration failed"); 00095 return -1; 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 || PAL_SUCCESS != pal_setCAChain(_conf, &caChain, NULL)){ 00123 tr_error("pal_setCAChain failed"); 00124 return -1; 00125 } 00126 00127 privateKey.size = MAX_CERTIFICATE_SIZE; 00128 ret_code = security->resource_value_buffer(M2MSecurity::Secretkey, certificate_ptr, security_instance_id, (size_t*)&privateKey.size); 00129 privateKey.buffer = certificate_ptr; 00130 if (ret_code < 0 || PAL_SUCCESS != pal_setOwnPrivateKey(_conf, &privateKey)) { 00131 tr_error("pal_setOwnPrivateKey failed"); 00132 return -1; 00133 } 00134 00135 void *dummy; 00136 00137 // Open certificate chain, size parameter contains the depth of certificate chain 00138 size_t cert_chain_size = 0; 00139 security->resource_value_buffer(M2MSecurity::OpenCertificateChain, (uint8_t *&)dummy, security_instance_id, &cert_chain_size); 00140 tr_info("M2MConnectionSecurityPimpl::init - cert chain length: %" PRIu32, cert_chain_size); 00141 00142 int index = 0; 00143 while (index < cert_chain_size) { 00144 owncert.size = MAX_CERTIFICATE_SIZE; 00145 ret_code = security->resource_value_buffer(M2MSecurity::ReadDeviceCertificateChain, certificate_ptr, security_instance_id, (size_t*)&owncert.size); 00146 owncert.buffer = certificate_ptr; 00147 00148 if (ret_code < 0 || PAL_SUCCESS != pal_setOwnCertChain(_conf, &owncert)){ 00149 tr_error("pal_setOwnCertChain failed"); 00150 security->resource_value_buffer(M2MSecurity::CloseCertificateChain, (uint8_t *&)dummy, security_instance_id, &cert_chain_size); 00151 return -1; 00152 } 00153 00154 index++; 00155 } 00156 security->resource_value_buffer(M2MSecurity::CloseCertificateChain, (uint8_t *&)dummy, security_instance_id, &cert_chain_size); 00157 00158 } else if (cert_mode == M2MSecurity::Psk){ 00159 00160 uint8_t identity[MAX_CERTIFICATE_SIZE]; 00161 uint8_t *identity_ptr = (uint8_t *)&identity; 00162 uint32_t identity_len; 00163 uint8_t psk[MAX_CERTIFICATE_SIZE]; 00164 uint8_t *psk_ptr = (uint8_t *)&psk; 00165 uint32_t psk_len; 00166 00167 security->resource_value_buffer(M2MSecurity::PublicKey, identity_ptr, security_instance_id, (size_t*)&identity_len); 00168 security->resource_value_buffer(M2MSecurity::Secretkey, psk_ptr, security_instance_id, (size_t*)&psk_len); 00169 palStatus_t ret = pal_setPSK(_conf, identity_ptr, identity_len, psk_ptr, psk_len); 00170 00171 00172 if(PAL_SUCCESS != ret){ 00173 tr_error("pal_setPSK failed"); 00174 return -1; 00175 } 00176 00177 }else{ 00178 tr_error("Security mode not set"); 00179 return -1; 00180 00181 } 00182 00183 if(PAL_SUCCESS != pal_initTLS(_conf, &_ssl)){ 00184 tr_error("pal_initTLS failed"); 00185 return -1; 00186 } 00187 00188 if(PAL_SUCCESS != pal_tlsSetSocket(_conf, &_tls_socket)){ 00189 tr_error("pal_tlsSetSocket failed"); 00190 return -1; 00191 } 00192 00193 _init_done = M2MConnectionSecurityPimpl::INIT_DONE; 00194 00195 #ifdef MBED_CONF_MBED_TRACE_ENABLE 00196 // Note: This call is not enough, one also needs the MBEDTLS_DEBUG_C to be defined globally 00197 // on build and if using default mbedtls configuration file, the 00198 // "#undef MBEDTLS_DEBUG_C" -line needs to be removed from mbedtls_mbed_client_config.h 00199 pal_sslSetDebugging(_conf, 1); 00200 #endif 00201 00202 tr_debug("M2MConnectionSecurityPimpl::init - out"); 00203 return 0; 00204 } 00205 00206 int M2MConnectionSecurityPimpl::start_handshake() 00207 { 00208 tr_debug("M2MConnectionSecurityPimpl::start_handshake"); 00209 00210 palStatus_t ret; 00211 00212 ret = pal_handShake(_ssl, _conf); 00213 00214 if(ret == PAL_ERR_TLS_WANT_READ || ret == PAL_ERR_TLS_WANT_WRITE || ret == PAL_ERR_TIMEOUT_EXPIRED ){ 00215 return M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00216 } 00217 else if(ret == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00218 return M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00219 } 00220 00221 if(ret != PAL_SUCCESS){ //We loose the original error here! 00222 tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_handShake() error %" PRId32, ret); 00223 return -1; 00224 } 00225 00226 ret = pal_sslGetVerifyResult(_ssl); 00227 if(PAL_SUCCESS != ret){ 00228 tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_sslGetVerifyResult() error %" PRId32, ret); 00229 return -1; 00230 } 00231 00232 return ret; 00233 } 00234 00235 int M2MConnectionSecurityPimpl::connect(M2MConnectionHandler* connHandler) 00236 { 00237 tr_debug("M2MConnectionSecurityPimpl::connect"); 00238 int ret = -1; 00239 00240 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00241 return ret; 00242 } 00243 00244 ret = start_handshake(); 00245 tr_debug("M2MConnectionSecurityPimpl::connect - handshake ret: %d", ret); 00246 return ret; 00247 } 00248 00249 00250 int M2MConnectionSecurityPimpl::send_message(unsigned char *message, int len) 00251 { 00252 tr_debug("M2MConnectionSecurityPimpl::send_message"); 00253 int ret = -1; 00254 palStatus_t return_value; 00255 uint32_t len_write; 00256 00257 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00258 return ret; 00259 } 00260 00261 00262 if(PAL_SUCCESS == (return_value = pal_sslWrite(_ssl, message, len, &len_write))){ 00263 ret = (int)len_write; 00264 } 00265 else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00266 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00267 } 00268 else if(return_value == PAL_ERR_TLS_WANT_WRITE) { 00269 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE; 00270 } 00271 else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00272 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00273 } 00274 00275 tr_debug("M2MConnectionSecurityPimpl::send_message - ret: %d", ret); 00276 return ret; //bytes written 00277 } 00278 00279 int M2MConnectionSecurityPimpl::read(unsigned char* buffer, uint16_t len) 00280 { 00281 int ret = -1; 00282 palStatus_t return_value; 00283 uint32_t len_read; 00284 00285 if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ 00286 tr_error("M2MConnectionSecurityPimpl::read - init not done!"); 00287 return ret; 00288 } 00289 00290 if(PAL_SUCCESS == (return_value = pal_sslRead(_ssl, buffer, len, &len_read))){ 00291 ret = (int)len_read; 00292 } 00293 00294 else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TLS_WANT_WRITE || return_value == PAL_ERR_TIMEOUT_EXPIRED ){ 00295 ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; 00296 } 00297 00298 else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { 00299 ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; 00300 } 00301 00302 return ret; 00303 } 00304 00305 void M2MConnectionSecurityPimpl::set_random_number_callback(random_number_cb callback) 00306 { 00307 (void)callback; 00308 } 00309 00310 void M2MConnectionSecurityPimpl::set_entropy_callback(entropy_cb callback) 00311 { 00312 00313 _entropy = callback; 00314 00315 } 00316 00317 void M2MConnectionSecurityPimpl::set_socket(palSocket_t socket, palSocketAddress_t *address) 00318 { 00319 _tls_socket.socket = socket; 00320 _tls_socket.socketAddress = address; 00321 _tls_socket.addressLength = sizeof(palSocketAddress_t); 00322 00323 if(_sec_mode == M2MConnectionSecurity::TLS){ 00324 _tls_socket.transportationMode = PAL_TLS_MODE; 00325 } 00326 else{ 00327 _tls_socket.transportationMode = PAL_DTLS_MODE; 00328 } 00329 } 00330 00331 bool M2MConnectionSecurityPimpl::certificate_parse_valid_time(const char *certificate, uint32_t certificate_len, uint64_t *valid_from, uint64_t *valid_to) 00332 { 00333 palX509Handle_t cert = 0; 00334 size_t len; 00335 palStatus_t ret; 00336 00337 tr_debug("certificate_validfrom_time"); 00338 00339 ret = pal_x509Initiate(&cert); 00340 if(PAL_SUCCESS != ret) { 00341 tr_error("certificate_validfrom_time - cert init failed: %u", (int)ret); 00342 pal_x509Free(&cert); 00343 return false; 00344 } 00345 if(PAL_SUCCESS != (ret = pal_x509CertParse(cert, (const unsigned char*)certificate, certificate_len))) { 00346 tr_error("certificate_validfrom_time - cert parse failed: %u", (int)ret); 00347 pal_x509Free(&cert); 00348 return false; 00349 } 00350 if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_FROM, valid_from, sizeof(uint64_t), &len))) { 00351 tr_error("certificate_validfrom_time - cert attr get failed: %u", (int)ret); 00352 pal_x509Free(&cert); 00353 return false; 00354 } 00355 if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_TO, valid_to, sizeof(uint64_t), &len))) { 00356 tr_error("certificate_validto_time - cert attr get failed: %u", (int)ret); 00357 pal_x509Free(&cert); 00358 return false; 00359 } 00360 00361 pal_x509Free(&cert); 00362 return true; 00363 }
Generated on Tue Jul 12 2022 16:24:13 by
1.7.2