Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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 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 }