Offloaded TLSSocket for BG96

Some external modems have an internal TLSSocket implementation which can be used
instead of mbedtls based TLSSocket. Using offloaded TLSSocket can result in
significantly reduced ROM usage.

Offloaded TLSSocket can be enabled by enabling "nsapi.offload-tlssocket" and the used
network stack (e.g. cellular modem's CellularStack class) must support the setsockopt's
defined in nsapi_types.h.

Compared to original mbedtls based TLSSocket, offloaded TLSSocket brings in one significant
API limitation. Offloaded TLSSocket requires setting of certificates and keys after open()
and before connect() calls, where mbedtls based TLSSocket allows setting these before open()
call.
pull/11357/head
Kimmo Vaisanen 2019-08-26 12:54:20 +03:00
parent d91ed5fa42
commit b319be14e8
7 changed files with 410 additions and 38 deletions

View File

@ -102,6 +102,7 @@ protected:
started(false),
tx_ready(false),
rx_avail(false),
tls_socket(false),
pending_bytes(0)
{
}
@ -119,6 +120,7 @@ protected:
bool started; // socket has been opened on modem stack
bool tx_ready; // socket is ready for sending on modem stack
bool rx_avail; // socket has data for reading on modem stack
bool tls_socket; // socket uses modem's internal TLS socket functionality
nsapi_size_t pending_bytes; // The number of received bytes pending
};

View File

