Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mconnectionsecuritypimpl.cpp Source File

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 }