HTTP and HTTPS library for Mbed OS 5

Dependents:   MQTTGateway2 MQTTGatewayK64 http-example-wnc GuardRoom ... more

For the example program, see: sandbox/http-example.

This library is used to make HTTP and HTTPS calls from Mbed OS 5 applications.

HTTP Request API

NetworkInterface* network = /* obtain a NetworkInterface object */

const char body[] = "{\"hello\":\"world\"}";

HttpRequest* request = new HttpRequest(network, HTTP_POST, "http://httpbin.org/post");
request->set_header("Content-Type", "application/json");
HttpResponse* response = request->send(body, strlen(body));
// if response is NULL, check response->get_error()

printf("status is %d - %s\n", response->get_status_code(), response->get_status_message());
printf("body is:\n%s\n", response->get_body_as_string().c_str());

delete request; // also clears out the response

HTTPS Request API

// pass in the root certificates that you trust, there is no central CA registry in Mbed OS
const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
    /* rest of the CA root certificates */;

NetworkInterface* network = /* obtain a NetworkInterface object */

const char body[] = "{\"hello\":\"world\"}";

HttpsRequest* request = new HttpsRequest(network, SSL_CA_PEM, HTTP_GET "https://httpbin.org/status/418");
HttpResponse* response = request->send();
// if response is NULL, check response->get_error()

printf("status is %d - %s\n", response->get_status_code(), response->get_status_message());
printf("body is:\n%s\n", response->get_body().c_str());

delete request;

