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:
Tue Mar 27 11:05:43 2018 +0200
Revision:
27:42b319540a74
Parent:
18:f7a85895a941
Reference TCPSocket in tls_socket

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