diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp index da7248fab6..6e5e5d8e2c 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp @@ -91,7 +91,15 @@ class SSLContext void connect(ClientContext* ctx, const char* hostName, uint32_t timeout_ms) { s_io_ctx = ctx; - _ssl = ssl_client_new(_ssl_ctx, 0, nullptr, 0, hostName); + _ssl_ext = ssl_ext_new(); + + int name_len = strlen(hostName); + + _ssl_ext->host_name = (char*) malloc((name_len + 1) * sizeof (char)); + strncpy(_ssl_ext->host_name, hostName, name_len + 1); + _ssl_ext->host_name[name_len] = 0; + + _ssl = ssl_client_new(_ssl_ctx, 0, nullptr, 0, _ssl_ext); uint32_t t = millis(); while (millis() - t < timeout_ms && ssl_handshake_status(_ssl) != SSL_OK) { @@ -112,6 +120,11 @@ class SSLContext { return _ssl != nullptr && ssl_handshake_status(_ssl) == SSL_OK; } + + void discardCache() { + _available = 0; + _read_ptr = nullptr; + } int read(uint8_t* dst, size_t size) { @@ -179,6 +192,14 @@ class SSLContext } return cb; } + + bool wantRead() { + return _available > 0 || (_ssl && ssl_want_read(_ssl) == 1); + } + + bool emptyCache() { + return _available == 0; + } bool loadObject(int type, Stream& stream, size_t size) { @@ -245,6 +266,7 @@ class SSLContext static SSL_CTX* _ssl_ctx; static int _ssl_ctx_refcnt; SSL* _ssl = nullptr; + SSL_EXTENSIONS* _ssl_ext = nullptr; int _refcnt = 0; const uint8_t* _read_ptr = nullptr; size_t _available = 0; @@ -332,7 +354,14 @@ size_t WiFiClientSecure::write(const uint8_t *buf, size_t size) if (!_ssl) { return 0; } - + + // axTLS is half-duplex so if a read operation is already underway, + // finish the read before trying to write; otherwise the read + // cache will be overwritten and data will be lost + if (!_ssl->emptyCache()) { + return SSL_ERROR_READ_LOCK; + } + int rc = ssl_write(*_ssl, buf, size); if (rc >= 0) { return rc; @@ -346,6 +375,20 @@ size_t WiFiClientSecure::write(const uint8_t *buf, size_t size) return 0; } +int WiFiClientSecure::wantRead() { + if (_ssl) { + return _ssl->wantRead(); + } + + return 0; +} + +void WiFiClientSecure::discardCache() { + if (_ssl) { + _ssl->discardCache(); + } +} + int WiFiClientSecure::read(uint8_t *buf, size_t size) { if (!_ssl) { @@ -420,7 +463,7 @@ err x N N uint8_t WiFiClientSecure::connected() { if (_ssl) { - if (_ssl->available()) { + if (_ssl->wantRead()) { return true; } if (_client && _client->state() == ESTABLISHED && _ssl->connected()) { @@ -595,6 +638,20 @@ bool WiFiClientSecure::loadPrivateKey(Stream& stream, size_t size) return _ssl->loadObject(SSL_OBJ_RSA_KEY, stream, size); } +extern "C" int __ax_port_pending(int fd) { + //Serial.println("ax_port_pending"); + ClientContext* _client = SSLContext::getIOContext(fd); + if (!_client || _client->state() != ESTABLISHED && !_client->getSize()) { + errno = EIO; + return -1; + } + + //Serial.printf("pending: %d\r\n", _client->getSize()); + return _client->getSize(); +} + +extern "C" void ax_port_pending() __attribute__ ((weak, alias("__ax_port_pending"))); + extern "C" int __ax_port_read(int fd, uint8_t* buffer, size_t count) { ClientContext* _client = SSLContext::getIOContext(fd); diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecure.h b/libraries/ESP8266WiFi/src/WiFiClientSecure.h index 4b5b9c9343..1dce858872 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecure.h +++ b/libraries/ESP8266WiFi/src/WiFiClientSecure.h @@ -25,6 +25,7 @@ #include "WiFiClient.h" #include "include/ssl.h" +#define SSL_ERROR_READ_LOCK -275 class SSLContext; @@ -49,6 +50,9 @@ class WiFiClientSecure : public WiFiClient { int peek() override; size_t peekBytes(uint8_t *buffer, size_t length) override; void stop() override; + + void discardCache(); + int wantRead(); bool setCACert(const uint8_t* pk, size_t size); bool setCertificate(const uint8_t* pk, size_t size); diff --git a/libraries/ESP8266WiFi/src/include/ssl.h b/libraries/ESP8266WiFi/src/include/ssl.h index f23d86af3a..2761c588b8 100644 --- a/libraries/ESP8266WiFi/src/include/ssl.h +++ b/libraries/ESP8266WiFi/src/include/ssl.h @@ -1,11 +1,12 @@ /* - * Copyright (c) 2007, Cameron Rich - * + * Copyright (c) 2007-2016, Cameron Rich + * Copyright (c) 2017, Diego Guerrero (ssl_want_write) + * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without + * + * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, @@ -72,10 +73,15 @@ extern "C" { #define EXP_FUNC #define STDCALL -// struct SSL_CTX_; + typedef struct SSL_CTX_ SSL_CTX; typedef struct SSL_ SSL; +typedef struct { + char *host_name; /* Needed for the SNI support */ + uint16_t max_fragment_size; /* Needed for the Max Fragment Size Extension. Allowed values: 2^9, 2^10 .. 2^14 */ +} SSL_EXTENSIONS; + /* The optional parameters that can be given to the client/server SSL engine */ #define SSL_CLIENT_AUTHENTICATION 0x00010000 #define SSL_SERVER_VERIFY_LATER 0x00020000 @@ -93,13 +99,16 @@ typedef struct SSL_ SSL; #define SSL_ERROR_DEAD -2 #define SSL_CLOSE_NOTIFY -3 #define SSL_ERROR_CONN_LOST -256 +#define SSL_ERROR_RECORD_OVERFLOW -257 #define SSL_ERROR_SOCK_SETUP_FAILURE -258 #define SSL_ERROR_INVALID_HANDSHAKE -260 #define SSL_ERROR_INVALID_PROT_MSG -261 #define SSL_ERROR_INVALID_HMAC -262 #define SSL_ERROR_INVALID_VERSION -263 +#define SSL_ERROR_UNSUPPORTED_EXTENSION -264 #define SSL_ERROR_INVALID_SESSION -265 #define SSL_ERROR_NO_CIPHER -266 +#define SSL_ERROR_INVALID_CERT_HASH_ALG -267 #define SSL_ERROR_BAD_CERTIFICATE -268 #define SSL_ERROR_INVALID_KEY -269 #define SSL_ERROR_FINISHED_INVALID -271 @@ -117,19 +126,25 @@ typedef struct SSL_ SSL; #define SSL_ALERT_CLOSE_NOTIFY 0 #define SSL_ALERT_UNEXPECTED_MESSAGE 10 #define SSL_ALERT_BAD_RECORD_MAC 20 +#define SSL_ALERT_RECORD_OVERFLOW 22 #define SSL_ALERT_HANDSHAKE_FAILURE 40 #define SSL_ALERT_BAD_CERTIFICATE 42 +#define SSL_ALERT_UNSUPPORTED_CERTIFICATE 43 +#define SSL_ALERT_CERTIFICATE_EXPIRED 45 +#define SSL_ALERT_CERTIFICATE_UNKNOWN 46 #define SSL_ALERT_ILLEGAL_PARAMETER 47 +#define SSL_ALERT_UNKNOWN_CA 48 #define SSL_ALERT_DECODE_ERROR 50 #define SSL_ALERT_DECRYPT_ERROR 51 #define SSL_ALERT_INVALID_VERSION 70 #define SSL_ALERT_NO_RENEGOTIATION 100 +#define SSL_ALERT_UNSUPPORTED_EXTENSION 110 /* The ciphers that are supported */ #define SSL_AES128_SHA 0x2f #define SSL_AES256_SHA 0x35 -#define SSL_RC4_128_SHA 0x05 -#define SSL_RC4_128_MD5 0x04 +#define SSL_AES128_SHA256 0x3c +#define SSL_AES256_SHA256 0x3d /* build mode ids' */ #define SSL_BUILD_SKELETON_MODE 0x01 @@ -218,6 +233,22 @@ EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions); */ EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx); +/** + * @brief Allocates new SSL extensions structure and returns pointer to it + * + * @return ssl_ext Pointer to SSL_EXTENSIONS structure + * + */ +EXP_FUNC SSL_EXTENSIONS * STDCALL ssl_ext_new(); + +/** + * @brief Frees SSL extensions structure + * + * @param ssl_ext [in] Pointer to SSL_EXTENSION structure + * + */ +EXP_FUNC void STDCALL ssl_ext_free(SSL_EXTENSIONS *ssl_ext); + /** * @brief (server only) Establish a new SSL connection to an SSL client. * @@ -244,11 +275,11 @@ EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd); * can be null if no session resumption is being used or required. This option * is not used in skeleton mode. * @param sess_id_size The size of the session id (max 32) - * @param host_name If non-zero, host name to be sent to server for SNI support - * @return An SSL object reference. Use ssl_handshake_status() to check + * @param ssl_ext pointer to a structure with the activated SSL extensions and their values + * @return An SSL object reference. Use ssl_handshake_status() to check * if a handshake succeeded. */ -EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size, const char* host_name); +EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size, SSL_EXTENSIONS* ssl_ext); /** * @brief Free any used resources on this connection. @@ -259,6 +290,19 @@ EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uin */ EXP_FUNC void STDCALL ssl_free(SSL *ssl); +/** + * @brief Check the rx buffer for new information. + * If the socket has new information to be read, 1 will be returned. + * Cheap alternative to check availability without actually decrypting. + * @param ssl [in] An SSL object reference. + * @return Read status: + * - if == 1, then there are bytes to be read, + * - if == 0, then there are not, + * - if < 0, there was an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_want_read(SSL *ssl); + /** * @brief Read the SSL data stream. * If the socket is non-blocking and data is blocked then SSO_OK will be @@ -289,6 +333,15 @@ EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data); */ EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len); +/** + * @brief Calculate the size of the encrypted data from what you are about to send + * @param ssl [in] An SSL obect reference. + * @param out_len [in] The number of bytes to be written. + * @return The number of bytes that will be sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_calculate_write_length(SSL *ssl, int out_len); + /** * @brief Find an ssl object based on a file descriptor. * @@ -367,7 +420,7 @@ EXP_FUNC void STDCALL ssl_display_error(int error_code); /** * @brief Authenticate a received certificate. - * + * * This call is usually made by a client after a handshake is complete and the * context is in SSL_SERVER_VERIFY_LATER mode. * @param ssl [in] An SSL object reference. @@ -385,8 +438,17 @@ EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl); EXP_FUNC int STDCALL ssl_match_fingerprint(const SSL *ssl, const uint8_t* fp); /** - * @brief Retrieve an X.509 distinguished name component. + * @brief Check if SHA256 hash of Subject Public Key Info matches the one given. * + * @param ssl [in] An SSL object reference. + * @param fp [in] SHA256 hash to match against + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_match_spki_sha256(const SSL *ssl, const uint8_t* hash); + +/** + * @brief Retrieve an X.509 distinguished name component. + * * When a handshake is complete and a certificate has been exchanged, then the * details of the remote certificate can be retrieved. * diff --git a/tools/sdk/lib/libaxtls.a b/tools/sdk/lib/libaxtls.a index 8abb83ee7e..66c99c9eca 100644 Binary files a/tools/sdk/lib/libaxtls.a and b/tools/sdk/lib/libaxtls.a differ