@ -18,6 +18,15 @@
#include <string.h>
#include "QUECTEL/BG96/QUECTEL_BG96_CellularStack.h"
#include "CellularLog.h"
#include "netsocket/TLSSocket.h"
// Ref: Quectel_BG96_SSL_AT_Commands_Manual, ch 2.1.1 AT+QSSLCFG
static const int BG96_SUPPORTED_SSL_VERSION = 4; // All
static const char BG96_SUPPORTED_CIPHER_SUITE[] = "0xFFFF"; // Support all
// TODO: At the moment we support only one active SSL context
// Later can be expanded to support multiple contexts. Modem supports IDs 0-5.
static const int sslctxID = 0;
using namespace mbed;
@ -25,12 +34,27 @@ QUECTEL_BG96_CellularStack::QUECTEL_BG96_CellularStack(ATHandler &atHandler, int
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
, _dns_callback(NULL), _dns_version(NSAPI_UNSPEC)
#endif
, _tls_sec_level(0)
{
_at.set_urc_handler("+QIURC: \"recv", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_recv));
_at.set_urc_handler("+QIURC: \"close", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_closed));
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
_at.set_urc_handler("+QIURC: \"dnsgip\",", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_dnsgip));
#endif
_at.set_urc_handler("+QSSLURC: \"recv", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_recv));
_at.set_urc_handler("+QSSLURC: \"close", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_closed));
// TODO: this needs to be handled properly, but now making just a quick hack
// Close all SSL sockets if open. This can happen for example if application processor
// was reset but modem not. Old sockets are still up and running and it prevents
// new SSL configurations and creating new sockets.
for (int i = 0; i < 12; i++) {
_at.clear_error();
tr_debug("Closing SSL socket %d...", i);
_at.at_cmd_discard("+QSSLCLOSE", "=", "%d", i);
}
_at.clear_error();
}
QUECTEL_BG96_CellularStack::~QUECTEL_BG96_CellularStack()
@ -52,7 +76,7 @@ nsapi_error_t QUECTEL_BG96_CellularStack::socket_connect(nsapi_socket_t handle,
CellularSocket *socket = (CellularSocket *)handle;
int modem_connect_id = -1;
int err = -1;
int err = NSAPI_ERROR_NO_CONNECTION;
int request_connect_id = find_socket_index(socket);
// assert here as its a programming error if the socket container doesn't contain
@ -61,12 +85,15 @@ nsapi_error_t QUECTEL_BG96_CellularStack::socket_connect(nsapi_socket_t handle,
_at.lock();
if (socket->proto == NSAPI_TCP) {
char ipdot[NSAPI_IP_SIZE];
ip2dot(address, ipdot);
_at.at_cmd_discard("+QIOPEN", "=", "%d%d%s%s%d%d%d", _cid, request_connect_id, "TCP",
ipdot, address.get_port(), socket->localAddress.get_port(), 0);
if (socket->tls_socket) {
if (_tls_sec_level == 0) {
_at.unlock();
return NSAPI_ERROR_AUTH_FAILURE;
}
handle_open_socket_response(modem_connect_id, err);
_at.at_cmd_discard("+QSSLOPEN", "=", "%d%d%d%s%d%d", _cid, sslctxID, request_connect_id,
address.get_ip_address(), address.get_port(), 0);
handle_open_socket_response(modem_connect_id, err, true);
if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) {
if (err == BG96_SOCKET_BIND_FAIL) {
@ -74,12 +101,33 @@ nsapi_error_t QUECTEL_BG96_CellularStack::socket_connect(nsapi_socket_t handle,
_at.unlock();
return NSAPI_ERROR_PARAMETER;
}
_at.at_cmd_discard("+QICLOSE", "=", "%d", modem_connect_id);
socket_close_impl(modem_connect_id);
_at.at_cmd_discard("+QSSLOPEN", "=", "%d%d%d%s%d%d", _cid, sslctxID, request_connect_id,
address.get_ip_address(), address.get_port(), 0);
handle_open_socket_response(modem_connect_id, err, true);
}
} else {
char ipdot[NSAPI_IP_SIZE];
ip2dot(address, ipdot);
_at.at_cmd_discard("+QIOPEN", "=", "%d%d%s%s%d%d%d", _cid, request_connect_id, "TCP",
ipdot, address.get_port(), socket->localAddress.get_port(), 0);
handle_open_socket_response(modem_connect_id, err, false);
if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) {
if (err == BG96_SOCKET_BIND_FAIL) {
socket->id = -1;
_at.unlock();
return NSAPI_ERROR_PARAMETER;
}
socket_close_impl(modem_connect_id);
_at.at_cmd_discard("+QIOPEN", "=", "%d%d%s%s%d%d%d", _cid, request_connect_id, "TCP",
ipdot, address.get_port(), socket->localAddress.get_port(), 0);
handle_open_socket_response(modem_connect_id, err);
handle_open_socket_response(modem_connect_id, err, false);
}
}
}
@ -91,14 +139,14 @@ nsapi_error_t QUECTEL_BG96_CellularStack::socket_connect(nsapi_socket_t handle,
nsapi_error_t ret_val = _at.get_last_error();
_at.unlock();
if ((ret_val == NSAPI_ERROR_OK) && (modem_connect_id == request_connect_id)) {
if ((!err) && (ret_val == NSAPI_ERROR_OK) && (modem_connect_id == request_connect_id)) {
socket->id = request_connect_id;
socket->remoteAddress = address;
socket->connected = true;
return NSAPI_ERROR_OK;
}
return NSAPI_ERROR_NO_CONNECTION;
return err;
}
void QUECTEL_BG96_CellularStack::urc_qiurc_recv()
@ -182,21 +230,41 @@ bool QUECTEL_BG96_CellularStack::is_protocol_supported(nsapi_protocol_t protocol
nsapi_error_t QUECTEL_BG96_CellularStack::socket_close_impl(int sock_id)
{
_at.set_at_timeout(BG96_CLOSE_SOCKET_TIMEOUT);
nsapi_error_t err = _at.at_cmd_discard("+QICLOSE", "=", "%d", sock_id);
nsapi_error_t err;
CellularSocket *socket = find_socket(sock_id);
if (socket && socket->tls_socket) {
err = _at.at_cmd_discard("+QSSLCLOSE", "=", "%d", sock_id);
if (err == NSAPI_ERROR_OK) {
// Disable TLSSocket settings to prevent reuse on next socket without setting the values
_tls_sec_level = 0;
err = _at.at_cmd_discard("+QSSLCFG", "=\"seclevel\",", "%d%d", sslctxID, _tls_sec_level);
}
} else {
err = _at.at_cmd_discard("+QICLOSE", "=", "%d", sock_id);
}
_at.restore_at_timeout();
return err;
}
void QUECTEL_BG96_CellularStack::handle_open_socket_response(int &modem_connect_id, int &err)
void QUECTEL_BG96_CellularStack::handle_open_socket_response(int &modem_connect_id, int &err, bool tlssocket)
{
// OK
// QIOPEN -> should be handled as URC?
_at.set_at_timeout(BG96_CREATE_SOCKET_TIMEOUT);
if (tlssocket) {
_at.resp_start("+QSSLOPEN:");
} else {
_at.resp_start("+QIOPEN:");
}
_at.restore_at_timeout();
modem_connect_id = _at.read_int();
err = _at.read_int();
if (tlssocket && err != 0) {
err = NSAPI_ERROR_AUTH_FAILURE;
}
}
nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *socket)
@ -215,7 +283,7 @@ nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *soc
(_ip_ver_sendto == NSAPI_IPv4) ? "127.0.0.1" : "0:0:0:0:0:0:0:1",
remote_port, socket->localAddress.get_port(), 0);
handle_open_socket_response(modem_connect_id, err);
handle_open_socket_response(modem_connect_id, err, false);
if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) {
if (err == BG96_SOCKET_BIND_FAIL) {
@ -228,7 +296,7 @@ nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *soc
(_ip_ver_sendto == NSAPI_IPv4) ? "127.0.0.1" : "0:0:0:0:0:0:0:1",
remote_port, socket->localAddress.get_port(), 0);
handle_open_socket_response(modem_connect_id, err);
handle_open_socket_response(modem_connect_id, err, false);
}
} else if (socket->proto == NSAPI_UDP && socket->connected) {
char ipdot[NSAPI_IP_SIZE];
@ -236,7 +304,7 @@ nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *soc
_at.at_cmd_discard("+QIOPEN", "=", "%d%d%s%s%d", _cid, request_connect_id, "UDP",
ipdot, socket->remoteAddress.get_port());
handle_open_socket_response(modem_connect_id, err);
handle_open_socket_response(modem_connect_id, err, false);
if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) {
if (err == BG96_SOCKET_BIND_FAIL) {
@ -248,7 +316,7 @@ nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *soc
_at.at_cmd_discard("+QIOPEN", "=", "%d%d%s%s%d", _cid, request_connect_id, "UDP",
ipdot, socket->remoteAddress.get_port());
handle_open_socket_response(modem_connect_id, err);
handle_open_socket_response(modem_connect_id, err, false);
}
}
@ -283,8 +351,12 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_sendto_impl(CellularSoc
int sent_len_before = 0;
int sent_len_after = 0;
if (socket->tls_socket) {
sent_len_after = size;
} else {
// Get the sent count before sending
_at.at_cmd_int("+QISEND", "=", sent_len_before, "%d%d", socket->id, 0);
}
// Send
if (socket->proto == NSAPI_UDP) {
@ -292,9 +364,13 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_sendto_impl(CellularSoc
ip2dot(address, ipdot);
_at.cmd_start_stop("+QISEND", "=", "%d%d%s%d", socket->id, size,
ipdot, address.get_port());
} else {
if (socket->tls_socket) {
_at.cmd_start_stop("+QSSLSEND", "=", "%d%d", socket->id, size);
} else {
_at.cmd_start_stop("+QISEND", "=", "%d%d", socket->id, size);
}
}
_at.resp_start(">");
_at.write_bytes((uint8_t *)data, size);
@ -310,7 +386,12 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_sendto_impl(CellularSoc
}
// Get the sent count after sending
nsapi_size_or_error_t err = _at.at_cmd_int("+QISEND", "=", sent_len_after, "%d%d", socket->id, 0);
nsapi_size_or_error_t err = NSAPI_ERROR_OK;
if (!socket->tls_socket) {
err = _at.at_cmd_int("+QISEND", "=", sent_len_after, "%d%d", socket->id, 0);
}
if (err == NSAPI_ERROR_OK) {
sent_len = sent_len_after - sent_len_before;
return sent_len;
@ -323,22 +404,34 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_recvfrom_impl(CellularS
void *buffer, nsapi_size_t size)
{
nsapi_size_or_error_t recv_len = 0;
int port;
int port = -1;
char ip_address[NSAPI_IP_SIZE + 1];
if (socket->proto == NSAPI_TCP) {
// do not read more than max size
size = size > BG96_MAX_RECV_SIZE ? BG96_MAX_RECV_SIZE : size;
if (socket->tls_socket) {
_at.cmd_start_stop("+QSSLRECV", "=", "%d%d", socket->id, size);
} else {
_at.cmd_start_stop("+QIRD", "=", "%d%d", socket->id, size);
}
} else {
_at.cmd_start_stop("+QIRD", "=", "%d", socket->id);
}
if (socket->tls_socket) {
_at.resp_start("+QSSLRECV:");
} else {
_at.resp_start("+QIRD:");
}
recv_len = _at.read_int();
if (recv_len > 0) {
// UDP has remote_IP and remote_port parameters
if (socket->proto == NSAPI_UDP) {
_at.read_string(ip_address, sizeof(ip_address));
port = _at.read_int();
if (recv_len > 0) {
}
// do not read more than buffer size
recv_len = recv_len > (nsapi_size_or_error_t)size ? size : recv_len;
_at.read_bytes((uint8_t *)buffer, recv_len);
@ -436,3 +529,120 @@ void QUECTEL_BG96_CellularStack::ip2dot(const SocketAddress &ip, char *dot)
*dot = '\0';
}
}
nsapi_error_t QUECTEL_BG96_CellularStack::set_to_modem_impl(const char *filename, const char *config, const char *data, size_t size)
{
// Delete old file from the modem.
_at.at_cmd_discard("+QFDEL", "=", "%s", filename);
_at.clear_error(); // Ignore error if file didn't exist
// Upload new file to modem
_at.cmd_start_stop("+QFUPL", "=", "%s%d", filename, size);
_at.resp_start("CONNECT");
_at.write_bytes((uint8_t *)data, size);
_at.resp_start("+QFUPL:");
size_t upload_size = _at.read_int();
_at.resp_stop();
if (upload_size != size) {
tr_error("Upload error! orig = %d, uploaded = %d", size, upload_size);
return NSAPI_ERROR_DEVICE_ERROR;
}
// Configure into use
_at.at_cmd_discard("+QSSLCFG", "=", "%s%d%s", config, sslctxID, filename);
return _at.get_last_error();
}
nsapi_error_t QUECTEL_BG96_CellularStack::setsockopt(nsapi_socket_t handle, int level,
int optname, const void *optval, unsigned optlen)
{
CellularSocket *socket = (CellularSocket *)handle;
nsapi_error_t ret = NSAPI_ERROR_OK;
if (level == NSAPI_TLSSOCKET_LEVEL) {
if (optval) {
_at.lock();
switch (optname) {
case NSAPI_TLSSOCKET_ENABLE: {
MBED_ASSERT(optlen == sizeof(bool));
bool *enabled = (bool *)optval;
if (socket->proto == NSAPI_TCP) {
socket->tls_socket = enabled;
if (enabled) {
_at.at_cmd_discard("+QSSLCFG", "=\"seclevel\",", "%d%d", sslctxID, _tls_sec_level);
_at.at_cmd_discard("+QSSLCFG", "=\"sslversion\",", "%d%d", sslctxID, BG96_SUPPORTED_SSL_VERSION);
_at.cmd_start("AT+QSSLCFG=\"ciphersuite\",");
_at.write_int(sslctxID);
_at.write_string(BG96_SUPPORTED_CIPHER_SUITE, false);
_at.cmd_stop_read_resp();
ret = _at.get_last_error();
}
} else {
tr_error("Trying to set non-TCPSocket as TLSSocket");
ret = NSAPI_ERROR_PARAMETER;
}
}
break;
case NSAPI_TLSSOCKET_SET_HOSTNAME: {
const char *hostname = (const char *)optval;
_at.at_cmd_discard("+QSSLCFG", "=\"checkhost\",", "%d%s", sslctxID, hostname);
ret = _at.get_last_error();
}
break;
case NSAPI_TLSSOCKET_SET_CACERT: {
const char *cacert = (const char *)optval;
ret = set_to_modem_impl("cacert.pem", "cacert", cacert, optlen);
// Set sec level to "Manage server authentication" if only cacert is in use
if (ret == NSAPI_ERROR_OK && _tls_sec_level == 0) {
_tls_sec_level = 1;
}
}
break;
case NSAPI_TLSSOCKET_SET_CLCERT: {
const char *clcert = (const char *)optval;
ret = set_to_modem_impl("clcert.pem", "clientcert", clcert, optlen);
// Set sec level to "Manage server and client authentication if requested by the remote server"
if (ret == NSAPI_ERROR_OK) {
_tls_sec_level = 2;
}
}
break;
case NSAPI_TLSSOCKET_SET_CLKEY: {
const char *clkey = (const char *)optval;
ret = set_to_modem_impl("client.key", "clientkey", clkey, optlen);
// Set sec level to "Manage server and client authentication if requested by the remote server"
if (ret == NSAPI_ERROR_OK) {
_tls_sec_level = 2;
}
}
break;
default:
tr_error("Unsupported sockopt (%d)", optname);
ret = NSAPI_ERROR_UNSUPPORTED;
}
_at.unlock();
} else {
tr_error("No optval!");
ret = NSAPI_ERROR_PARAMETER;
}
} else {
tr_warning("Unsupported level (%d)", level);
ret = NSAPI_ERROR_UNSUPPORTED;
}
return ret;
}

View File

@ -55,6 +55,9 @@ protected: // NetworkStack
virtual nsapi_error_t gethostbyname_async_cancel(int id);
#endif
virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
int optname, const void *optval, unsigned optlen);
protected: // AT_CellularStack
virtual int get_max_socket_count();
@ -79,7 +82,9 @@ private:
// URC handler for socket being closed
void urc_qiurc_closed();
void handle_open_socket_response(int &modem_connect_id, int &err);
void handle_open_socket_response(int &modem_connect_id, int &err, bool tlssocket);
nsapi_error_t set_to_modem_impl(const char *filename, const char *config, const char *data, size_t size);
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
// URC handler for DNS query
@ -89,6 +94,9 @@ private:
hostbyname_cb_t _dns_callback;
nsapi_version_t _dns_version;
#endif
uint8_t _tls_sec_level;
/** Convert IP address to dotted string representation
*
* BG96 requires consecutive zeros so can't use get_ip_address or ip6tos directly.

View File

@ -20,6 +20,8 @@
#define TRACE_GROUP "TLSS"
#include "mbed-trace/mbed_trace.h"
#if !defined(MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET) || !(MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET)
// This class requires Mbed TLS SSL/TLS client code
#if defined(MBEDTLS_SSL_CLI_C)
@ -46,5 +48,71 @@ TLSSocket::~TLSSocket()
*/
close();
}
#endif // MBEDTLS_SSL_CLI_C
#else // MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET
TLSSocket::TLSSocket()
{
}
TLSSocket::~TLSSocket()
{
}
nsapi_error_t TLSSocket::set_hostname(const char *hostname)
{
return setsockopt(NSAPI_TLSSOCKET_LEVEL, NSAPI_TLSSOCKET_SET_HOSTNAME, hostname, strlen(hostname));
}
nsapi_error_t TLSSocket::set_root_ca_cert(const void *root_ca, size_t len)
{
return setsockopt(NSAPI_TLSSOCKET_LEVEL, NSAPI_TLSSOCKET_SET_CACERT, root_ca, len);
}
nsapi_error_t TLSSocket::set_root_ca_cert(const char *root_ca_pem)
{
return set_root_ca_cert(root_ca_pem, strlen(root_ca_pem));
}
nsapi_error_t TLSSocket::set_client_cert_key(const void *client_cert, size_t client_cert_len,
const void *client_private_key_pem, size_t client_private_key_len)
{
nsapi_error_t ret = setsockopt(NSAPI_TLSSOCKET_LEVEL, NSAPI_TLSSOCKET_SET_CLCERT, client_cert, client_cert_len);
if (ret == NSAPI_ERROR_OK) {
ret = setsockopt(NSAPI_TLSSOCKET_LEVEL, NSAPI_TLSSOCKET_SET_CLKEY, client_private_key_pem, client_private_key_len);
}
return ret;
}
nsapi_error_t TLSSocket::set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem)
{
return set_client_cert_key(client_cert_pem, strlen(client_cert_pem), client_private_key_pem, strlen(client_private_key_pem));
}
nsapi_error_t TLSSocket::connect(const char *host, uint16_t port)
{
nsapi_error_t ret = enable_tlssocket();
if (ret == NSAPI_ERROR_OK) {
ret = TCPSocket::connect(host, port);
}
return ret;
}
nsapi_error_t TLSSocket::connect(const SocketAddress &address)
{
nsapi_error_t ret = enable_tlssocket();
if (ret == NSAPI_ERROR_OK) {
ret = TCPSocket::connect(address);
}
return ret;
}
nsapi_error_t TLSSocket::enable_tlssocket()
{
bool enabled = true;
return setsockopt(NSAPI_TLSSOCKET_LEVEL, NSAPI_TLSSOCKET_ENABLE, &enabled, sizeof(enabled));
}
#endif // MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET

View File

@ -23,7 +23,6 @@
#define _MBED_HTTPS_TLS_TCP_SOCKET_H_
#include "netsocket/TCPSocket.h"
#include "TLSSocketWrapper.h"
#include "mbedtls/platform.h"
#include "mbedtls/ssl.h"
@ -31,9 +30,13 @@
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#if !defined(MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET) || !(MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET)
// This class requires Mbed TLS SSL/TLS client code
#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
#include "TLSSocketWrapper.h"
/**
* \brief TLSSocket is a wrapper around TCPSocket for interacting with TLS servers.
*
@ -62,7 +65,7 @@ public:
* clear internal TLS memory structures.
*
* @param stack Network stack as target for socket.
* @return 0 on success, negative error code on failure.
* @return NSAPI_ERROR_OK on success, negative error code on failure.
*/
virtual nsapi_error_t open(NetworkStack *stack)
{
@ -87,15 +90,80 @@ public:
*
* @param host Hostname of the remote host.
* @param port Port of the remote host.
* @return 0 on success, negative error code on failure.
* @return NSAPI_ERROR_OK on success, negative error code on failure.
*/
nsapi_error_t connect(const char *host, uint16_t port);
private:
TCPSocket tcp_socket;
};
#endif // MBEDTLS_SSL_CLI_C
#else // MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET
class TLSSocket : public TCPSocket {
public:
TLSSocket();
virtual ~TLSSocket();
/** Set hostname.
*
* TLSSocket requires hostname used to verify the certificate.
* If hostname is not given in constructor, this function must be used before
* starting the TLS handshake.
*
* @param hostname Hostname of the remote host, used for certificate checking.
*/
nsapi_error_t set_hostname(const char *hostname);
/** Sets the certification of Root CA.
*
* @note Must be called after open() before calling connect()
*
* @param root_ca Root CA Certificate in any Mbed TLS-supported format.
* @param len Length of certificate (including terminating 0 for PEM).
* @return NSAPI_ERROR_OK on success, negative error code on failure.
*/
virtual nsapi_error_t set_root_ca_cert(const void *root_ca, size_t len);
/** Sets the certification of Root CA.
*
* @note Must be called after open() before calling connect()
*
* @param root_ca_pem Root CA Certificate in PEM format.
*/
virtual nsapi_error_t set_root_ca_cert(const char *root_ca_pem);
/** Sets client certificate, and client private key.
*
* @param client_cert Client certification in PEM or DER format.
* @param client_cert_len Certificate size including the terminating null byte for PEM data.
* @param client_private_key_pem Client private key in PEM or DER format.
* @param client_private_key_len Key size including the terminating null byte for PEM data
* @return NSAPI_ERROR_OK on success, negative error code on failure.
*/
virtual nsapi_error_t set_client_cert_key(const void *client_cert, size_t client_cert_len,
const void *client_private_key_pem, size_t client_private_key_len);
/** Sets client certificate, and client private key.
*
* @param client_cert_pem Client certification in PEM format.
* @param client_private_key_pem Client private key in PEM format.
* @return NSAPI_ERROR_OK on success, negative error code on failure.
*/
virtual nsapi_error_t set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem);
// From TCPSocket
virtual nsapi_error_t connect(const char *host, uint16_t port);
virtual nsapi_error_t connect(const SocketAddress &address);
protected:
virtual nsapi_error_t enable_tlssocket();
};
#endif // MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET
#endif // _MBED_HTTPS_TLS_TCP_SOCKET_H_
/** @} */