Note: You can get the root CA for a domain easily from Firefox. Click on the green padlock, click More information > Security > View certificate > Details. Select the top entry in the 'Certificate Hierarchy' and click Export.... This gives you a PEM file. Add the content of the PEM file to your root CA list (here's an image).

Mbed TLS Entropy configuration

If your target does not have a built-in TRNG, or other entropy sources, add the following macros to your mbed_app.json file to disable entropy:

{
    "macros": [
        "MBEDTLS_TEST_NULL_ENTROPY",
        "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES"
    ]
}

Note that this is not secure, and you should not deploy this device into production with this configuration.

Memory usage

Small requests where the body of the response is cached by the library (like the one found in main-http.cpp), require 4K of RAM. When the request is finished they require 1.5K of RAM, depending on the size of the response. This applies both to HTTP and HTTPS. If you need to handle requests that return a large response body, see 'Dealing with large body'.

HTTPS requires additional memory: on FRDM-K64F about 50K of heap space (at its peak). This means that you cannot use HTTPS on devices with less than 128K of memory, asyou also need to reserve memory for the stack and network interface.

Dealing with large response body

By default the library will store the full request body on the heap. This works well for small responses, but you'll run out of memory when receiving a large response body. To mitigate this you can pass in a callback as the last argument to the request constructor. This callback will be called whenever a chunk of the body is received. You can set the request chunk size in the HTTP_RECEIVE_BUFFER_SIZE macro (see mbed_lib.json for the definition) although it also depends on the buffer size ofthe underlying network connection.

void body_callback(const char* data, uint32_t data_len) {
    // do something with the data
}

HttpRequest* req = new HttpRequest(network, HTTP_GET, "http://pathtolargefile.com", &body_callback);
req->send(NULL, 0);

Dealing with a large request body

If you cannot load the full request into memory, you can pass a callback into the send function. Through this callback you can feed in chunks of the request body. This is very useful if you want to send files from a file system.

const void * get_chunk(uint32_t* out_size) {
    // set the value of out_size (via *out_size = 10) to the size of the buffer
    // return the buffer

    // if you don't have any more data, set *out_size to 0
}

HttpRequest* req = new HttpRequest(network, HTTP_POST, "http://my_api.com/upload");
req->send(callback(&get_chunk));

Socket re-use

By default the library opens a new socket per request. This is wasteful, especially when dealing with TLS requests. You can re-use sockets like this:

HTTP

TCPSocket* socket = new TCPSocket();

nsapi_error_t open_result = socket->open(network);
// check open_result

nsapi_error_t connect_result = socket->connect("httpbin.org", 80);
// check connect_result

// Pass in `socket`, instead of `network` as first argument
HttpRequest* req = new HttpRequest(socket, HTTP_GET, "http://httpbin.org/status/418");

HTTPS

TLSSocket* socket = new TLSSocket();

nsapi_error_t r;
// make sure to check the return values for the calls below (should return NSAPI_ERROR_OK)
r = socket->open(network);
r = socket->set_root_ca_cert(SSL_CA_PEM);
r = socket->connect("httpbin.org", 443);

// Pass in `socket`, instead of `network` as first argument, and omit the `SSL_CA_PEM` argument
HttpsRequest* get_req = new HttpsRequest(socket, HTTP_GET, "https://httpbin.org/status/418");

Request logging

To make debugging easier you can log the raw request body that goes over the line. This also works with chunked encoding.

uint8_t *request_buffer = (uint8_t*)calloc(2048, 1);
req->set_request_log_buffer(request_buffer, 2048);

// after the request is done:
printf("\n----- Request buffer -----\n");
for (size_t ix = 0; ix < req->get_request_log_buffer_length(); ix++) {
    printf("%02x ", request_buffer[ix]);
}
printf("\n");

Integration tests

Integration tests are located in the TESTS folder and are ran through Greentea. Instructions on how to run the tests are in http-example.

Mbed OS 5.10 or lower

If you want to use this library on Mbed OS 5.10 or lower, you need to add the TLSSocket library to your project. This library is included in Mbed OS 5.11 and up.

Tested on

  • K64F with Ethernet.
  • NUCLEO_F411RE with ESP8266.
  • ODIN-W2 with WiFi.
  • K64F with Atmel 6LoWPAN shield.
  • DISCO-L475VG-IOT01A with WiFi.
  • Mbed Simulator.
Committer:
Jan Jongboom
Date:
Mon Sep 04 16:31:38 2017 +0100
Revision:
18:f7a85895a941
Parent:
15:ffc77f212382
Child:
27:42b319540a74
tls_socket was leaking 1024 bytes of memory

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jan Jongboom 13:992d953ecfb9 1 /*
Jan Jongboom 13:992d953ecfb9 2 * PackageLicenseDeclared: Apache-2.0
Jan Jongboom 13:992d953ecfb9 3 * Copyright (c) 2017 ARM Limited
Jan Jongboom 13:992d953ecfb9 4 *
Jan Jongboom 13:992d953ecfb9 5 * Licensed under the Apache License, Version 2.0 (the "License");
Jan Jongboom 13:992d953ecfb9 6 * you may not use this file except in compliance with the License.
Jan Jongboom 13:992d953ecfb9 7 * You may obtain a copy of the License at
Jan Jongboom 13:992d953ecfb9 8 *
Jan Jongboom 13:992d953ecfb9 9 * http://www.apache.org/licenses/LICENSE-2.0
Jan Jongboom 13:992d953ecfb9 10 *
Jan Jongboom 13:992d953ecfb9 11 * Unless required by applicable law or agreed to in writing, software
Jan Jongboom 13:992d953ecfb9 12 * distributed under the License is distributed on an "AS IS" BASIS,
Jan Jongboom 13:992d953ecfb9 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Jan Jongboom 13:992d953ecfb9 14 * See the License for the specific language governing permissions and
Jan Jongboom 13:992d953ecfb9 15 * limitations under the License.
Jan Jongboom 13:992d953ecfb9 16 */
Jan Jongboom 13:992d953ecfb9 17
Jan Jongboom 13:992d953ecfb9 18 #ifndef _MBED_HTTPS_TLS_SOCKET_H_
Jan Jongboom 13:992d953ecfb9 19 #define _MBED_HTTPS_TLS_SOCKET_H_
Jan Jongboom 13:992d953ecfb9 20
Jan Jongboom 13:992d953ecfb9 21 /* Change to a number between 1 and 4 to debug the TLS connection */
Jan Jongboom 13:992d953ecfb9 22 #define DEBUG_LEVEL 0
Jan Jongboom 13:992d953ecfb9 23
Jan Jongboom 13:992d953ecfb9 24 #include <string>
Jan Jongboom 13:992d953ecfb9 25 #include <vector>
Jan Jongboom 13:992d953ecfb9 26 #include <map>
Jan Jongboom 13:992d953ecfb9 27 #include "http_parser.h"
Jan Jongboom 13:992d953ecfb9 28 #include "http_response.h"
Jan Jongboom 13:992d953ecfb9 29 #include "http_request_builder.h"
Jan Jongboom 15:ffc77f212382 30 #include "http_request_parser.h"
Jan Jongboom 13:992d953ecfb9 31 #include "http_parsed_url.h"
Jan Jongboom 13:992d953ecfb9 32
Jan Jongboom 13:992d953ecfb9 33 #include "mbedtls/platform.h"
Jan Jongboom 13:992d953ecfb9 34 #include "mbedtls/ssl.h"
Jan Jongboom 13:992d953ecfb9 35 #include "mbedtls/entropy.h"
Jan Jongboom 13:992d953ecfb9 36 #include "mbedtls/ctr_drbg.h"
Jan Jongboom 13:992d953ecfb9 37 #include "mbedtls/error.h"
Jan Jongboom 13:992d953ecfb9 38
Jan Jongboom 13:992d953ecfb9 39 #if DEBUG_LEVEL > 0
Jan Jongboom 13:992d953ecfb9 40 #include "mbedtls/debug.h"
Jan Jongboom 13:992d953ecfb9 41 #endif
Jan Jongboom 13:992d953ecfb9 42
Jan Jongboom 13:992d953ecfb9 43 /**
Jan Jongboom 13:992d953ecfb9 44 * \brief TLSSocket a wrapper around TCPSocket for interacting with TLS servers
Jan Jongboom 13:992d953ecfb9 45 */
Jan Jongboom 13:992d953ecfb9 46 class TLSSocket {
Jan Jongboom 13:992d953ecfb9 47 public:
Jan Jongboom 13:992d953ecfb9 48 TLSSocket(NetworkInterface* net_iface, const char* hostname, uint16_t port, const char* ssl_ca_pem) {
Jan Jongboom 13:992d953ecfb9 49 _tcpsocket = new TCPSocket(net_iface);
Jan Jongboom 13:992d953ecfb9 50 _ssl_ca_pem = ssl_ca_pem;
Jan Jongboom 13:992d953ecfb9 51 _is_connected = false;
Jan Jongboom 13:992d953ecfb9 52 _debug = false;
Jan Jongboom 13:992d953ecfb9 53 _hostname = hostname;
Jan Jongboom 13:992d953ecfb9 54 _port = port;
Jan Jongboom 13:992d953ecfb9 55 _error = 0;
Jan Jongboom 13:992d953ecfb9 56
Jan Jongboom 13:992d953ecfb9 57 DRBG_PERS = "mbed TLS helloword client";
Jan Jongboom 13:992d953ecfb9 58
Jan Jongboom 13:992d953ecfb9 59 mbedtls_entropy_init(&_entropy);
Jan Jongboom 13:992d953ecfb9 60 mbedtls_ctr_drbg_init(&_ctr_drbg);
Jan Jongboom 13:992d953ecfb9 61 mbedtls_x509_crt_init(&_cacert);
Jan Jongboom 13:992d953ecfb9 62 mbedtls_ssl_init(&_ssl);
Jan Jongboom 13:992d953ecfb9 63 mbedtls_ssl_config_init(&_ssl_conf);
Jan Jongboom 13:992d953ecfb9 64 }
Jan Jongboom 13:992d953ecfb9 65
Jan Jongboom 13:992d953ecfb9 66 ~TLSSocket() {
Jan Jongboom 13:992d953ecfb9 67 mbedtls_entropy_free(&_entropy);
Jan Jongboom 13:992d953ecfb9 68 mbedtls_ctr_drbg_free(&_ctr_drbg);
Jan Jongboom 13:992d953ecfb9 69 mbedtls_x509_crt_free(&_cacert);
Jan Jongboom 13:992d953ecfb9 70 mbedtls_ssl_free(&_ssl);
Jan Jongboom 13:992d953ecfb9 71 mbedtls_ssl_config_free(&_ssl_conf);
Jan Jongboom 13:992d953ecfb9 72
Jan Jongboom 13:992d953ecfb9 73 if (_tcpsocket) {
Jan Jongboom 13:992d953ecfb9 74 _tcpsocket->close();
Jan Jongboom 13:992d953ecfb9 75 delete _tcpsocket;
Jan Jongboom 13:992d953ecfb9 76 }
Jan Jongboom 13:992d953ecfb9 77
Jan Jongboom 13:992d953ecfb9 78 // @todo: free DRBG_PERS ?
Jan Jongboom 13:992d953ecfb9 79 }
Jan Jongboom 13:992d953ecfb9 80
Jan Jongboom 13:992d953ecfb9 81 nsapi_error_t connect() {
Jan Jongboom 13:992d953ecfb9 82 /* Initialize the flags */
Jan Jongboom 13:992d953ecfb9 83 /*
Jan Jongboom 13:992d953ecfb9 84 * Initialize TLS-related stuf.
Jan Jongboom 13:992d953ecfb9 85 */
Jan Jongboom 13:992d953ecfb9 86 int ret;
Jan Jongboom 13:992d953ecfb9 87 if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
Jan Jongboom 13:992d953ecfb9 88 (const unsigned char *) DRBG_PERS,
Jan Jongboom 13:992d953ecfb9 89 sizeof (DRBG_PERS))) != 0) {
Jan Jongboom 13:992d953ecfb9 90 print_mbedtls_error("mbedtls_crt_drbg_init", ret);
Jan Jongboom 13:992d953ecfb9 91 _error = ret;
Jan Jongboom 13:992d953ecfb9 92 return _error;
Jan Jongboom 13:992d953ecfb9 93 }
Jan Jongboom 13:992d953ecfb9 94
Jan Jongboom 13:992d953ecfb9 95 if ((ret = mbedtls_x509_crt_parse(&_cacert, (const unsigned char *)_ssl_ca_pem,
Jan Jongboom 13:992d953ecfb9 96 strlen(_ssl_ca_pem) + 1)) != 0) {
Jan Jongboom 13:992d953ecfb9 97 print_mbedtls_error("mbedtls_x509_crt_parse", ret);
Jan Jongboom 13:992d953ecfb9 98 _error = ret;
Jan Jongboom 13:992d953ecfb9 99 return _error;
Jan Jongboom 13:992d953ecfb9 100 }
Jan Jongboom 13:992d953ecfb9 101
Jan Jongboom 13:992d953ecfb9 102 if ((ret = mbedtls_ssl_config_defaults(&_ssl_conf,
Jan Jongboom 13:992d953ecfb9 103 MBEDTLS_SSL_IS_CLIENT,
Jan Jongboom 13:992d953ecfb9 104 MBEDTLS_SSL_TRANSPORT_STREAM,
Jan Jongboom 13:992d953ecfb9 105 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
Jan Jongboom 13:992d953ecfb9 106 print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
Jan Jongboom 13:992d953ecfb9 107 _error = ret;
Jan Jongboom 13:992d953ecfb9 108 return _error;
Jan Jongboom 13:992d953ecfb9 109 }
Jan Jongboom 13:992d953ecfb9 110
Jan Jongboom 13:992d953ecfb9 111 mbedtls_ssl_conf_ca_chain(&_ssl_conf, &_cacert, NULL);
Jan Jongboom 13:992d953ecfb9 112 mbedtls_ssl_conf_rng(&_ssl_conf, mbedtls_ctr_drbg_random, &_ctr_drbg);
Jan Jongboom 13:992d953ecfb9 113
Jan Jongboom 13:992d953ecfb9 114 /* It is possible to disable authentication by passing
Jan Jongboom 13:992d953ecfb9 115 * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
Jan Jongboom 13:992d953ecfb9 116 */
Jan Jongboom 13:992d953ecfb9 117 mbedtls_ssl_conf_authmode(&_ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED);
Jan Jongboom 13:992d953ecfb9 118
Jan Jongboom 13:992d953ecfb9 119 #if DEBUG_LEVEL > 0
Jan Jongboom 13:992d953ecfb9 120 mbedtls_ssl_conf_verify(&_ssl_conf, my_verify, NULL);
Jan Jongboom 13:992d953ecfb9 121 mbedtls_ssl_conf_dbg(&_ssl_conf, my_debug, NULL);
Jan Jongboom 13:992d953ecfb9 122 mbedtls_debug_set_threshold(DEBUG_LEVEL);
Jan Jongboom 13:992d953ecfb9 123 #endif
Jan Jongboom 13:992d953ecfb9 124
Jan Jongboom 13:992d953ecfb9 125 if ((ret = mbedtls_ssl_setup(&_ssl, &_ssl_conf)) != 0) {
Jan Jongboom 13:992d953ecfb9 126 print_mbedtls_error("mbedtls_ssl_setup", ret);
Jan Jongboom 13:992d953ecfb9 127 _error = ret;
Jan Jongboom 13:992d953ecfb9 128 return _error;
Jan Jongboom 13:992d953ecfb9 129 }
Jan Jongboom 13:992d953ecfb9 130
Jan Jongboom 13:992d953ecfb9 131 mbedtls_ssl_set_hostname(&_ssl, _hostname);
Jan Jongboom 13:992d953ecfb9 132
Jan Jongboom 13:992d953ecfb9 133 mbedtls_ssl_set_bio(&_ssl, static_cast<void *>(_tcpsocket),
Jan Jongboom 13:992d953ecfb9 134 ssl_send, ssl_recv, NULL );
Jan Jongboom 13:992d953ecfb9 135
Jan Jongboom 13:992d953ecfb9 136 /* Connect to the server */
Jan Jongboom 13:992d953ecfb9 137 if (_debug) mbedtls_printf("Connecting to %s:%d\r\n", _hostname, _port);
Jan Jongboom 13:992d953ecfb9 138 ret = _tcpsocket->connect(_hostname, _port);
Jan Jongboom 13:992d953ecfb9 139 if (ret != NSAPI_ERROR_OK) {
Jan Jongboom 13:992d953ecfb9 140 if (_debug) mbedtls_printf("Failed to connect\r\n");
Jan Jongboom 13:992d953ecfb9 141 onError(_tcpsocket, -1);
Jan Jongboom 13:992d953ecfb9 142 return _error;
Jan Jongboom 13:992d953ecfb9 143 }
Jan Jongboom 13:992d953ecfb9 144
Jan Jongboom 13:992d953ecfb9 145 /* Start the handshake, the rest will be done in onReceive() */
Jan Jongboom 13:992d953ecfb9 146 if (_debug) mbedtls_printf("Starting the TLS handshake...\r\n");
Jan Jongboom 13:992d953ecfb9 147 ret = mbedtls_ssl_handshake(&_ssl);
Jan Jongboom 13:992d953ecfb9 148 if (ret < 0) {
Jan Jongboom 13:992d953ecfb9 149 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
Jan Jongboom 13:992d953ecfb9 150 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
Jan Jongboom 13:992d953ecfb9 151 print_mbedtls_error("mbedtls_ssl_handshake", ret);
Jan Jongboom 13:992d953ecfb9 152 onError(_tcpsocket, -1);
Jan Jongboom 13:992d953ecfb9 153 }
Jan Jongboom 13:992d953ecfb9 154 else {
Jan Jongboom 13:992d953ecfb9 155 _error = ret;
Jan Jongboom 13:992d953ecfb9 156 }
Jan Jongboom 13:992d953ecfb9 157 return _error;
Jan Jongboom 13:992d953ecfb9 158 }
Jan Jongboom 13:992d953ecfb9 159
Jan Jongboom 13:992d953ecfb9 160 /* It also means the handshake is done, time to print info */
Jan Jongboom 13:992d953ecfb9 161 if (_debug) mbedtls_printf("TLS connection to %s:%d established\r\n", _hostname, _port);
Jan Jongboom 13:992d953ecfb9 162
Jan Jongboom 13:992d953ecfb9 163 const uint32_t buf_size = 1024;
Jan Jongboom 18:f7a85895a941 164 char buf[buf_size] = { 0 };
Jan Jongboom 13:992d953ecfb9 165 mbedtls_x509_crt_info(buf, buf_size, "\r ",
Jan Jongboom 13:992d953ecfb9 166 mbedtls_ssl_get_peer_cert(&_ssl));
Jan Jongboom 13:992d953ecfb9 167 if (_debug) mbedtls_printf("Server certificate:\r\n%s\r", buf);
Jan Jongboom 13:992d953ecfb9 168
Jan Jongboom 13:992d953ecfb9 169 uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
Jan Jongboom 13:992d953ecfb9 170 if( flags != 0 )
Jan Jongboom 13:992d953ecfb9 171 {
Jan Jongboom 13:992d953ecfb9 172 mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags);
Jan Jongboom 13:992d953ecfb9 173 if (_debug) mbedtls_printf("Certificate verification failed:\r\n%s\r\r\n", buf);
Jan Jongboom 13:992d953ecfb9 174 }
Jan Jongboom 13:992d953ecfb9 175 else {
Jan Jongboom 13:992d953ecfb9 176 if (_debug) mbedtls_printf("Certificate verification passed\r\n\r\n");
Jan Jongboom 13:992d953ecfb9 177 }
Jan Jongboom 13:992d953ecfb9 178
Jan Jongboom 13:992d953ecfb9 179 _is_connected = true;
Jan Jongboom 13:992d953ecfb9 180
Jan Jongboom 13:992d953ecfb9 181 return 0;
Jan Jongboom 13:992d953ecfb9 182 }
Jan Jongboom 13:992d953ecfb9 183
Jan Jongboom 13:992d953ecfb9 184 bool connected() {
Jan Jongboom 13:992d953ecfb9 185 return _is_connected;
Jan Jongboom 13:992d953ecfb9 186 }
Jan Jongboom 13:992d953ecfb9 187
Jan Jongboom 13:992d953ecfb9 188 nsapi_error_t error() {
Jan Jongboom 13:992d953ecfb9 189 return _error;
Jan Jongboom 13:992d953ecfb9 190 }
Jan Jongboom 13:992d953ecfb9 191
Jan Jongboom 13:992d953ecfb9 192 TCPSocket* get_tcp_socket() {
Jan Jongboom 13:992d953ecfb9 193 return _tcpsocket;
Jan Jongboom 13:992d953ecfb9 194 }
Jan Jongboom 13:992d953ecfb9 195
Jan Jongboom 13:992d953ecfb9 196 mbedtls_ssl_context* get_ssl_context() {
Jan Jongboom 13:992d953ecfb9 197 return &_ssl;
Jan Jongboom 13:992d953ecfb9 198 }
Jan Jongboom 13:992d953ecfb9 199
Jan Jongboom 13:992d953ecfb9 200 /**
Jan Jongboom 13:992d953ecfb9 201 * Set the debug flag.
Jan Jongboom 13:992d953ecfb9 202 *
Jan Jongboom 13:992d953ecfb9 203 * If this flag is set, debug information from mbed TLS will be logged to stdout.
Jan Jongboom 13:992d953ecfb9 204 */
Jan Jongboom 13:992d953ecfb9 205 void set_debug(bool debug) {
Jan Jongboom 13:992d953ecfb9 206 _debug = debug;
Jan Jongboom 13:992d953ecfb9 207 }
Jan Jongboom 13:992d953ecfb9 208
Jan Jongboom 13:992d953ecfb9 209 protected:
Jan Jongboom 13:992d953ecfb9 210 /**
Jan Jongboom 13:992d953ecfb9 211 * Helper for pretty-printing mbed TLS error codes
Jan Jongboom 13:992d953ecfb9 212 */
Jan Jongboom 13:992d953ecfb9 213 static void print_mbedtls_error(const char *name, int err) {
Jan Jongboom 13:992d953ecfb9 214 char buf[128];
Jan Jongboom 13:992d953ecfb9 215 mbedtls_strerror(err, buf, sizeof (buf));
Jan Jongboom 13:992d953ecfb9 216 mbedtls_printf("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf);
Jan Jongboom 13:992d953ecfb9 217 }
Jan Jongboom 13:992d953ecfb9 218
Jan Jongboom 13:992d953ecfb9 219 #if DEBUG_LEVEL > 0
Jan Jongboom 13:992d953ecfb9 220 /**
Jan Jongboom 13:992d953ecfb9 221 * Debug callback for mbed TLS
Jan Jongboom 13:992d953ecfb9 222 * Just prints on the USB serial port
Jan Jongboom 13:992d953ecfb9 223 */
Jan Jongboom 13:992d953ecfb9 224 static void my_debug(void *ctx, int level, const char *file, int line,
Jan Jongboom 13:992d953ecfb9 225 const char *str)
Jan Jongboom 13:992d953ecfb9 226 {
Jan Jongboom 13:992d953ecfb9 227 const char *p, *basename;
Jan Jongboom 13:992d953ecfb9 228 (void) ctx;
Jan Jongboom 13:992d953ecfb9 229
Jan Jongboom 13:992d953ecfb9 230 /* Extract basename from file */
Jan Jongboom 13:992d953ecfb9 231 for(p = basename = file; *p != '\0'; p++) {
Jan Jongboom 13:992d953ecfb9 232 if(*p == '/' || *p == '\\') {
Jan Jongboom 13:992d953ecfb9 233 basename = p + 1;
Jan Jongboom 13:992d953ecfb9 234 }
Jan Jongboom 13:992d953ecfb9 235 }
Jan Jongboom 13:992d953ecfb9 236
Jan Jongboom 13:992d953ecfb9 237 if (_debug) {
Jan Jongboom 13:992d953ecfb9 238 mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
Jan Jongboom 13:992d953ecfb9 239 }
Jan Jongboom 13:992d953ecfb9 240 }
Jan Jongboom 13:992d953ecfb9 241
Jan Jongboom 13:992d953ecfb9 242 /**
Jan Jongboom 13:992d953ecfb9 243 * Certificate verification callback for mbed TLS
Jan Jongboom 13:992d953ecfb9 244 * Here we only use it to display information on each cert in the chain
Jan Jongboom 13:992d953ecfb9 245 */
Jan Jongboom 13:992d953ecfb9 246 static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
Jan Jongboom 13:992d953ecfb9 247 {
Jan Jongboom 13:992d953ecfb9 248 const uint32_t buf_size = 1024;
Jan Jongboom 13:992d953ecfb9 249 char *buf = new char[buf_size];
Jan Jongboom 13:992d953ecfb9 250 (void) data;
Jan Jongboom 13:992d953ecfb9 251
Jan Jongboom 13:992d953ecfb9 252 if (_debug) mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
Jan Jongboom 13:992d953ecfb9 253 mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
Jan Jongboom 13:992d953ecfb9 254 if (_debug) mbedtls_printf("%s", buf);
Jan Jongboom 13:992d953ecfb9 255
Jan Jongboom 13:992d953ecfb9 256 if (*flags == 0)
Jan Jongboom 13:992d953ecfb9 257 if (_debug) mbedtls_printf("No verification issue for this certificate\n");
Jan Jongboom 13:992d953ecfb9 258 else
Jan Jongboom 13:992d953ecfb9 259 {
Jan Jongboom 13:992d953ecfb9 260 mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
Jan Jongboom 13:992d953ecfb9 261 if (_debug) mbedtls_printf("%s\n", buf);
Jan Jongboom 13:992d953ecfb9 262 }
Jan Jongboom 13:992d953ecfb9 263
Jan Jongboom 13:992d953ecfb9 264 delete[] buf;
Jan Jongboom 13:992d953ecfb9 265 return 0;
Jan Jongboom 13:992d953ecfb9 266 }
Jan Jongboom 13:992d953ecfb9 267 #endif
Jan Jongboom 13:992d953ecfb9 268
Jan Jongboom 13:992d953ecfb9 269 /**
Jan Jongboom 13:992d953ecfb9 270 * Receive callback for mbed TLS
Jan Jongboom 13:992d953ecfb9 271 */
Jan Jongboom 13:992d953ecfb9 272 static int ssl_recv(void *ctx, unsigned char *buf, size_t len) {
Jan Jongboom 13:992d953ecfb9 273 int recv = -1;
Jan Jongboom 13:992d953ecfb9 274 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Jan Jongboom 13:992d953ecfb9 275 recv = socket->recv(buf, len);
Jan Jongboom 13:992d953ecfb9 276
Jan Jongboom 13:992d953ecfb9 277 if (NSAPI_ERROR_WOULD_BLOCK == recv) {
Jan Jongboom 13:992d953ecfb9 278 return MBEDTLS_ERR_SSL_WANT_READ;
Jan Jongboom 13:992d953ecfb9 279 }
Jan Jongboom 13:992d953ecfb9 280 else if (recv < 0) {
Jan Jongboom 13:992d953ecfb9 281 return -1;
Jan Jongboom 13:992d953ecfb9 282 }
Jan Jongboom 13:992d953ecfb9 283 else {
Jan Jongboom 13:992d953ecfb9 284 return recv;
Jan Jongboom 13:992d953ecfb9 285 }
Jan Jongboom 13:992d953ecfb9 286 }
Jan Jongboom 13:992d953ecfb9 287
Jan Jongboom 13:992d953ecfb9 288 /**
Jan Jongboom 13:992d953ecfb9 289 * Send callback for mbed TLS
Jan Jongboom 13:992d953ecfb9 290 */
Jan Jongboom 13:992d953ecfb9 291 static int ssl_send(void *ctx, const unsigned char *buf, size_t len) {
Jan Jongboom 13:992d953ecfb9 292 int size = -1;
Jan Jongboom 13:992d953ecfb9 293 TCPSocket *socket = static_cast<TCPSocket *>(ctx);
Jan Jongboom 13:992d953ecfb9 294 size = socket->send(buf, len);
Jan Jongboom 13:992d953ecfb9 295
Jan Jongboom 13:992d953ecfb9 296 if(NSAPI_ERROR_WOULD_BLOCK == size) {
Jan Jongboom 13:992d953ecfb9 297 return len;
Jan Jongboom 13:992d953ecfb9 298 }
Jan Jongboom 13:992d953ecfb9 299 else if (size < 0){
Jan Jongboom 13:992d953ecfb9 300 return -1;
Jan Jongboom 13:992d953ecfb9 301 }
Jan Jongboom 13:992d953ecfb9 302 else {
Jan Jongboom 13:992d953ecfb9 303 return size;
Jan Jongboom 13:992d953ecfb9 304 }
Jan Jongboom 13:992d953ecfb9 305 }
Jan Jongboom 13:992d953ecfb9 306
Jan Jongboom 13:992d953ecfb9 307 private:
Jan Jongboom 13:992d953ecfb9 308 void onError(TCPSocket *s, int error) {
Jan Jongboom 13:992d953ecfb9 309 s->close();
Jan Jongboom 13:992d953ecfb9 310 _error = error;
Jan Jongboom 13:992d953ecfb9 311 }
Jan Jongboom 13:992d953ecfb9 312
Jan Jongboom 13:992d953ecfb9 313 TCPSocket* _tcpsocket;
Jan Jongboom 13:992d953ecfb9 314
Jan Jongboom 13:992d953ecfb9 315 const char* DRBG_PERS;
Jan Jongboom 13:992d953ecfb9 316 const char* _ssl_ca_pem;
Jan Jongboom 13:992d953ecfb9 317 const char* _hostname;
Jan Jongboom 13:992d953ecfb9 318 uint16_t _port;
Jan Jongboom 13:992d953ecfb9 319
Jan Jongboom 13:992d953ecfb9 320 bool _debug;
Jan Jongboom 13:992d953ecfb9 321 bool _is_connected;
Jan Jongboom 13:992d953ecfb9 322
Jan Jongboom 13:992d953ecfb9 323 nsapi_error_t _error;
Jan Jongboom 13:992d953ecfb9 324
Jan Jongboom 13:992d953ecfb9 325 mbedtls_entropy_context _entropy;
Jan Jongboom 13:992d953ecfb9 326 mbedtls_ctr_drbg_context _ctr_drbg;
Jan Jongboom 13:992d953ecfb9 327 mbedtls_x509_crt _cacert;
Jan Jongboom 13:992d953ecfb9 328 mbedtls_ssl_context _ssl;
Jan Jongboom 13:992d953ecfb9 329 mbedtls_ssl_config _ssl_conf;
Jan Jongboom 13:992d953ecfb9 330 };
Jan Jongboom 13:992d953ecfb9 331
Jan Jongboom 13:992d953ecfb9 332 #endif // _MBED_HTTPS_TLS_SOCKET_H_