mirror of https://github.com/ARMmbed/mbed-os.git
Implement TLSSocket
Provide TLSSocket implementation. This implementation allows TLSSocket to wrap around any existing socket. Currently only TLS supported. DTLS not yet implemented. Design document also provided with the implementation. Documentation submitted to Mbed OS handbook.pull/8311/head
parent
8bf51be75a
commit
7f39bb4453
|
@ -0,0 +1,275 @@
|
|||
# TLSSocket - Design document
|
||||
## Overview and Background
|
||||
|
||||
This document describes design of TLSSocket class that provides simple interface for Mbed OS
|
||||
user to create TLS connections over TCP socket.
|
||||
|
||||
This class greatly simplifies the usage of TLS but limits itself to only one use case.
|
||||
This design limitation is accepted as other users can continue using Mbed TLS API
|
||||
directly. TLSSocket also exposes internal Mbed TLS structures allowing use of Mbed TLS API to configure the underlying library.
|
||||
|
||||
High level goal is to demonstrate Mbed OS users that secure connections are not hard to do.
|
||||
|
||||
## Design Limitations
|
||||
|
||||
Following design limitations exist in the current design of TLSSocket
|
||||
|
||||
* `TLSSocket::connect()` is always blocking
|
||||
* Can only use server and client certificates through `set_root_ca_cert()` and `set_client_cert_key()` methods. For other use cases, internal Mbed TLS structures are exposed.
|
||||
* No PSK mode
|
||||
|
||||
# System Architecture and High-Level Design
|
||||
|
||||
Secure socket consist of two classes:
|
||||
|
||||
* `TLSocketWrapper` <br>
|
||||
Which handles initialization of TLS library and does TLS handsake. Takes any Socket as a
|
||||
trasport.
|
||||
* `TLSSocket` <br>
|
||||
Which inherits TLSocketWrapper and has TCP socket as a transport.
|
||||
Adds `connect(char *hostname)`
|
||||
for initiating the TCP and TLS handshakes at one call.
|
||||
|
||||
```
|
||||
,--------------.
|
||||
|Socket |
|
||||
|--------------|
|
||||
|--------------|
|
||||
|int connect();|
|
||||
|int recv(); |
|
||||
|int send(); |
|
||||
`--------------'
|
||||
|
|
||||
|
|
||||
,----------------------------.
|
||||
|TLSocketWrapper |
|
||||
|----------------------------|
|
||||
|Socket *transport; |
|
||||
|----------------------------|
|
||||
|TLSocketWrapper(*transport);|
|
||||
|int set_root_ca_cert(...); |
|
||||
|void set_hostname(...); |
|
||||
|int do_handshake(); |
|
||||
`----------------------------'
|
||||
|
|
||||
,----------------------------.
|
||||
|TLSSocket |
|
||||
|----------------------------|
|
||||
|TCPSocket transport |
|
||||
|----------------------------|
|
||||
|int connect(char *hostname);|
|
||||
`----------------------------'
|
||||
```
|
||||
|
||||
## High Level Design Goal 1: Abstract socket API
|
||||
|
||||
Secure socket both uses `Socket` interface as its transport layer and implements it. This makes it transport independent and there is no direct dependency to IP stack.
|
||||
|
||||
When TLSSocket implements Socket API it is able to be used instead of TCP connection in
|
||||
any Mbed OS library. For example MQTT library is made secure without any code changes:
|
||||
https://github.com/coisme/Mbed-to-Azure-IoT-Hub/tree/new-TLSSocket
|
||||
|
||||
## High Level Design Goal 2: Only certificate based authentication
|
||||
|
||||
Aim is to first support only certificate based authentication, so we implement only `set_root_ca_cert()` and `set_client_cert_key()` functions. For later on, different types of authentication methods can be added.
|
||||
|
||||
## High Level Design Goal 3: Support both blocking and non-blocking operations
|
||||
|
||||
As the Mbed TLS is already work with both socket types, we are able to `TLSocketWrapper`
|
||||
that can handle both types as well.
|
||||
|
||||
Functions `set_blocking()` and `set_timeout()` just pass the information for underlying
|
||||
transport socket. Extra handling on the TLS state machine is not required.
|
||||
|
||||
## High Level Design Goal 4: Expose Mbed TLS structures
|
||||
|
||||
Exposing Mbed TLS configuration structures allows user to configure the underlying TLS instance using Mbed TLS API. This allows greater usability as TLSSocket is not limited to only one use case.
|
||||
|
||||
Also configuration structures can be shared between sockets which leads to RAM saving then two or more TLSSockets are used with same parameters.
|
||||
|
||||
## System Architecture and Component Interaction
|
||||
*Description and diagrams showing overall architecture of how the above-mentioned components/resources interface with each other.*
|
||||
|
||||
# Detailed Design
|
||||
*This section provides detailed design on implementation of components/modules mentioned in High Level Design section.*
|
||||
|
||||
## Detailed Design for Abstract socket API
|
||||
|
||||
Mbed OS [Socket interface](https://github.com/ARMmbed/mbed-os/blob/master/features/netsocket/Socket.h) is a abstract C++ inteface that follows POSIX socket API.
|
||||
|
||||
### Receiving and sending data from Mbed TLS
|
||||
|
||||
`TLSSocketWrapper` contains static wrappers `ssl_recv()` and `ssl_send()` functions which are
|
||||
registered to Mbed TLS library in `mbedtls_ssl_set_bio()` call.
|
||||
|
||||
There functions then call the transport socket's `Socket::send()` and `Socket::recv()` calls
|
||||
respectively. Error coded are passed through, except `NSAPI_ERROR_WOULD_BLOCK` which is translated to `MBEDTLS_ERR_SSL_WANT_WRITE` or `MBEDTLS_ERR_SSL_WANT_READ`.
|
||||
|
||||
### Providing Socket API
|
||||
|
||||
```
|
||||
virtual nsapi_error_t close();
|
||||
```
|
||||
|
||||
Destroys the memory allocated by TLS library.
|
||||
Alternatively also closes the transport socket, unless `TLSSocketWrapper::keep_transport_open()` has been called earlier.
|
||||
|
||||
|
||||
```
|
||||
virtual nsapi_error_t connect(const SocketAddress &address);
|
||||
```
|
||||
|
||||
Initiates the TCP connection and continues to TLS hanshake.
|
||||
This is currently forced to blocking mode.
|
||||
|
||||
```
|
||||
virtual nsapi_size_or_error_t send(const void *data, nsapi_size_t size);
|
||||
virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size);
|
||||
virtual nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size);
|
||||
virtual nsapi_size_or_error_t recvfrom(SocketAddress *address, void *data, nsapi_size_t size);
|
||||
```
|
||||
These work as expected, but `SocketAddress` parameters are ignored. TLS connection cannot
|
||||
change the peer. Also `recvfrom()` call does not set the peer address.
|
||||
|
||||
Mbed TLS error codes `MBEDTLS_ERR_SSL_WANT_READ` and `MBEDTLS_ERR_SSL_WANT_WRITE` are
|
||||
translated to `NSAPI_ERROR_WOULD_BLOCK` before passing to user.
|
||||
|
||||
`MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY` is ignored and zero is returned to user (connection closed). Other error codes are passed through.
|
||||
|
||||
```
|
||||
virtual nsapi_error_t bind(const SocketAddress &address);
|
||||
virtual void set_blocking(bool blocking);
|
||||
virtual void set_timeout(int timeout);
|
||||
virtual void sigio(mbed::Callback<void()> func);
|
||||
virtual nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen);
|
||||
virtual nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen);
|
||||
```
|
||||
These are passed through to transport socket.
|
||||
|
||||
|
||||
```
|
||||
virtual Socket *accept(nsapi_error_t *error = NULL);
|
||||
virtual nsapi_error_t listen(int backlog = 1);
|
||||
```
|
||||
These are returning `NSAPI_ERROR_UNSUPPORTED` as TLS socket cannot be set to listening mode.
|
||||
|
||||
## Detailed Design for certificate based authentication
|
||||
|
||||
`TLSSocketWrapper` provides following API to set server certificate. You can use either BASE64 formatted PEM certificate, or binary DER certificates. Later form just assumes `root_ca_pem` or `client_cert_pem` to be standard C string and counts its lenght and passes to method which takes just `void*` and `len`.
|
||||
|
||||
```
|
||||
/** Sets the certification of Root CA.
|
||||
*
|
||||
* @param root_ca Root CA Certificate in any mbed-TLS supported format.
|
||||
* @param len Length of certificate (including terminating 0 for PEM).
|
||||
*/
|
||||
nsapi_error_t TLSSocketWrapper::set_root_ca_cert(const void *root_ca, size_t len);
|
||||
|
||||
/** Sets the certification of Root CA.
|
||||
*
|
||||
* @param root_ca_pem Root CA Certificate in PEM format
|
||||
*/
|
||||
nsapi_error_t TLSSocketWrapper::set_root_ca_cert(const char *root_ca_pem);
|
||||
```
|
||||
|
||||
If client authentication is required, following API allows you to set the client certificate and private key:
|
||||
|
||||
```
|
||||
/** Sets client certificate, and client private key.
|
||||
*
|
||||
* @param client_cert Client certification in any mbed-TLS supported format.
|
||||
* @param client_private_key Client private key in PEM format.
|
||||
*/
|
||||
nsapi_error_t TLSSocketWrapper::set_client_cert_key(const void *client_cert_pem, 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 Client private key in PEM format.
|
||||
*/
|
||||
nsapi_error_t TLSSocketWrapper::set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem);
|
||||
```
|
||||
|
||||
Certificate is then passed unmodified to `mbedtls_x509_crt_parse()` function.
|
||||
|
||||
## Detailed Design for Support both blocking and non-blocking operations
|
||||
|
||||
`send()` and `receive()` methods do not need to know whether underlying socket is in
|
||||
blocking mode as Mbed OS return values are enough to tell that.
|
||||
|
||||
Data path when application send data to TLS socket:
|
||||
|
||||
1. Application call `TLSSocketWrapper::send()` function.
|
||||
1. Which calls `mbedtls_ssl_write()` function
|
||||
1. Which calls `TLSSocketWrapper::ssl_send()`
|
||||
1. Which calls transport socket's `Socket::send()` which either blocks or returns `NSAPI_ERROR_WOULD_BLOCK`
|
||||
|
||||
When this `NSAPI_ERROR_WOULD_BLOCK` is returned:
|
||||
|
||||
1. `TLSSocketWrapper::ssl_send()` translates error to `MBEDTLS_ERR_SSL_WANT_WRITE`
|
||||
1. returned to `mbedtls_ssl_write()` which return the same error
|
||||
1. `TLSSocketWrapper::send()` gets the `MBEDTLS_ERR_SSL_WANT_WRITE` and translates that to `NSAPI_ERROR_WOULD_BLOCK`
|
||||
1. Application gets `NSAPI_ERROR_WOULD_BLOCK` and back off.
|
||||
|
||||
When transport socket is in blocking mode, it never returns `NSAPI_ERROR_WOULD_BLOCK` and therefore `mbedtls_ssl_write()` never gets `MBEDTLS_ERR_SSL_WANT_WRITE`, so any translation does not happen, but code path stays unchanged.
|
||||
|
||||
## Detailed Design for exposing Mbed TLS structures
|
||||
|
||||
TLSSocket exposes following API to provide access to internal Mbed TLS data structures:
|
||||
```
|
||||
mbedtls_x509_crt *get_own_cert();
|
||||
int set_own_cert(mbedtls_x509_crt *);
|
||||
mbedtls_x509_crt *get_ca_chain();
|
||||
void set_ca_chain(mbedtls_x509_crt *);
|
||||
mbedtls_ssl_config *get_ssl_config();
|
||||
void set_ssl_config(mbedtls_ssl_config *);
|
||||
```
|
||||
|
||||
This allows sockets to share same configuration and allow user to fine tune TLS configuration, for example:
|
||||
|
||||
```
|
||||
TLSSocket a;
|
||||
TLSSocket b;
|
||||
a.set_root_ca_cert(<cert>);
|
||||
b.set_ssl_config(a.get_ssl_config());
|
||||
```
|
||||
|
||||
# Usage Scenarios and Examples
|
||||
|
||||
## Scenario 1: Connecting to secure server:
|
||||
|
||||
```
|
||||
NetworkInterface *net = NetworkInterface::get_default_instance();
|
||||
|
||||
TLSSocket sock(net);
|
||||
sock.add_root_CA(...);
|
||||
|
||||
sock.connect("my_server.mbed.com", 8080); // Connect & handle TLS handshake
|
||||
|
||||
// Now Socket is connected and can be used as any socket
|
||||
sock.send("hello", 5);
|
||||
```
|
||||
|
||||
Example user: https://github.com/coisme/Mbed-to-Azure-IoT-Hub/blob/new-TLSSocket/MQTTNetwork.h
|
||||
|
||||
# Tools and Configuration Changes
|
||||
|
||||
No tool changes required
|
||||
|
||||
# Other Information
|
||||
|
||||
## Reusability
|
||||
|
||||
Parts of the state machine are probably relevant when implementing DTLS socket.
|
||||
|
||||
TLSSocketWrapper is entirely reusable when doing TLS handshake using any socket type.
|
||||
It does not have tight bindings to TCP.
|
||||
|
||||
## Assumptions
|
||||
|
||||
We are assuming that server certificate is given from the application to `TLSSocket::set_root_ca_cert()` interface in a format that is understood by Mbed TLS.
|
||||
|
||||
## Deprecations
|
||||
|
||||
No deprecations
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License 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 "TLSSocket.h"
|
||||
|
||||
#define TRACE_GROUP "TLSS"
|
||||
#include "mbed-trace/mbed_trace.h"
|
||||
|
||||
// This class requires Mbed TLS SSL/TLS client code
|
||||
#if defined(MBEDTLS_SSL_CLI_C)
|
||||
|
||||
nsapi_error_t TLSSocket::connect(const char *host, uint16_t port)
|
||||
{
|
||||
set_hostname(host);
|
||||
|
||||
nsapi_error_t ret = tcp_socket.connect(host, port);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return TLSSocketWrapper::do_handshake();
|
||||
}
|
||||
|
||||
#endif // MBEDTLS_SSL_CLI_C
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License 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.
|
||||
*/
|
||||
|
||||
#ifndef _MBED_HTTPS_TLS_TCP_SOCKET_H_
|
||||
#define _MBED_HTTPS_TLS_TCP_SOCKET_H_
|
||||
|
||||
#include "netsocket/TCPSocket.h"
|
||||
#include "TLSSocketWrapper.h"
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
|
||||
// This class requires Mbed TLS SSL/TLS client code
|
||||
#if defined(MBEDTLS_SSL_CLI_C)
|
||||
|
||||
/**
|
||||
* \brief TLSSocket a wrapper around TCPSocket for interacting with TLS servers
|
||||
*/
|
||||
class TLSSocket : public TLSSocketWrapper {
|
||||
public:
|
||||
/** Create an uninitialized socket
|
||||
*
|
||||
* Must call open to initialize the socket on a network stack.
|
||||
*/
|
||||
TLSSocket() : TLSSocketWrapper(&tcp_socket) {}
|
||||
|
||||
/** Create a socket on a network interface
|
||||
*
|
||||
* Creates and opens a socket on the network stack of the given
|
||||
* network interface.
|
||||
* If hostname is also given, user is not required to call set_hostname() later.
|
||||
*
|
||||
* @param stack Network stack as target for socket
|
||||
* @param hostname Hostname used for certificate verification
|
||||
*/
|
||||
template <typename S>
|
||||
TLSSocket(S *stack, const char *hostname = NULL) : TLSSocketWrapper(&tcp_socket, hostname)
|
||||
{
|
||||
nsapi_error_t ret = tcp_socket.open(stack);
|
||||
MBED_ASSERT(ret == NSAPI_ERROR_OK);
|
||||
}
|
||||
|
||||
/** Opens a socket
|
||||
*
|
||||
* Creates a network socket on the network stack of the given
|
||||
* network interface. Not needed if stack is passed to the
|
||||
* socket's constructor.
|
||||
*
|
||||
* @param stack Network stack as target for socket
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t open(NetworkStack *stack) {
|
||||
return tcp_socket.open(stack);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
nsapi_error_t open(S *stack) {
|
||||
return open(nsapi_create_stack(stack));
|
||||
}
|
||||
|
||||
using TLSSocketWrapper::connect;
|
||||
|
||||
/** Connects TCP socket to a remote host
|
||||
*
|
||||
* Initiates a connection to a remote server specified by either
|
||||
* a domain name or an IP address and a port.
|
||||
*
|
||||
* @param host Hostname of the remote host
|
||||
* @param port Port of the remote host
|
||||
* @return 0 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
|
||||
#endif // _MBED_HTTPS_TLS_TCP_SOCKET_H_
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License 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 "TLSSocketWrapper.h"
|
||||
#include "drivers/Timer.h"
|
||||
|
||||
#define TRACE_GROUP "TLSW"
|
||||
#include "mbed-trace/mbed_trace.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbed_error.h"
|
||||
|
||||
// This class requires Mbed TLS SSL/TLS client code
|
||||
#if defined(MBEDTLS_SSL_CLI_C)
|
||||
|
||||
TLSSocketWrapper::TLSSocketWrapper(Socket *transport, const char *hostname, control_transport control) :
|
||||
_transport(transport),
|
||||
_cacert(NULL),
|
||||
_clicert(NULL),
|
||||
_ssl_conf(NULL),
|
||||
_connect_transport(control==TRANSPORT_CONNECT || control==TRANSPORT_CONNECT_AND_CLOSE),
|
||||
_close_transport(control==TRANSPORT_CLOSE || control==TRANSPORT_CONNECT_AND_CLOSE),
|
||||
_handshake_completed(false),
|
||||
_cacert_allocated(false),
|
||||
_clicert_allocated(false),
|
||||
_ssl_conf_allocated(false)
|
||||
{
|
||||
mbedtls_entropy_init(&_entropy);
|
||||
mbedtls_ctr_drbg_init(&_ctr_drbg);
|
||||
mbedtls_ssl_init(&_ssl);
|
||||
mbedtls_pk_init(&_pkctx);
|
||||
|
||||
if (hostname) {
|
||||
set_hostname(hostname);
|
||||
}
|
||||
}
|
||||
|
||||
TLSSocketWrapper::~TLSSocketWrapper() {
|
||||
if (_transport) {
|
||||
close();
|
||||
}
|
||||
mbedtls_entropy_free(&_entropy);
|
||||
mbedtls_ctr_drbg_free(&_ctr_drbg);
|
||||
mbedtls_ssl_free(&_ssl);
|
||||
mbedtls_pk_free(&_pkctx);
|
||||
|
||||
set_own_cert(NULL);
|
||||
set_ca_chain(NULL);
|
||||
set_ssl_config(NULL);
|
||||
}
|
||||
|
||||
void TLSSocketWrapper::set_hostname(const char *hostname)
|
||||
{
|
||||
mbedtls_ssl_set_hostname(&_ssl, hostname);
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::set_root_ca_cert(const void *root_ca, size_t len)
|
||||
{
|
||||
#if !defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||
return NSAPI_ERROR_UNSUPPORTED
|
||||
#else
|
||||
mbedtls_x509_crt *crt;
|
||||
|
||||
crt = new (std::nothrow) mbedtls_x509_crt;
|
||||
if (!crt) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
mbedtls_x509_crt_init(crt);
|
||||
|
||||
/* Parse CA certification */
|
||||
int ret;
|
||||
if ((ret = mbedtls_x509_crt_parse(crt, static_cast<const unsigned char *>(root_ca),
|
||||
len)) != 0) {
|
||||
print_mbedtls_error("mbedtls_x509_crt_parse", ret);
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
set_ca_chain(crt);
|
||||
_cacert_allocated = true;
|
||||
return NSAPI_ERROR_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::set_root_ca_cert(const char *root_ca_pem)
|
||||
{
|
||||
return set_root_ca_cert(root_ca_pem, strlen(root_ca_pem) + 1);
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::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) + 1, client_private_key_pem, strlen(client_private_key_pem) + 1);
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::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)
|
||||
{
|
||||
#if !defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||
return NSAPI_ERROR_UNSUPPORTED
|
||||
#else
|
||||
|
||||
int ret;
|
||||
mbedtls_x509_crt *crt = new mbedtls_x509_crt;
|
||||
mbedtls_x509_crt_init(crt);
|
||||
if((ret = mbedtls_x509_crt_parse(crt, static_cast<const unsigned char *>(client_cert),
|
||||
client_cert_len)) != 0) {
|
||||
print_mbedtls_error("mbedtls_x509_crt_parse", ret);
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
mbedtls_pk_init(&_pkctx);
|
||||
if((ret = mbedtls_pk_parse_key(&_pkctx, static_cast<const unsigned char *>(client_private_key_pem),
|
||||
client_private_key_len, NULL, 0)) != 0) {
|
||||
print_mbedtls_error("mbedtls_pk_parse_key", ret);
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
set_own_cert(crt);
|
||||
_clicert_allocated = true;
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||
}
|
||||
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::do_handshake() {
|
||||
nsapi_error_t _error;
|
||||
const char DRBG_PERS[] = "mbed TLS client";
|
||||
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
_transport->set_blocking(true);
|
||||
/*
|
||||
* Initialize TLS-related stuf.
|
||||
*/
|
||||
int ret;
|
||||
if ((ret = mbedtls_ctr_drbg_seed(&_ctr_drbg, mbedtls_entropy_func, &_entropy,
|
||||
(const unsigned char *) DRBG_PERS,
|
||||
sizeof (DRBG_PERS))) != 0) {
|
||||
print_mbedtls_error("mbedtls_crt_drbg_init", ret);
|
||||
_error = ret;
|
||||
return _error;
|
||||
}
|
||||
|
||||
tr_info("mbedtls_ssl_conf_rng()");
|
||||
mbedtls_ssl_conf_rng(get_ssl_config(), mbedtls_ctr_drbg_random, &_ctr_drbg);
|
||||
|
||||
|
||||
#if MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0
|
||||
mbedtls_ssl_conf_verify(get_ssl_config(), my_verify, NULL);
|
||||
mbedtls_ssl_conf_dbg(get_ssl_config(), my_debug, NULL);
|
||||
mbedtls_debug_set_threshold(MBED_CONF_TLS_SOCKET_DEBUG_LEVEL);
|
||||
#endif
|
||||
|
||||
tr_info("mbedtls_ssl_setup()");
|
||||
if ((ret = mbedtls_ssl_setup(&_ssl, get_ssl_config())) != 0) {
|
||||
print_mbedtls_error("mbedtls_ssl_setup", ret);
|
||||
_error = ret;
|
||||
return _error;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio(&_ssl, this, ssl_send, ssl_recv, NULL );
|
||||
|
||||
/* Start the handshake, the rest will be done in onReceive() */
|
||||
tr_info("Starting TLS handshake with %s", _ssl.hostname);
|
||||
|
||||
do {
|
||||
ret = mbedtls_ssl_handshake(&_ssl);
|
||||
} while (ret != 0 && (ret == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||
ret == MBEDTLS_ERR_SSL_WANT_WRITE));
|
||||
if (ret < 0) {
|
||||
print_mbedtls_error("mbedtls_ssl_handshake", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* It also means the handshake is done, time to print info */
|
||||
tr_info("TLS connection to %s established\r\n", _ssl.hostname);
|
||||
|
||||
/* Prints the server certificate and verify it. */
|
||||
const size_t buf_size = 1024;
|
||||
char* buf = new char[buf_size];
|
||||
mbedtls_x509_crt_info(buf, buf_size, "\r ",
|
||||
mbedtls_ssl_get_peer_cert(&_ssl));
|
||||
tr_debug("Server certificate:\r\n%s\r\n", buf);
|
||||
|
||||
uint32_t flags = mbedtls_ssl_get_verify_result(&_ssl);
|
||||
if( flags != 0 ) {
|
||||
/* Verification failed. */
|
||||
mbedtls_x509_crt_verify_info(buf, buf_size, "\r ! ", flags);
|
||||
tr_error("Certificate verification failed:\r\n%s", buf);
|
||||
} else {
|
||||
/* Verification succeeded. */
|
||||
tr_info("Certificate verification passed");
|
||||
}
|
||||
delete[] buf;
|
||||
|
||||
_handshake_completed = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::send(const void *data, nsapi_size_t size) {
|
||||
int ret;
|
||||
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
tr_debug("send %d", size);
|
||||
ret = mbedtls_ssl_write(&_ssl, (const unsigned char *) data, size);
|
||||
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
|
||||
ret == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
// translate to socket error
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
if (ret < 0) {
|
||||
print_mbedtls_error("mbedtls_ssl_write", ret);
|
||||
}
|
||||
return ret; // Assume "non negative errorcode" to be propagated from Socket layer
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t TLSSocketWrapper::sendto(const SocketAddress &, const void *data, nsapi_size_t size)
|
||||
{
|
||||
// Ignore the SocketAddress
|
||||
return send(data, size);
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t TLSSocketWrapper::recv(void *data, nsapi_size_t size) {
|
||||
int ret;
|
||||
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
ret = mbedtls_ssl_read(&_ssl, (unsigned char *) data, size);
|
||||
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
|
||||
ret == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
// translate to socket error
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
} else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
|
||||
/* MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY is not considered as error.
|
||||
* Just ignre here. Once connection is closed, mbedtls_ssl_read()
|
||||
* will return 0.
|
||||
*/
|
||||
return 0;
|
||||
} else if (ret < 0) {
|
||||
print_mbedtls_error("mbedtls_ssl_read", ret);
|
||||
// There is no mapping of TLS error codes to Socket API so return most generic error to application
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t TLSSocketWrapper::recvfrom(SocketAddress *address, void *data, nsapi_size_t size)
|
||||
{
|
||||
return recv(data, size);
|
||||
}
|
||||
|
||||
void TLSSocketWrapper::print_mbedtls_error(const char *name, int err) {
|
||||
char *buf = new char[128];
|
||||
mbedtls_strerror(err, buf, 128);
|
||||
tr_err("%s() failed: -0x%04x (%d): %s", name, -err, err, buf);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
|
||||
#if MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0
|
||||
|
||||
void TLSSocketWrapper::my_debug(void *ctx, int level, const char *file, int line,
|
||||
const char *str)
|
||||
{
|
||||
const char *p, *basename;
|
||||
(void) ctx;
|
||||
|
||||
/* Extract basename from file */
|
||||
for(p = basename = file; *p != '\0'; p++) {
|
||||
if(*p == '/' || *p == '\\') {
|
||||
basename = p + 1;
|
||||
}
|
||||
}
|
||||
|
||||
tr_debug("%s:%04d: |%d| %s", basename, line, level, str);
|
||||
}
|
||||
|
||||
|
||||
int TLSSocketWrapper::my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
|
||||
{
|
||||
const uint32_t buf_size = 1024;
|
||||
char *buf = new char[buf_size];
|
||||
(void) data;
|
||||
|
||||
tr_debug("\nVerifying certificate at depth %d:\n", depth);
|
||||
mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
|
||||
tr_debug("%s", buf);
|
||||
|
||||
if (*flags == 0)
|
||||
tr_info("No verification issue for this certificate\n");
|
||||
else
|
||||
{
|
||||
mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
|
||||
tr_info("%s\n", buf);
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0 */
|
||||
|
||||
|
||||
int TLSSocketWrapper::ssl_recv(void *ctx, unsigned char *buf, size_t len) {
|
||||
int recv;
|
||||
|
||||
TLSSocketWrapper *my = static_cast<TLSSocketWrapper *>(ctx);
|
||||
|
||||
if (!my->_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
recv = my->_transport->recv(buf, len);
|
||||
|
||||
if (NSAPI_ERROR_WOULD_BLOCK == recv) {
|
||||
return MBEDTLS_ERR_SSL_WANT_READ;
|
||||
} else if(recv < 0) {
|
||||
tr_error("Socket recv error %d", recv);
|
||||
}
|
||||
// Propagate also Socket errors to SSL, it allows negative error codes to be returned here.
|
||||
return recv;
|
||||
}
|
||||
|
||||
int TLSSocketWrapper::ssl_send(void *ctx, const unsigned char *buf, size_t len) {
|
||||
int size = -1;
|
||||
TLSSocketWrapper *my = static_cast<TLSSocketWrapper *>(ctx);
|
||||
|
||||
if (!my->_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
size = my->_transport->send(buf, len);
|
||||
|
||||
if (NSAPI_ERROR_WOULD_BLOCK == size) {
|
||||
return MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
} else if(size < 0){
|
||||
tr_error("Socket send error %d", size);
|
||||
}
|
||||
// Propagate also Socket errors to SSL, it allows negative error codes to be returned here.
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
mbedtls_x509_crt *TLSSocketWrapper::get_own_cert()
|
||||
{
|
||||
return _clicert;
|
||||
}
|
||||
|
||||
int TLSSocketWrapper::set_own_cert(mbedtls_x509_crt *crt)
|
||||
{
|
||||
int ret = 0;
|
||||
if (_clicert && _clicert_allocated) {
|
||||
mbedtls_x509_crt_free(_clicert);
|
||||
delete _clicert;
|
||||
_clicert_allocated = false;
|
||||
}
|
||||
_clicert = crt;
|
||||
if (crt) {
|
||||
if((ret = mbedtls_ssl_conf_own_cert(get_ssl_config(), _clicert, &_pkctx)) != 0) {
|
||||
print_mbedtls_error("mbedtls_ssl_conf_own_cert", ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
mbedtls_x509_crt *TLSSocketWrapper::get_ca_chain()
|
||||
{
|
||||
return _cacert;
|
||||
}
|
||||
|
||||
void TLSSocketWrapper::set_ca_chain(mbedtls_x509_crt *crt)
|
||||
{
|
||||
if (_cacert && _cacert_allocated) {
|
||||
mbedtls_x509_crt_free(_cacert);
|
||||
delete _cacert;
|
||||
_cacert_allocated = false;
|
||||
}
|
||||
_cacert = crt;
|
||||
tr_info("mbedtls_ssl_conf_ca_chain()");
|
||||
mbedtls_ssl_conf_ca_chain(get_ssl_config(), _cacert, NULL);
|
||||
}
|
||||
|
||||
mbedtls_ssl_config *TLSSocketWrapper::get_ssl_config()
|
||||
{
|
||||
if (!_ssl_conf) {
|
||||
int ret;
|
||||
_ssl_conf = new mbedtls_ssl_config;
|
||||
mbedtls_ssl_config_init(_ssl_conf);
|
||||
_ssl_conf_allocated = true;
|
||||
|
||||
tr_info("mbedtls_ssl_config_defaults()");
|
||||
if ((ret = mbedtls_ssl_config_defaults(_ssl_conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
print_mbedtls_error("mbedtls_ssl_config_defaults", ret);
|
||||
set_ssl_config(NULL);
|
||||
MBED_ERROR( MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_OUT_OF_MEMORY), "mbedtls_ssl_config_defaults() failed" );
|
||||
return NULL;
|
||||
}
|
||||
/* It is possible to disable authentication by passing
|
||||
* MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode()
|
||||
*/
|
||||
tr_info("mbedtls_ssl_conf_authmode()");
|
||||
mbedtls_ssl_conf_authmode(get_ssl_config(), MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
}
|
||||
return _ssl_conf;
|
||||
}
|
||||
|
||||
void TLSSocketWrapper::set_ssl_config(mbedtls_ssl_config *conf)
|
||||
{
|
||||
if (_ssl_conf && _ssl_conf_allocated) {
|
||||
mbedtls_ssl_config_free(_ssl_conf);
|
||||
delete _ssl_conf;
|
||||
_ssl_conf_allocated = false;
|
||||
}
|
||||
_ssl_conf = conf;
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::close()
|
||||
{
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
tr_info("Closing TLS");
|
||||
|
||||
int ret = 0;
|
||||
if (_handshake_completed) {
|
||||
_transport->set_blocking(true);
|
||||
ret = mbedtls_ssl_close_notify(&_ssl);
|
||||
if (ret) {
|
||||
print_mbedtls_error("mbedtls_ssl_close_notify", ret);
|
||||
}
|
||||
_handshake_completed = false;
|
||||
}
|
||||
|
||||
if (_close_transport) {
|
||||
int ret2 = _transport->close();
|
||||
if (!ret) {
|
||||
ret = ret2;
|
||||
}
|
||||
}
|
||||
|
||||
_transport = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::connect(const SocketAddress &address)
|
||||
{
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if (_connect_transport) {
|
||||
nsapi_error_t ret = _transport->connect(address);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return do_handshake();
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::bind(const SocketAddress &address)
|
||||
{
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
return _transport->bind(address);
|
||||
}
|
||||
|
||||
void TLSSocketWrapper::set_blocking(bool blocking)
|
||||
{
|
||||
if (!_transport) {
|
||||
return;
|
||||
}
|
||||
_transport->set_blocking(blocking);
|
||||
}
|
||||
|
||||
void TLSSocketWrapper::set_timeout(int timeout)
|
||||
{
|
||||
if (!_transport) {
|
||||
return;
|
||||
}
|
||||
_transport->set_timeout(timeout);
|
||||
}
|
||||
|
||||
void TLSSocketWrapper::sigio(mbed::Callback<void()> func)
|
||||
{
|
||||
if (!_transport) {
|
||||
return;
|
||||
}
|
||||
// Allow sigio() to propagate to upper level and handle errors on recv() and send()
|
||||
_transport->sigio(func);
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::setsockopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
return _transport->setsockopt(level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::getsockopt(int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
if (!_transport) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
return _transport->getsockopt(level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
Socket *TLSSocketWrapper::accept(nsapi_error_t *err)
|
||||
{
|
||||
if (err) {
|
||||
*err = NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsapi_error_t TLSSocketWrapper::listen(int)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
#endif /* MBEDTLS_SSL_CLI_C */
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License 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.
|
||||
*/
|
||||
|
||||
#ifndef _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
|
||||
#define _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
|
||||
|
||||
#include "netsocket/Socket.h"
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
|
||||
// This class requires Mbed TLS SSL/TLS client code
|
||||
#if defined(MBEDTLS_SSL_CLI_C)
|
||||
|
||||
/**
|
||||
* \brief TLSSocket a wrapper around Socket for interacting with TLS servers
|
||||
*/
|
||||
class TLSSocketWrapper : public Socket {
|
||||
public:
|
||||
enum control_transport {
|
||||
TRANSPORT_KEEP,
|
||||
TRANSPORT_CONNECT_AND_CLOSE,
|
||||
TRANSPORT_CONNECT,
|
||||
TRANSPORT_CLOSE,
|
||||
};
|
||||
|
||||
/* Create a TLSSocketWrapper
|
||||
*
|
||||
* @param transport Underlying transport socket to wrap
|
||||
* @param hostname Hostname of the remote host, used for certificate checking
|
||||
*/
|
||||
TLSSocketWrapper(Socket *transport, const char *hostname = NULL, control_transport control = TRANSPORT_CONNECT_AND_CLOSE);
|
||||
|
||||
/** Destroy a socket wrapper
|
||||
*
|
||||
* Closes socket wrapper if the socket wrapper is still open
|
||||
*/
|
||||
virtual ~TLSSocketWrapper();
|
||||
|
||||
/** Set hostname.
|
||||
*
|
||||
* TLSSocket requires hostname that is used to verify the certificate.
|
||||
* If hostname is not given in constructor, this function must be used before
|
||||
* starting the TLS handshake.
|
||||
*/
|
||||
void set_hostname(const char *hostname);
|
||||
|
||||
/** Sets the certification of Root CA.
|
||||
*
|
||||
* @param root_ca Root CA Certificate in any mbed-TLS supported format.
|
||||
* @param len Length of certificate (including terminating 0 for PEM).
|
||||
*/
|
||||
nsapi_error_t set_root_ca_cert(const void *root_ca, size_t len);
|
||||
|
||||
/** Sets the certification of Root CA.
|
||||
*
|
||||
* @param root_ca_pem Root CA Certificate in PEM format
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
nsapi_error_t set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem);
|
||||
|
||||
/** Send data over a TLS socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes sent from the buffer.
|
||||
*
|
||||
* @param data Buffer of data to send to the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of sent bytes on success, negative error
|
||||
* code on failure
|
||||
*/
|
||||
virtual nsapi_error_t send(const void *data, nsapi_size_t size);
|
||||
|
||||
/** Receive data over a TLS socket
|
||||
*
|
||||
* The socket must be connected to a remote host. Returns the number of
|
||||
* bytes received into the buffer.
|
||||
*
|
||||
* @param data Destination buffer for data received from the host
|
||||
* @param size Size of the buffer in bytes
|
||||
* @return Number of received bytes on success, negative error
|
||||
* code on failure. If no data is available to be received
|
||||
* and the peer has performed an orderly shutdown,
|
||||
* recv() returns 0.
|
||||
*/
|
||||
virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size);
|
||||
|
||||
/* = Functions inherited from Socket = */
|
||||
virtual nsapi_error_t close();
|
||||
virtual nsapi_error_t connect(const SocketAddress &address = SocketAddress());
|
||||
virtual nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size);
|
||||
virtual nsapi_size_or_error_t recvfrom(SocketAddress *address,
|
||||
void *data, nsapi_size_t size);
|
||||
virtual nsapi_error_t bind(const SocketAddress &address);
|
||||
virtual void set_blocking(bool blocking);
|
||||
virtual void set_timeout(int timeout);
|
||||
virtual void sigio(mbed::Callback<void()> func);
|
||||
virtual nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen);
|
||||
virtual nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen);
|
||||
virtual Socket *accept(nsapi_error_t *error = NULL);
|
||||
virtual nsapi_error_t listen(int backlog = 1);
|
||||
|
||||
/** Get own certificate directly from Mbed TLS
|
||||
* @return internal Mbed TLS X509 structure
|
||||
*/
|
||||
mbedtls_x509_crt *get_own_cert();
|
||||
|
||||
/** Set own certificate directly to Mbed TLS
|
||||
* @param crt Mbed TLS X509 certificate chain.
|
||||
* @return error code from mbedtls_ssl_conf_own_cert()
|
||||
*/
|
||||
int set_own_cert(mbedtls_x509_crt *crt);
|
||||
|
||||
/** Get CA chain structure.
|
||||
* @return Mbed TLS X509 certificate chain.
|
||||
*/
|
||||
mbedtls_x509_crt *get_ca_chain();
|
||||
|
||||
/** Set CA chain directly to Mbed TLS
|
||||
* @param crt Mbed TLS X509 certificate chain.
|
||||
*/
|
||||
void set_ca_chain(mbedtls_x509_crt *crt);
|
||||
|
||||
/** Get internal Mbed TLS configuration structure
|
||||
* @return Mbed TLS SSL config
|
||||
*/
|
||||
mbedtls_ssl_config *get_ssl_config();
|
||||
|
||||
/** Override Mbed TLS configuration.
|
||||
* @param conf Mbed TLS SSL configuration structure
|
||||
*/
|
||||
void set_ssl_config(mbedtls_ssl_config *conf);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Helper for pretty-printing mbed TLS error codes
|
||||
*/
|
||||
static void print_mbedtls_error(const char *name, int err);
|
||||
|
||||
/** Initiates TLS Handshake
|
||||
*
|
||||
* Initiates a TLS hanshake to a remote speer
|
||||
* Underlying transport socket should already be connected
|
||||
*
|
||||
* Root CA certification must be set by set_ssl_ca_pem() before
|
||||
* call this function.
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
nsapi_error_t do_handshake();
|
||||
|
||||
#if MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0
|
||||
/**
|
||||
* Debug callback for mbed TLS
|
||||
* Just prints on the USB serial port
|
||||
*/
|
||||
static void my_debug(void *ctx, int level, const char *file, int line,
|
||||
const char *str);
|
||||
|
||||
/**
|
||||
* Certificate verification callback for mbed TLS
|
||||
* Here we only use it to display information on each cert in the chain
|
||||
*/
|
||||
static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags);
|
||||
|
||||
#endif /* MBED_CONF_TLS_SOCKET_DEBUG_LEVEL > 0 */
|
||||
|
||||
/**
|
||||
* Receive callback for Mbed TLS
|
||||
*/
|
||||
static int ssl_recv(void *ctx, unsigned char *buf, size_t len);
|
||||
|
||||
/**
|
||||
* Send callback for Mbed TLS
|
||||
*/
|
||||
static int ssl_send(void *ctx, const unsigned char *buf, size_t len);
|
||||
|
||||
private:
|
||||
mbedtls_ssl_context _ssl;
|
||||
mbedtls_pk_context _pkctx;
|
||||
mbedtls_ctr_drbg_context _ctr_drbg;
|
||||
mbedtls_entropy_context _entropy;
|
||||
|
||||
Socket *_transport;
|
||||
|
||||
mbedtls_x509_crt* _cacert;
|
||||
mbedtls_x509_crt* _clicert;
|
||||
mbedtls_ssl_config* _ssl_conf;
|
||||
|
||||
bool _connect_transport:1;
|
||||
bool _close_transport:1;
|
||||
bool _handshake_completed:1;
|
||||
bool _cacert_allocated:1;
|
||||
bool _clicert_allocated:1;
|
||||
bool _ssl_conf_allocated:1;
|
||||
|
||||
};
|
||||
|
||||
#endif /* MBEDTLS_SSL_CLI_C */
|
||||
#endif // _MBED_HTTPS_TLS_SOCKET_WRAPPER_H_
|
Loading…
Reference in New Issue