Unverified Commit 15bbd0a1 authored by Anthony Elder's avatar Anthony Elder Committed by GitHub

Add ALPN support to WiFiClientSecure (#5633)

This adds a function to WiFiClientSecure to set the ALPN protocol.

This is required for an MQTT client to connect to AWS IoT when using an AWS Custom Authorizer, as described here.

Example code snippet:

...
WiFiClientSecure wiFiClient;

// ALPN protocol, needed with AWS custom authorizer
const char *aws_protos[] = {"mqtt", NULL};

void setup() {
  wiFiClient.setCACert(AWSCAPEM);
  wiFiClient.setAlpnProtocols(aws_protos);
}
...
parent 02c3ec01
......@@ -66,3 +66,18 @@ To use PSK:
encryption for the connection
Please see the WiFiClientPSK example.
Specifying the ALPN Protocol
----------------------------
Application-Layer Protocol Negotiation (ALPN) is a Transport Layer Security (TLS) extension that allows
the application layer to negotiate which protocol should be performed over a secure connection in a manner
that avoids additional round trips and which is independent of the application-layer protocols.
For example, this is used with AWS IoT Custom Authorizers where an MQTT client must set the ALPN protocol to ```mqtt```:
```
const char *aws_protos[] = {"mqtt", NULL};
...
wiFiClient.setAlpnProtocols(aws_protos);
```
\ No newline at end of file
......@@ -29,6 +29,7 @@ connected KEYWORD2
setCACert KEYWORD2
setCertificate KEYWORD2
setPrivateKey KEYWORD2
setAlpnProtocols KEYWORD2
#######################################
# Constants (LITERAL1)
......
......@@ -43,6 +43,7 @@ WiFiClientSecure::WiFiClientSecure()
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
_alpn_protos = NULL;
}
......@@ -66,6 +67,7 @@ WiFiClientSecure::WiFiClientSecure(int sock)
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
_alpn_protos = NULL;
}
WiFiClientSecure::~WiFiClientSecure()
......@@ -127,7 +129,7 @@ int WiFiClientSecure::connect(const char *host, uint16_t port, const char *CA_ce
if(_timeout > 0){
sslclient->handshake_timeout = _timeout;
}
int ret = start_ssl_client(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure);
int ret = start_ssl_client(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure, _alpn_protos);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
......@@ -147,7 +149,7 @@ int WiFiClientSecure::connect(const char *host, uint16_t port, const char *pskId
if(_timeout > 0){
sslclient->handshake_timeout = _timeout;
}
int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure);
int ret = start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure, _alpn_protos);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
......@@ -341,3 +343,8 @@ void WiFiClientSecure::setHandshakeTimeout(unsigned long handshake_timeout)
{
sslclient->handshake_timeout = handshake_timeout * 1000;
}
void WiFiClientSecure::setAlpnProtocols(const char **alpn_protos)
{
_alpn_protos = alpn_protos;
}
......@@ -39,6 +39,7 @@ protected:
const char *_private_key;
const char *_pskIdent; // identity for PSK cipher suites
const char *_psKey; // key in hex for PSK cipher suites
const char **_alpn_protos;
public:
WiFiClientSecure *next;
......@@ -73,6 +74,7 @@ public:
bool loadPrivateKey(Stream& stream, size_t size);
bool verify(const char* fingerprint, const char* domain_name);
void setHandshakeTimeout(unsigned long handshake_timeout);
void setAlpnProtocols(const char **alpn_protos);
const mbedtls_x509_crt* getPeerCertificate() { return mbedtls_ssl_get_peer_cert(&sslclient->ssl_ctx); };
bool getFingerprintSHA256(uint8_t sha256_result[32]) { return get_peer_fingerprint(sslclient, sha256_result); };
int setTimeout(uint32_t seconds){ return 0; }
......
......@@ -51,7 +51,7 @@ void ssl_init(sslclient_context *ssl_client)
}
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure)
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure, const char **alpn_protos)
{
char buf[512];
int ret, flags;
......@@ -156,6 +156,13 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p
return handle_error(ret);
}
if (alpn_protos != NULL) {
log_v("Setting ALPN protocols");
if ((ret = mbedtls_ssl_conf_alpn_protocols(&ssl_client->ssl_conf, alpn_protos) ) != 0) {
return handle_error(ret);
}
}
// MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and
// MBEDTLS_SSL_VERIFY_NONE if not.
......
......@@ -29,7 +29,7 @@ typedef struct sslclient_context {
void ssl_init(sslclient_context *ssl_client);
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure);
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure, const char **alpn_protos);
void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int data_to_read(sslclient_context *ssl_client);
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, size_t len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment