NuMaker connection with AWS IoT thru MQTT/HTTPS

Dependencies:   MQTT_ON_AWS

Committer:
ccli8
Date:
Mon Apr 15 15:40:16 2019 +0800
Revision:
25:edf568984d27
Refine MyTLSSocket code

1. Refactor
2. Add mbed_lib.json to configure its behavior

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ccli8 25:edf568984d27 1 #include "mbed.h"
ccli8 25:edf568984d27 2 #include "MyTLSSocket.h"
ccli8 25:edf568984d27 3
ccli8 25:edf568984d27 4
ccli8 25:edf568984d27 5 MyTLSSocket::MyTLSSocket(NetworkInterface* net_iface, const char* ssl_ca_pem, const char* ssl_owncert_pem, const char* ssl_own_priv_key_pem)
ccli8 25:edf568984d27 6 {
ccli8 25:edf568984d27 7 _tcpsocket = new TCPSocket(net_iface);
ccli8 25:edf568984d27 8 _ssl_ca_pem = ssl_ca_pem;
ccli8 25:edf568984d27 9 _ssl_owncert_pem = ssl_owncert_pem;
ccli8 25:edf568984d27 10 _ssl_own_priv_key_pem = ssl_own_priv_key_pem;
ccli8 25:edf568984d27 11 _is_connected = false;
ccli8 25:edf568984d27 12 _debug = false;
ccli8 25:edf568984d27 13 _hostname = NULL;
ccli8 25:edf568984d27 14 _port = 0;
ccli8 25:edf568984d27 15 _error = 0;
ccli8 25:edf568984d27 16
ccli8 25:edf568984d27 17 DRBG_PERS = "mbed TLS helloword client";
ccli8 25:edf568984d27 18
ccli8 25:edf568984d27 19 mbedtls_entropy_init(&_entropy);
ccli8 25:edf568984d27 20 mbedtls_ctr_drbg_init(&_ctr_drbg);
ccli8 25:edf568984d27 21 mbedtls_x509_crt_init(&_cacert);
ccli8 25:edf568984d27 22 mbedtls_x509_crt_init(&_owncert);
ccli8 25:edf568984d27 23 mbedtls_pk_init(&_own_priv_key);
ccli8 25:edf568984d27 24 mbedtls_ssl_init(&_ssl);
ccli8 25:edf568984d27 25 mbedtls_ssl_config_init(&_ssl_conf);
ccli8 25:edf568984d27 26 }
ccli8 25:edf568984d27 27
ccli8 25:edf568984d27 28 MyTLSSocket::~MyTLSSocket()
ccli8 25:edf568984d27 29 {
ccli8 25:edf568984d27 30 mbedtls_entropy_free(&_entropy);
ccli8 25:edf568984d27 31 mbedtls_ctr_drbg_free(&_ctr_drbg);
ccli8 25:edf568984d27 32 mbedtls_x509_crt_free(&_cacert);
ccli8 25:edf568984d27 33 mbedtls_x509_crt_free(&_owncert);
ccli8 25:edf568984d27 34 mbedtls_pk_free(&_own_priv_key);
ccli8 25:edf568984d27 35 mbedtls_ssl_free(&_ssl);
ccli8 25:edf568984d27 36 mbedtls_ssl_config_free(&_ssl_conf);
ccli8 25:edf568984d27 37
ccli8 25:edf568984d27 38 if (_tcpsocket) {
ccli8 25:edf568984d27 39 _tcpsocket->close();
ccli8 25:edf568984d27 40 delete _tcpsocket;
ccli8 25:edf568984d27 41 }
ccli8 25:edf568984d27 42 }
ccli8 25:edf568984d27 43
ccli8 25:edf568984d27 44 nsapi_error_t MyTLSSocket::close()
ccli8 25:edf568984d27 45 {
ccli8 25:edf568984d27 46 return _tcpsocket->close();
ccli8 25:edf568984d27 47 }
ccli8 25:edf568984d27 48
ccli8 25:edf568984d27 49 nsapi_error_t MyTLSSocket::connect(const char *hostname, uint16_t port)
ccli8 25:edf568984d27 50 {
ccli8 25:edf568984d27 51 _hostname = hostname;
ccli8 25:edf568984d27 52 _port = port;
ccli8 25:edf568984d27 53
ccli8 25:edf568984d27 54 /* Initialize the flags */
ccli8 25:edf568984d27 55 /*
ccli8 25:edf568984d27 56 * Initialize TLS-related stuf.
ccli8 25:edf568984d27 57 */
ccli8 25:edf568984d27 58 int ret;
ccli8 25:edf568984d27 59 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
ccli8 25:edf568984d27 60 (const unsigned char *) DRBG_PERS,
ccli8 25:edf568984d27 61 sizeof (DRBG_PERS))) != 0) {
ccli8 25:edf568984d27 62 print_mbedtls_error("mbedtls_crt_drbg_init", ret);
ccli8 25:edf568984d27 63 _error = ret;
ccli8 25:edf568984d27 64 return _error;
ccli8 25:edf568984d27 65 }
ccli8 25:edf568984d27 66
ccli8 25:edf568984d27 67 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *)_ssl_ca_pem,
ccli8 25:edf568984d27 68 strlen(_ssl_ca_pem) + 1)) != 0) {
ccli8 25:edf568984d27 69 print_mbedtls_error("mbedtls_x509_crt_parse", ret);
ccli8 25:edf568984d27 70 _error = ret;
ccli8 25:edf568984d27 71 return _error;
ccli8 25:edf568984d27 72 }
ccli8 25:edf568984d27 73
ccli8 25:edf568984d27 74 if ((ret = mbedtls_x509_crt_parse(&_owncert, (const unsigned char *) _ssl_owncert_pem,
ccli8 25:edf568984d27 75 strlen(_ssl_owncert_pem) + 1)) != 0) {
ccli8 25:edf568984d27 76 print_mbedtls_error("mbedtls_x509_crt_parse", ret);
ccli8 25:edf568984d27 77 _error = ret;
ccli8 25:edf568984d27 78 return _error;
ccli8 25:edf568984d27 79 }
ccli8 25:edf568984d27 80
ccli8 25:edf568984d27 81 if ((ret = mbedtls_pk_parse_key(&_own_priv_key, (const unsigned char *) _ssl_own_priv_key_pem,
ccli8 25:edf568984d27 82 strlen(_ssl_own_priv_key_pem) + 1, NULL, 0)) != 0) {
ccli8 25:edf568984d27 83 print_mbedtls_error("mbedtls_pk_parse_key", ret);
ccli8 25:edf568984d27 84 _error = ret;
ccli8 25:edf568984d27 85 return _error;
ccli8 25:edf568984d27 86 }
ccli8 25:edf568984d27 87
ccli8 25:edf568984d27 88 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
ccli8 25:edf568984d27 89 MBEDTLS_SSL_IS_CLIENT,
ccli8 25:edf568984d27 90 MBEDTLS_SSL_TRANSPORT_STREAM,
ccli8 25:edf568984d27 91 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
ccli8 25:edf568984d27 92 print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
ccli8 25:edf568984d27 93 _error = ret;
ccli8 25:edf568984d27 94 return _error;
ccli8 25:edf568984d27 95 }
ccli8 25:edf568984d27 96
ccli8 25:edf568984d27 97 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
ccli8 25:edf568984d27 98 mbedtls_ssl_conf_own_cert(&_ssl_conf, &_owncert, &_own_priv_key);
ccli8 25:edf568984d27 99 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
ccli8 25:edf568984d27 100
ccli8 25:edf568984d27 101 /* It is possible to disable authentication by passing
ccli8 25:edf568984d27 102 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
ccli8 25:edf568984d27 103 */
ccli8 25:edf568984d27 104 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
ccli8 25:edf568984d27 105
ccli8 25:edf568984d27 106 /* Enable RFC 6066 max_fragment_length extension in SSL */
ccli8 25:edf568984d27 107 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && (MBED_CONF_MY_TLSSOCKET_TLS_MAX_FRAG_LEN > 0)
ccli8 25:edf568984d27 108 mbedtls_ssl_conf_max_frag_len(&_ssl_conf, MBED_CONF_MY_TLSSOCKET_TLS_MAX_FRAG_LEN);
ccli8 25:edf568984d27 109 #endif
ccli8 25:edf568984d27 110
ccli8 25:edf568984d27 111 #if MBED_CONF_MY_TLSSOCKET_TLS_DEBUG_LEVEL > 0
ccli8 25:edf568984d27 112 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, this);
ccli8 25:edf568984d27 113 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, this);
ccli8 25:edf568984d27 114 mbedtls_debug_set_threshold(MBED_CONF_MY_TLSSOCKET_TLS_DEBUG_LEVEL);
ccli8 25:edf568984d27 115 #endif
ccli8 25:edf568984d27 116
ccli8 25:edf568984d27 117 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
ccli8 25:edf568984d27 118 print_mbedtls_error("mbedtls_ssl_setup", ret);
ccli8 25:edf568984d27 119 _error = ret;
ccli8 25:edf568984d27 120 return _error;
ccli8 25:edf568984d27 121 }
ccli8 25:edf568984d27 122
ccli8 25:edf568984d27 123 mbedtls_ssl_set_hostname(&_ssl, _hostname);
ccli8 25:edf568984d27 124
ccli8 25:edf568984d27 125 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
ccli8 25:edf568984d27 126 ssl_send, ssl_recv, NULL );
ccli8 25:edf568984d27 127
ccli8 25:edf568984d27 128 /* Connect to the server */
ccli8 25:edf568984d27 129 if (_debug) {
ccli8 25:edf568984d27 130 mbedtls_printf("Connecting to %s:%d\r\n", _hostname, _port);
ccli8 25:edf568984d27 131 }
ccli8 25:edf568984d27 132 ret = _tcpsocket->connect(_hostname, _port);
ccli8 25:edf568984d27 133 if (ret != NSAPI_ERROR_OK) {
ccli8 25:edf568984d27 134 if (_debug) {
ccli8 25:edf568984d27 135 mbedtls_printf("Failed to connect\r\n");
ccli8 25:edf568984d27 136 }
ccli8 25:edf568984d27 137 onError(_tcpsocket, -1);
ccli8 25:edf568984d27 138 return _error;
ccli8 25:edf568984d27 139 }
ccli8 25:edf568984d27 140
ccli8 25:edf568984d27 141 /* Start the handshake, the rest will be done in onReceive() */
ccli8 25:edf568984d27 142 if (_debug) {
ccli8 25:edf568984d27 143 mbedtls_printf("Starting the TLS handshake...\r\n");
ccli8 25:edf568984d27 144 }
ccli8 25:edf568984d27 145 do {
ccli8 25:edf568984d27 146 ret = mbedtls_ssl_handshake(&_ssl);
ccli8 25:edf568984d27 147 } while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
ccli8 25:edf568984d27 148 if (ret < 0) {
ccli8 25:edf568984d27 149 print_mbedtls_error("mbedtls_ssl_handshake", ret);
ccli8 25:edf568984d27 150 onError(_tcpsocket, ret);
ccli8 25:edf568984d27 151 return ret;
ccli8 25:edf568984d27 152 }
ccli8 25:edf568984d27 153
ccli8 25:edf568984d27 154 /* It also means the handshake is done, time to print info */
ccli8 25:edf568984d27 155 if (_debug) {
ccli8 25:edf568984d27 156 mbedtls_printf("TLS connection to %s:%d established\r\n", _hostname, _port);
ccli8 25:edf568984d27 157 }
ccli8 25:edf568984d27 158
ccli8 25:edf568984d27 159 const uint32_t buf_size = 1024;
ccli8 25:edf568984d27 160 char *buf = new char[buf_size];
ccli8 25:edf568984d27 161 mbedtls_x509_crt_info(buf, buf_size, "\r ", mbedtls_ssl_get_peer_cert(&_ssl));
ccli8 25:edf568984d27 162 if (_debug) {
ccli8 25:edf568984d27 163 mbedtls_printf("Server certificate:\r\n%s\r", buf);
ccli8 25:edf568984d27 164 }
ccli8 25:edf568984d27 165
ccli8 25:edf568984d27 166 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
ccli8 25:edf568984d27 167 if (flags != 0) {
ccli8 25:edf568984d27 168 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags);
ccli8 25:edf568984d27 169 if (_debug) {
ccli8 25:edf568984d27 170 mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf);
ccli8 25:edf568984d27 171 }
ccli8 25:edf568984d27 172 }
ccli8 25:edf568984d27 173 else {
ccli8 25:edf568984d27 174 if (_debug) mbedtls_printf("Certificate verification passed\r\n\r\n");
ccli8 25:edf568984d27 175 }
ccli8 25:edf568984d27 176 delete [] buf;
ccli8 25:edf568984d27 177 buf = NULL;
ccli8 25:edf568984d27 178
ccli8 25:edf568984d27 179 _is_connected = true;
ccli8 25:edf568984d27 180
ccli8 25:edf568984d27 181 return 0;
ccli8 25:edf568984d27 182 }
ccli8 25:edf568984d27 183
ccli8 25:edf568984d27 184 nsapi_size_or_error_t MyTLSSocket::send(const void *data, nsapi_size_t size)
ccli8 25:edf568984d27 185 {
ccli8 25:edf568984d27 186 return mbedtls_ssl_write(&_ssl, (const uint8_t *) data, size);
ccli8 25:edf568984d27 187 }
ccli8 25:edf568984d27 188
ccli8 25:edf568984d27 189 nsapi_size_or_error_t MyTLSSocket::recv(void *data, nsapi_size_t size)
ccli8 25:edf568984d27 190 {
ccli8 25:edf568984d27 191 return mbedtls_ssl_read(&_ssl, (uint8_t *) data, size);
ccli8 25:edf568984d27 192 }
ccli8 25:edf568984d27 193
ccli8 25:edf568984d27 194 void MyTLSSocket::set_blocking(bool blocking)
ccli8 25:edf568984d27 195 {
ccli8 25:edf568984d27 196 _tcpsocket->set_blocking(blocking);
ccli8 25:edf568984d27 197 }
ccli8 25:edf568984d27 198
ccli8 25:edf568984d27 199 void MyTLSSocket::set_timeout(int timeout)
ccli8 25:edf568984d27 200 {
ccli8 25:edf568984d27 201 _tcpsocket->set_timeout(timeout);
ccli8 25:edf568984d27 202 }
ccli8 25:edf568984d27 203
ccli8 25:edf568984d27 204 bool MyTLSSocket::connected()
ccli8 25:edf568984d27 205 {
ccli8 25:edf568984d27 206 return _is_connected;
ccli8 25:edf568984d27 207 }
ccli8 25:edf568984d27 208
ccli8 25:edf568984d27 209 nsapi_error_t MyTLSSocket::error()
ccli8 25:edf568984d27 210 {
ccli8 25:edf568984d27 211 return _error;
ccli8 25:edf568984d27 212 }
ccli8 25:edf568984d27 213
ccli8 25:edf568984d27 214 TCPSocket* MyTLSSocket::get_tcp_socket()
ccli8 25:edf568984d27 215 {
ccli8 25:edf568984d27 216 return _tcpsocket;
ccli8 25:edf568984d27 217 }
ccli8 25:edf568984d27 218
ccli8 25:edf568984d27 219 mbedtls_ssl_context *MyTLSSocket::get_ssl_context()
ccli8 25:edf568984d27 220 {
ccli8 25:edf568984d27 221 return &_ssl;
ccli8 25:edf568984d27 222 }
ccli8 25:edf568984d27 223
ccli8 25:edf568984d27 224 void MyTLSSocket::set_debug(bool debug)
ccli8 25:edf568984d27 225 {
ccli8 25:edf568984d27 226 _debug = debug;
ccli8 25:edf568984d27 227 }
ccli8 25:edf568984d27 228
ccli8 25:edf568984d27 229 int MyTLSSocket::read(unsigned char* buffer, int len, int timeout)
ccli8 25:edf568984d27 230 {
ccli8 25:edf568984d27 231 set_timeout(timeout);
ccli8 25:edf568984d27 232 int rc = recv(buffer, len);
ccli8 25:edf568984d27 233 return (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE) ? 0 : rc;
ccli8 25:edf568984d27 234 }
ccli8 25:edf568984d27 235
ccli8 25:edf568984d27 236 int MyTLSSocket::write(unsigned char* buffer, int len, int timeout)
ccli8 25:edf568984d27 237 {
ccli8 25:edf568984d27 238 set_timeout(timeout);
ccli8 25:edf568984d27 239 int rc = send(buffer, len);
ccli8 25:edf568984d27 240 return (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE) ? 0 : rc;
ccli8 25:edf568984d27 241 }
ccli8 25:edf568984d27 242
ccli8 25:edf568984d27 243 #if MBED_CONF_MY_TLSSOCKET_TLS_DEBUG_LEVEL > 0
ccli8 25:edf568984d27 244 void MyTLSSocket::my_debug(void *ctx, int level, const char *file, int line,
ccli8 25:edf568984d27 245 const char *str)
ccli8 25:edf568984d27 246 {
ccli8 25:edf568984d27 247 const char *p, *basename;
ccli8 25:edf568984d27 248 MyTLSSocket *tlssocket = static_cast<MyTLSSocket *>(ctx);
ccli8 25:edf568984d27 249
ccli8 25:edf568984d27 250 /* Extract basename from file */
ccli8 25:edf568984d27 251 for (p = basename = file; *p != '\0'; p++) {
ccli8 25:edf568984d27 252 if (*p == '/' || *p == '\\') {
ccli8 25:edf568984d27 253 basename = p + 1;
ccli8 25:edf568984d27 254 }
ccli8 25:edf568984d27 255 }
ccli8 25:edf568984d27 256
ccli8 25:edf568984d27 257 if (tlssocket->_debug) {
ccli8 25:edf568984d27 258 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
ccli8 25:edf568984d27 259 }
ccli8 25:edf568984d27 260 }
ccli8 25:edf568984d27 261
ccli8 25:edf568984d27 262 int MyTLSSocket::my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
ccli8 25:edf568984d27 263 {
ccli8 25:edf568984d27 264 const uint32_t buf_size = 1024;
ccli8 25:edf568984d27 265 char *buf = new char[buf_size];
ccli8 25:edf568984d27 266 MyTLSSocket *tlssocket = static_cast<MyTLSSocket *>(data);
ccli8 25:edf568984d27 267
ccli8 25:edf568984d27 268 if (tlssocket->_debug) {
ccli8 25:edf568984d27 269 mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
ccli8 25:edf568984d27 270 }
ccli8 25:edf568984d27 271 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
ccli8 25:edf568984d27 272 if (tlssocket->_debug) {
ccli8 25:edf568984d27 273 mbedtls_printf("%s", buf);
ccli8 25:edf568984d27 274 }
ccli8 25:edf568984d27 275
ccli8 25:edf568984d27 276 if (*flags == 0) {
ccli8 25:edf568984d27 277 if (tlssocket->_debug) {
ccli8 25:edf568984d27 278 mbedtls_printf("No verification issue for this certificate\n");
ccli8 25:edf568984d27 279 }
ccli8 25:edf568984d27 280 }
ccli8 25:edf568984d27 281 else {
ccli8 25:edf568984d27 282 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
ccli8 25:edf568984d27 283 if (tlssocket->_debug) mbedtls_printf("%s\n", buf);
ccli8 25:edf568984d27 284 }
ccli8 25:edf568984d27 285
ccli8 25:edf568984d27 286 delete[] buf;
ccli8 25:edf568984d27 287 return 0;
ccli8 25:edf568984d27 288 }
ccli8 25:edf568984d27 289 #endif
ccli8 25:edf568984d27 290
ccli8 25:edf568984d27 291 int MyTLSSocket::ssl_recv(void *ctx, unsigned char *buf, size_t len)
ccli8 25:edf568984d27 292 {
ccli8 25:edf568984d27 293 int recv = -1;
ccli8 25:edf568984d27 294 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
ccli8 25:edf568984d27 295 recv = socket->recv(buf, len);
ccli8 25:edf568984d27 296
ccli8 25:edf568984d27 297 if (NSAPI_ERROR_WOULD_BLOCK == recv) {
ccli8 25:edf568984d27 298 return MBEDTLS_ERR_SSL_WANT_READ;
ccli8 25:edf568984d27 299 }
ccli8 25:edf568984d27 300 else if (recv < 0) {
ccli8 25:edf568984d27 301 return -1;
ccli8 25:edf568984d27 302 }
ccli8 25:edf568984d27 303 else {
ccli8 25:edf568984d27 304 return recv;
ccli8 25:edf568984d27 305 }
ccli8 25:edf568984d27 306 }
ccli8 25:edf568984d27 307
ccli8 25:edf568984d27 308 int MyTLSSocket::ssl_send(void *ctx, const unsigned char *buf, size_t len)
ccli8 25:edf568984d27 309 {
ccli8 25:edf568984d27 310 int size = -1;
ccli8 25:edf568984d27 311 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
ccli8 25:edf568984d27 312 size = socket->send(buf, len);
ccli8 25:edf568984d27 313
ccli8 25:edf568984d27 314 if (NSAPI_ERROR_WOULD_BLOCK == size) {
ccli8 25:edf568984d27 315 return MBEDTLS_ERR_SSL_WANT_WRITE;
ccli8 25:edf568984d27 316 }
ccli8 25:edf568984d27 317 else if (size < 0) {
ccli8 25:edf568984d27 318 return -1;
ccli8 25:edf568984d27 319 }
ccli8 25:edf568984d27 320 else {
ccli8 25:edf568984d27 321 return size;
ccli8 25:edf568984d27 322 }
ccli8 25:edf568984d27 323 }
ccli8 25:edf568984d27 324
ccli8 25:edf568984d27 325 void MyTLSSocket::onError(TCPSocket *s, int error)
ccli8 25:edf568984d27 326 {
ccli8 25:edf568984d27 327 s->close();
ccli8 25:edf568984d27 328 _error = error;
ccli8 25:edf568984d27 329 }