View File

@ -65,6 +65,10 @@
"socket-stats-max-count": {
"help": "Maximum number of socket statistics cached",
"value": 10
},
"offload-tlssocket" : {
"help": "Use external TLSSocket implementation. Used network stack must support external TLSSocket setsockopt values (see nsapi_types.h)",
"value": null
}
},
"target_overrides": {

View File

@ -269,6 +269,18 @@ typedef enum nsapi_socket_option {
NSAPI_BIND_TO_DEVICE, /*!< Bind socket network interface name*/
} nsapi_socket_option_t;
typedef enum nsapi_tlssocket_level {
NSAPI_TLSSOCKET_LEVEL = 7099, /*!< TLSSocket option level - see nsapi_tlssocket_option_t for options*/
} nsapi_tlssocket_level_t;
typedef enum nsapi_tlssocket_option {
NSAPI_TLSSOCKET_SET_HOSTNAME, /*!< Set host name */
NSAPI_TLSSOCKET_SET_CACERT, /*!< Set server CA certificate */
NSAPI_TLSSOCKET_SET_CLCERT, /*!< Set client certificate */
NSAPI_TLSSOCKET_SET_CLKEY, /*!< Set client key */
NSAPI_TLSSOCKET_ENABLE /*!< Enable TLSSocket */
} nsapi_tlssocket_option_t;
/** Supported IP protocol versions of IP stack
*
* @enum nsapi_ip_stack