|
| 1 | +## Secure Socket |
| 2 | + |
| 3 | +Mbed OS provides an interface for creating secure connections in the form of TLS stream. The `TLSSocketWrapper` class gives you the ability to secure any stream-based socket connection, for example TCP stream. This allows you to use existing protocol libraries through secure connections. |
| 4 | + |
| 5 | +`TLSSocketWrapper` inherits the `Socket` class, which allows any application that uses `Socket` to use `TLSSocketWrapper` instead. Secure socket both uses the Socket interface as its transport layer and implements it. This makes it transport independent, and there is no direct dependency on the IP stack. For example, you can use the HTTP library and give `TLSSocketWrapper` to it to covert it to HTTPS. |
| 6 | + |
| 7 | +The helper class called `TLSSocket` contains internal TCP socket for transport stream. |
| 8 | + |
| 9 | +### Usage example |
| 10 | + |
| 11 | +`TLSSocketWrapper` implements the Mbed OS Socket API and extends it with functions that allow configuring security certificates, so it is straightforward to use after setting up. Please note that for most of the use cases, you are using these methods through `TLSSocket` class: |
| 12 | + |
| 13 | +``` |
| 14 | +TLSSocket *socket = new TLSSocket(); |
| 15 | +socket->open(network) |
| 16 | +socket->set_root_ca_cert(certificate); |
| 17 | +
|
| 18 | +socket->connect(HOST_NAME, PORT) |
| 19 | +
|
| 20 | +socket->send(data, size); |
| 21 | +``` |
| 22 | + |
| 23 | +Please note that internal TLS structures require over 1 kB of RAM, so you need to allocate each TLSSocket from the heap by using the `new` command, instead of using stack or statically allocating it. |
| 24 | + |
| 25 | +### Design |
| 26 | + |
| 27 | +Internally `TLSSocket` consists of two classes, `TLSSocketWrapper` and `TLSSocket`, as shown in the following diagram: |
| 28 | + |
| 29 | +<span class="images"><span>TLSSocket UML</span></span> |
| 30 | + |
| 31 | +The `TLSSocketWrapper` can use any `Socket` as its transport. `TLSSocket` is a helper that uses directly `TCPSocket` for its transport, so you can adopt existing TCP based applications to TLS. |
| 32 | + |
| 33 | +One use case of `TLSSocketWrapper` is that you can upgrade the existing TCP socket to TLS, by wrapping it like this: |
| 34 | + |
| 35 | +``` |
| 36 | +TCPSocket connection; |
| 37 | +connection.open(net); |
| 38 | +connection.connect(SERVER, PORT); |
| 39 | +
|
| 40 | +// First talk with the server without encryption |
| 41 | +connection.send("STARTTLS\r\n", 10); |
| 42 | +
|
| 43 | +// Wrap the TCP into TLS object |
| 44 | +TLSSocketWrapper tls = new TLSSocketWrapper(connection, SERVER, TLSSocketWrapper::TRANSPORT_CLOSE); |
| 45 | +
|
| 46 | +// Initiate TLS handshake |
| 47 | +tls.connect(); |
| 48 | +
|
| 49 | +// Now the secure connection can be used like regular socket |
| 50 | +tls.send("HELLO", 5); |
| 51 | +``` |
| 52 | + |
| 53 | +#### Configuring certificates |
| 54 | + |
| 55 | +`TLSSocketWrapper` provides the following API to set server certificate. You can use either BASE64 formatted PEM certificate or binary DER certificates. The latter form of these functions assumes `root_ca_pem` or `client_cert_pem` to be standard C string, counts its length and passes to method, which takes only `void*` and `len`. |
| 56 | + |
| 57 | +``` |
| 58 | +/** Sets the certification of Root CA. |
| 59 | + * |
| 60 | + * @param root_ca Root CA Certificate in any mbed-TLS supported format. |
| 61 | + * @param len Length of certificate (including terminating 0 for PEM). |
| 62 | + */ |
| 63 | +nsapi_error_t TLSSocketWrapper::set_root_ca_cert(const void *root_ca, size_t len); |
| 64 | +
|
| 65 | +/** Sets the certification of Root CA. |
| 66 | + * |
| 67 | + * @param root_ca_pem Root CA Certificate in PEM format |
| 68 | + */ |
| 69 | +nsapi_error_t TLSSocketWrapper::set_root_ca_cert(const char *root_ca_pem); |
| 70 | +``` |
| 71 | + |
| 72 | +If client authentication is required, the following API allows you to set the client certificate and private key: |
| 73 | + |
| 74 | +``` |
| 75 | +/** Sets client certificate, and client private key. |
| 76 | + * |
| 77 | + * @param client_cert Client certification in any mbed-TLS supported format. |
| 78 | + * @param client_private_key Client private key in PEM format. |
| 79 | + */ |
| 80 | +nsapi_error_t TLSSocketWrapper::set_client_cert_key(const void *client_cert_pem, size_t client_cert_len, |
| 81 | + const void *client_private_key_pem, size_t client_private_key_len); |
| 82 | +
|
| 83 | +/** Sets client certificate, and client private key. |
| 84 | + * |
| 85 | + * @param client_cert_pem Client certification in PEM format. |
| 86 | + * @param client_private_key Client private key in PEM format. |
| 87 | + */ |
| 88 | +nsapi_error_t TLSSocketWrapper::set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem); |
| 89 | +``` |
| 90 | + |
| 91 | +#### Socket API |
| 92 | + |
| 93 | +`TLSSocketWrapper` implements the [Mbed OS Socket API](../apis/network-socket.html): |
| 94 | + |
| 95 | +``` |
| 96 | +virtual nsapi_error_t close(); |
| 97 | +``` |
| 98 | + |
| 99 | +This destroys the memory the TLS library allocates. It also closes the transport socket, unless [transport mode](#transport-modes) is set to `TRANSPORT_KEEP` or `TRANSPORT_CONNECT`: |
| 100 | + |
| 101 | +``` |
| 102 | +virtual nsapi_error_t connect(const SocketAddress &address); |
| 103 | +``` |
| 104 | + |
| 105 | +The code above initiates the TCP connection and continues to TLS hanshake. If [transport mode](#transport-modes) is either `TRANSPORT_KEEP` or `TRANSPORT_CLOSE`, TCP is assumed to be open and state directly goes into TLS handshake. This is currently forced to blocking mode. After succesfully connecting, you can set it to nonblocking mode: |
| 106 | + |
| 107 | +``` |
| 108 | +virtual nsapi_size_or_error_t send(const void *data, nsapi_size_t size); |
| 109 | +virtual nsapi_size_or_error_t recv(void *data, nsapi_size_t size); |
| 110 | +virtual nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size); |
| 111 | +virtual nsapi_size_or_error_t recvfrom(SocketAddress *address, void *data, nsapi_size_t size); |
| 112 | +``` |
| 113 | + |
| 114 | +These work as expected, but `SocketAddress` parameters are ignored. The TLS connection cannot change the peer. Also, `recvfrom()` call does not set the peer address. |
| 115 | + |
| 116 | +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. |
| 117 | + |
| 118 | +`MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY` is ignored, and zero is returned to you (connection closed). Other error codes are passed through: |
| 119 | + |
| 120 | +``` |
| 121 | +virtual nsapi_error_t bind(const SocketAddress &address); |
| 122 | +virtual void set_blocking(bool blocking); |
| 123 | +virtual void set_timeout(int timeout); |
| 124 | +virtual void sigio(mbed::Callback<void()> func); |
| 125 | +virtual nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen); |
| 126 | +virtual nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen); |
| 127 | +``` |
| 128 | + |
| 129 | +These are passed through to transport socket. |
| 130 | + |
| 131 | +``` |
| 132 | +virtual Socket *accept(nsapi_error_t *error = NULL); |
| 133 | +virtual nsapi_error_t listen(int backlog = 1); |
| 134 | +``` |
| 135 | + |
| 136 | +These are returning `NSAPI_ERROR_UNSUPPORTED` as you can't set TLS socket to listening mode. |
| 137 | + |
| 138 | +#### Transport modes |
| 139 | + |
| 140 | +`TLSSocketWrapper` has four modes that are given in the constructor and affect how the transport Socket is used in connection and closing phases: |
| 141 | + |
| 142 | +|Mode|Behavior on trasport socket| |
| 143 | +|----|----------------------------| |
| 144 | +|TRANSPORT_KEEP | Keep the transport as it is. Does not call `connect()` or `close()` methods. | |
| 145 | +|TRANSPORT_CONNECT_AND_CLOSE | Both `connect()` and `close()` are called. (default) | |
| 146 | +|TRANSPORT_CONNECT | Call `connect()`, but do not close the connection when finished. | |
| 147 | +|TRANSPORT_CLOSE | Call `close()` when connection is finished. | |
| 148 | + |
| 149 | +The default mode is `TRANSPORT_CONNECT_AND_CLOSE`. |
| 150 | + |
| 151 | +#### Advanced use: using internal Mbed TLS structures |
| 152 | + |
| 153 | +You may choose to use internal Mbed TLS structures to configure the TLS instance. This is supported by exposing some Mbed TLS structures like this: |
| 154 | + |
| 155 | +``` |
| 156 | +mbedtls_x509_crt *get_own_cert(); |
| 157 | +int set_own_cert(mbedtls_x509_crt *); |
| 158 | +mbedtls_x509_crt *get_ca_chain(); |
| 159 | +void set_ca_chain(mbedtls_x509_crt *); |
| 160 | +mbedtls_ssl_config *get_ssl_config(); |
| 161 | +void set_ssl_config(mbedtls_ssl_config *); |
| 162 | +``` |
| 163 | + |
| 164 | +For guidance of how to use these, please refer to the [Mbed TLS documentation](../apis/tls.html). |
| 165 | + |
| 166 | +## Related content |
| 167 | + |
| 168 | +- [Security overview](../apis/security.html). |
| 169 | +- [TLSSocket](../apis/tlssocket.html) API reference. |
| 170 | +- [DTLSSocket](../apis/dtlssocket.html) API reference. |
0 commit comments