V.06 11/3
Dependencies: FT6206 SDFileSystem SPI_TFT_ILI9341 TFT_fonts
Fork of ATT_AWS_IoT_demo by
Diff: AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/mbedtls/network_mbedtls_wrapper.cpp
- Revision:
- 15:6f2798e45099
- Child:
- 18:6370da1de572
diff -r 339320b096c5 -r 6f2798e45099 AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/mbedtls/network_mbedtls_wrapper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_mbed_os/mbedtls/network_mbedtls_wrapper.cpp Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,440 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include <stdbool.h> +#include <string.h> + + +#include "aws_iot_config.h" +#include "aws_iot_error.h" +#include "aws_iot_log.h" +#include "network_interface.h" +#include "mbedtls/config.h" + +#include "mbedtls/net.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/certs.h" +#include "mbedtls/x509.h" +#include "mbedtls/error.h" +#include "mbedtls/debug.h" +#include "mbedtls/timing.h" +#include "mbedtls/net_sockets.h" +#include "pem.h" + +#include "platform.h" +#include "WNCTCPSocketConnection.h" + +#ifdef USING_AVNET_SHIELD +// Used for BIO connections +extern WNCTCPSocketConnection* _tcpsocket; +#endif + +/* + * This is a function to do further verification if needed on the cert received + */ +static int myCertVerify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) { + char buf[1024]; + ((void) data); + + DEBUG("\nVerify requested for (Depth %d):\n", depth); + mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt); + DEBUG("%s", buf); + + if ((*flags) == 0) { + DEBUG(" This certificate has no flags\n"); + } else { + DEBUG(buf, sizeof(buf), " ! ", *flags); DEBUG("%s\n", buf); + } + + return (0); +} + +static int ret = 0, i; +static mbedtls_entropy_context entropy; +static mbedtls_ctr_drbg_context ctr_drbg; +static mbedtls_ssl_context ssl; +static mbedtls_ssl_config conf; +static uint32_t flags; +static mbedtls_x509_crt cacert; +static mbedtls_x509_crt clicert; +static mbedtls_pk_context pkey; +static mbedtls_net_context server_fd; + +// TODO: We can modify these functions to pull certs from an SD card +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) +{ + //FILE *f; + //long size; + + // Assign cert/key based on 'path' + /* + switch (path[0]) + { + case 'r': + *n = (size_t)(sizeof(AWS_IOT_ROOT_CA)/sizeof(AWS_IOT_ROOT_CA[0])); + *buf = AWS_IOT_ROOT_CA; + break; + case 'c': + *n = (size_t)(sizeof(AWS_IOT_CERTIFICATE)/sizeof(AWS_IOT_CERTIFICATE[0])); + *buf = AWS_IOT_CERTIFICATE; + break; + case 'p': + *n = (size_t)sizeof (AWS_IOT_PRIVATE_KEY); + *buf = (unsigned char *) AWS_IOT_PRIVATE_KEY; + + //ret = mbedtls_pk_parse_key(&pkey, (unsigned char *) AWS_IOT_PRIVATE_KEY, sizeof (AWS_IOT_PRIVATE_KEY), NULL, 0 ); + break; + default: + ERROR(" failed\n ! Unknown option for cert/key\n\r"); + }*/ + + /* + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + //fclose( f ); + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + mbedtls_free( *buf ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + */ + + return( 0 ); +} +// Implementation that should never be optimized out by the compiler +static void mbedtls_zeroize( unsigned char *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + DEBUG("...CRT Parse"); + ret = mbedtls_x509_crt_parse( chain, buf, n ); + + //mbedtls_zeroize( buf, n ); + //mbedtls_free( buf ); + + return( ret ); +} +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *pwd ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + DEBUG("...Key Parse"); + if( pwd == NULL ) { + DEBUG("...Using PWD"); + ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); + } + else { + DEBUG("...No PWD"); + ret = mbedtls_pk_parse_key( ctx, buf, n, (const unsigned char *) pwd, strlen( pwd ) ); + } + + //mbedtls_zeroize( buf, n ); + //mbedtls_free( buf ); + + return( ret ); +} +// TODO: File system functions end + +/* personalization string for the drbg */ +const char *DRBG_PERS = "mbed TLS helloword client"; + +int iot_tls_init(Network *pNetwork) { + IoT_Error_t ret_val = NONE_ERROR; + const char *pers = "aws_iot_tls_wrapper"; + unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1]; + + mbedtls_net_init(&server_fd); + mbedtls_ssl_init(&ssl); + mbedtls_ssl_config_init(&conf); + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_x509_crt_init(&cacert); + mbedtls_x509_crt_init(&clicert); + mbedtls_pk_init(&pkey); + + DEBUG("...Seeding the random number generator"); + mbedtls_entropy_init(&entropy); + if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) DRBG_PERS, sizeof (DRBG_PERS))) != 0) { + ERROR(" failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret); + return ret_val; + } + DEBUG(" ok\n"); + + pNetwork->my_socket = 0; + pNetwork->connect = iot_tls_connect; + pNetwork->mqttread = iot_tls_read; + pNetwork->mqttwrite = iot_tls_write; + pNetwork->disconnect = iot_tls_disconnect; + pNetwork->isConnected = iot_tls_is_connected; + pNetwork->destroy = iot_tls_destroy; + + return ret_val; +} + +int iot_tls_is_connected(Network *pNetwork) { + /* Use this to add implementation which can check for physical layer disconnect */ + return 1; +} + +int iot_tls_connect(Network *pNetwork, TLSConnectParams params) { + const char *pers = "aws_iot_tls_wrapper"; + + DEBUG("...Loading the CA root certificate"); + // TODO: We can pull the cert from an SD card + //ret = mbedtls_x509_crt_parse_file(&cacert, params.pRootCALocation); + ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *)AWS_IOT_ROOT_CA, strlen ((const char *)AWS_IOT_ROOT_CA)+1); + + if (ret < 0) { + ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + DEBUG(" ok (%d skipped)", ret); + + + DEBUG("...Loading the client cert"); + // TODO: We can pull the cert from an SD card + //ret = mbedtls_x509_crt_parse_file(&clicert, params.pDeviceCertLocation); + ret = mbedtls_x509_crt_parse(&clicert, (const unsigned char *)AWS_IOT_CERTIFICATE, strlen ((const char *)AWS_IOT_CERTIFICATE)+1); + if (ret != 0) { + ERROR(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + return ret; + } + DEBUG(" ok"); + + + DEBUG("...Loading the client key"); + // TODO: We can pull the cert from an SD card + //ret = mbedtls_pk_parse_keyfile(&pkey, params.pDevicePrivateKeyLocation, ""); + ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *)AWS_IOT_PRIVATE_KEY, strlen ((const char *)AWS_IOT_PRIVATE_KEY)+1, NULL, 0 ); + if (ret != 0) { + ERROR(" failed\n ! mbedtls_pk_parse_key returned -0x%x\n\n", -ret); + return ret; + } + DEBUG(" ok"); + + + char portBuffer[6]; + sprintf(portBuffer, "%d", params.DestinationPort); + DEBUG("...Connecting to %s/%s", params.pDestinationURL, portBuffer); + if ((ret = mbedtls_net_connect(&server_fd, params.pDestinationURL, portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) { + ERROR(" failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret); + return ret; + } + + + ret = mbedtls_net_set_block(&server_fd); + if (ret != 0) { + ERROR(" failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret); + return ret; + } + DEBUG(" ok"); + + + DEBUG("...Setting up the SSL/TLS structure"); + if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + ERROR(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret); + return ret; + } + + + mbedtls_ssl_conf_verify(&conf, myCertVerify, NULL); + if (params.ServerVerificationFlag == true) { + mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED); + } else { + mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + } + mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); + + mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); + if ((ret = mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey)) != 0) { + ERROR(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret); + return ret; + } + + mbedtls_ssl_conf_read_timeout(&conf, params.timeout_ms); + + if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { + ERROR(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret); + return ret; + } + if ((ret = mbedtls_ssl_set_hostname(&ssl, params.pDestinationURL)) != 0) { + ERROR(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); + return ret; + } + + DEBUG("...Set Socket I/O Functions"); + mbedtls_ssl_set_bio(&ssl, static_cast<void *>(_tcpsocket), mbedtls_net_send, NULL, mbedtls_net_recv_timeout ); + DEBUG(" ok"); + + + DEBUG("...Performing the SSL/TLS handshake"); + while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ERROR(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret); + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + ERROR(" Unable to verify the server's certificate. " + "Either it is invalid,\n" + " or you didn't set ca_file or ca_path " + "to an appropriate value.\n" + " Alternatively, you may want to use " + "auth_mode=optional for testing purposes.\n"); + } + return ret; + } + } + + + DEBUG(" ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n", mbedtls_ssl_get_version(&ssl), mbedtls_ssl_get_ciphersuite(&ssl)); + if ((ret = mbedtls_ssl_get_record_expansion(&ssl)) >= 0) { + DEBUG(" [ Record expansion is %d ]\n", ret); + } else { + DEBUG(" [ Record expansion is unknown (compression) ]\n"); + } + + + DEBUG("...Verifying peer X.509 certificate"); + if (params.ServerVerificationFlag == true) { + if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { + char vrfy_buf[512]; + ERROR(" failed\n"); + mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); + ERROR("%s\n", vrfy_buf); + } else { + DEBUG(" ok\n"); + ret = NONE_ERROR; + } + } else { + DEBUG(" Server Verification skipped\n"); + ret = NONE_ERROR; + } + + + DEBUG("...SSL get peer cert"); + if (mbedtls_ssl_get_peer_cert(&ssl) != NULL) { + DEBUG("...Peer certificate information"); + const uint32_t buf_size = 1024; + char *buf = new char[buf_size]; + mbedtls_x509_crt_info(buf, buf_size, " ", mbedtls_ssl_get_peer_cert(&ssl)); + DEBUG("...Server certificate:\r\n%s\r", buf); + } + + mbedtls_ssl_conf_read_timeout(&conf, 10); + + return ret; +} + +int iot_tls_write(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) { + + int written; + int frags; + + for (written = 0, frags = 0; written < len; written += ret, frags++) { + while ((ret = mbedtls_ssl_write(&ssl, pMsg + written, len - written)) <= 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ERROR(" failed\n ! mbedtls_ssl_write returned -0x%x\n\n", -ret); + return ret; + } + } + } + + return written; +} + +int iot_tls_read(Network *pNetwork, unsigned char *pMsg, int len, int timeout_ms) { + int rxLen = 0; + bool isErrorFlag = false; + bool isCompleteFlag = false; + + // TODO check this against base + //mbedtls_ssl_conf_read_timeout(&conf, timeout_ms); + + do { + ret = mbedtls_ssl_read(&ssl, pMsg, len); + if (ret > 0) { + rxLen += ret; + } else if (ret != MBEDTLS_ERR_SSL_WANT_READ) { + isErrorFlag = true; + } + if (rxLen >= len) { + isCompleteFlag = true; + } + } while (!isErrorFlag && !isCompleteFlag); + + return ret; +} + +void iot_tls_disconnect(Network *pNetwork) { + do { + ret = mbedtls_ssl_close_notify(&ssl); + } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE); +} + +int iot_tls_destroy(Network *pNetwork) { + + mbedtls_net_free(&server_fd); + + mbedtls_x509_crt_free(&clicert); + mbedtls_x509_crt_free(&cacert); + mbedtls_pk_free(&pkey); + mbedtls_ssl_free(&ssl); + mbedtls_ssl_config_free(&conf); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + + return 0; +} + +