WIP: ESP-IDF Core 3 migration - mbedtls SSL, module library, board configs, MQTT and network updates

This commit is contained in:
proddy
2026-02-15 13:53:13 +01:00
parent e9f77c1bde
commit 6741232450
44 changed files with 29993 additions and 241 deletions

View File

@@ -5,7 +5,7 @@
},
"core": "esp32",
"extra_flags": [
"-DTASMOTA_SDK",
"-DNO_TLS_SUPPORT",
"-DARDUINO_LOLIN_C3_MINI",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_CDC_ON_BOOT=1"

View File

@@ -6,7 +6,7 @@
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DTASMOTA_SDK",
"-DNO_TLS_SUPPORT",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0"
],

View File

@@ -1,7 +1,7 @@
{
"build": {
"core": "esp32",
"extra_flags": "-DTASMOTA_SDK",
"extra_flags": "-DNO_TLS_SUPPORT",
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",

View File

@@ -1,7 +1,7 @@
{
"build": {
"core": "esp32",
"extra_flags": "-DTASMOTA_SDK",
"extra_flags": "-DNO_TLS_SUPPORT",
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",

View File

@@ -148,9 +148,7 @@
#elif defined(ARDUINO_ARCH_ESP32)
#include <driver/rtc_io.h>
#include <soc/gpio_struct.h>
#if ESP_IDF_VERSION_MAJOR >= 5
#include "soc/gpio_periph.h"
#endif // ESP_IDF_VERSION_MAJOR >= 5
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE uint32_t

View File

@@ -66,14 +66,10 @@ the LICENSE file.
#endif
#if EMC_USE_MEMPOOL
#ifndef EMC_NUM_POOL_ELEMENTS
#define EMC_NUM_POOL_ELEMENTS 32
#endif
#ifndef EMC_SIZE_POOL_ELEMENTS
#define EMC_SIZE_POOL_ELEMENTS 128
#endif
#ifndef EMC_NUM_POOL_ELEMENTS
#define EMC_NUM_POOL_ELEMENTS 32
#endif
#ifndef EMC_SIZE_POOL_ELEMENTS
#define EMC_SIZE_POOL_ELEMENTS 128
#endif
#ifndef TASMOTA_SDK
#define EMC_CLIENT_SECURE
#endif

View File

@@ -6,66 +6,154 @@ For a copy, see <https://opensource.org/licenses/MIT> or
the LICENSE file.
*/
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#include "ClientSecureSync.h"
#include <lwip/sockets.h> // socket options
#include "mbedtls_ssl.h" // triggers compilation of mbedtls SSL module (stripped from Tasmota libmbedtls.a)
#include <cstring>
#include <lwip/sockets.h>
#include <fcntl.h>
namespace espMqttClientInternals {
ClientSecureSync::ClientSecureSync()
: client() {
// empty
: _tls(nullptr)
, _cfg{}
, _connected(false) {
}
ClientSecureSync::~ClientSecureSync() {
stop();
}
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
if (ret) {
#if defined(ARDUINO_ARCH_ESP8266)
client.setNoDelay(true);
#elif defined(ARDUINO_ARCH_ESP32)
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
int val = true;
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
#endif
char host[16];
sprintf(host, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
return connect(host, port);
}
bool ClientSecureSync::connect(const char * host, uint16_t port) {
stop(); // clean up any previous connection
_tls = esp_tls_init();
if (!_tls) {
return false;
}
return ret;
}
bool ClientSecureSync::connect(const char* host, uint16_t port) {
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
if (ret) {
#if defined(ARDUINO_ARCH_ESP8266)
client.setNoDelay(true);
#elif defined(ARDUINO_ARCH_ESP32)
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
int val = true;
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
#endif
if (esp_tls_conn_new_sync(host, strlen(host), port, &_cfg, _tls) <= 0) {
esp_tls_conn_destroy(_tls);
_tls = nullptr;
return false;
}
_connected = true;
// Set TCP_NODELAY and non-blocking mode on the underlying socket
int fd = -1;
if (esp_tls_get_conn_sockfd(_tls, &fd) == ESP_OK && fd >= 0) {
int val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
// Make socket non-blocking so reads don't stall the MQTT event loop
int flags = fcntl(fd, F_GETFL, 0);
if (flags >= 0) {
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
}
return true;
}
size_t ClientSecureSync::write(const uint8_t * buf, size_t size) {
if (!_tls || !_connected) {
return 0;
}
// Write all data, retrying on WANT_WRITE (non-blocking socket)
size_t written = 0;
while (written < size) {
int ret = esp_tls_conn_write(_tls, buf + written, size - written);
if (ret > 0) {
written += ret;
} else if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ) {
continue; // retry
} else {
_connected = false;
break;
}
}
return written;
}
int ClientSecureSync::read(uint8_t * buf, size_t size) {
if (!_tls || !_connected) {
return -1;
}
int ret = esp_tls_conn_read(_tls, buf, size);
if (ret > 0) {
return ret;
}
size_t ClientSecureSync::write(const uint8_t* buf, size_t size) {
return client.write(buf, size);
}
int ClientSecureSync::read(uint8_t* buf, size_t size) {
return client.read(buf, size);
}
if (ret == ESP_TLS_ERR_SSL_WANT_READ || ret == ESP_TLS_ERR_SSL_WANT_WRITE) {
return -1; // no data available yet, still connected
}
// Connection closed or error
_connected = false;
return -1;
}
void ClientSecureSync::stop() {
client.stop();
if (_tls) {
esp_tls_conn_destroy(_tls);
_tls = nullptr;
}
_connected = false;
}
bool ClientSecureSync::connected() {
return client.connected();
return _connected && _tls != nullptr;
}
bool ClientSecureSync::disconnected() {
return !client.connected();
return !connected();
}
void ClientSecureSync::setCACert(const char * rootCA) {
_cfg.cacert_pem_buf = reinterpret_cast<const unsigned char *>(rootCA);
_cfg.cacert_pem_bytes = strlen(rootCA) + 1;
}
void ClientSecureSync::setCertificate(const char * clientCert) {
_cfg.clientcert_pem_buf = reinterpret_cast<const unsigned char *>(clientCert);
_cfg.clientcert_pem_bytes = strlen(clientCert) + 1;
}
void ClientSecureSync::setPrivateKey(const char * privateKey) {
_cfg.clientkey_pem_buf = reinterpret_cast<const unsigned char *>(privateKey);
_cfg.clientkey_pem_bytes = strlen(privateKey) + 1;
}
void ClientSecureSync::setPreSharedKey(const char * pskIdent, const char * psKey) {
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
_psk.hint = pskIdent;
size_t key_len = strlen(psKey) / 2;
if (key_len > sizeof(_psk_key)) {
key_len = sizeof(_psk_key);
}
for (size_t i = 0; i < key_len; i++) {
sscanf(psKey + 2 * i, "%2hhx", &_psk_key[i]);
}
_psk.key = _psk_key;
_psk.key_size = key_len;
_cfg.psk_hint_key = &_psk;
#endif
}
void ClientSecureSync::setInsecure() {
_cfg.cacert_pem_buf = nullptr;
_cfg.cacert_pem_bytes = 0;
_cfg.crt_bundle_attach = nullptr;
_cfg.use_global_ca_store = false;
_cfg.skip_common_name = true;
}
} // namespace espMqttClientInternals
#endif

View File

@@ -8,15 +8,8 @@ the LICENSE file.
#pragma once
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
// Added for EMS-ESP
#include "../Config.h"
#if defined(EMC_CLIENT_SECURE)
#include <WiFiClientSecure.h> // includes IPAddress
#else
#include <WiFiClient.h>
#endif
#include <IPAddress.h>
#include "esp_tls.h"
#include "Transport.h"
namespace espMqttClientInternals {
@@ -24,6 +17,7 @@ namespace espMqttClientInternals {
class ClientSecureSync : public Transport {
public:
ClientSecureSync();
~ClientSecureSync();
bool connect(IPAddress ip, uint16_t port) override;
bool connect(const char * host, uint16_t port) override;
size_t write(const uint8_t * buf, size_t size) override;
@@ -31,14 +25,22 @@ class ClientSecureSync : public Transport {
void stop() override;
bool connected() override;
bool disconnected() override;
// added for EMS-ESP
#if defined(EMC_CLIENT_SECURE)
WiFiClientSecure client;
#else
WiFiClient client;
// TLS configuration (call before connect)
void setCACert(const char * rootCA);
void setCertificate(const char * clientCert);
void setPrivateKey(const char * privateKey);
void setPreSharedKey(const char * pskIdent, const char * psKey);
void setInsecure();
private:
esp_tls_t * _tls;
esp_tls_cfg_t _cfg;
bool _connected;
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
psk_hint_key_t _psk;
unsigned char _psk_key[64];
#endif
};
} // namespace espMqttClientInternals
#endif

View File

@@ -78,36 +78,36 @@ espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
}
espMqttClientSecure & espMqttClientSecure::setInsecure() {
#if defined(EMC_CLIENT_SECURE)
_client.client.setInsecure();
#ifndef NO_TLS_SUPPORT
_client.setInsecure();
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setCACert(rootCA);
#ifndef NO_TLS_SUPPORT
_client.setCACert(rootCA);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setCertificate(clientCa);
#ifndef NO_TLS_SUPPORT
_client.setCertificate(clientCa);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setPrivateKey(privateKey);
#ifndef NO_TLS_SUPPORT
_client.setPrivateKey(privateKey);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setPreSharedKey(pskIdent, psKey);
#ifndef NO_TLS_SUPPORT
_client.setPreSharedKey(pskIdent, psKey);
#endif
return *this;
}

View File

@@ -0,0 +1,40 @@
Import("env")
import os
# The Tasmota platform builds with CONFIG_MBEDTLS_TLS_DISABLED=y, stripping the
# SSL/TLS module from libmbedtls.a. We compile it from source and re-enable the
# necessary config macros for a minimal TLS 1.2 client.
try:
platform = env.PioPlatform()
framework_dir = platform.get_package_dir("framework-arduinoespressif32")
mcu = env.BoardConfig().get("build.mcu", "esp32")
base = os.path.join(framework_dir, "tools", "esp32-arduino-libs", mcu, "include", "mbedtls")
paths = [
os.path.join(base, "mbedtls", "library"),
os.path.join(base, "mbedtls", "include"),
os.path.join(base, "port", "include"),
]
for p in paths:
if os.path.isdir(p):
env.Append(CPPPATH=[p])
# Re-enable mbedtls TLS 1.2 client support (disabled by Tasmota sdkconfig)
env.Append(CPPDEFINES=[
# Core TLS
"CONFIG_MBEDTLS_TLS_ENABLED",
"CONFIG_MBEDTLS_TLS_CLIENT",
"CONFIG_MBEDTLS_SSL_PROTO_TLS1_2",
("CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN", "16384"),
# Key exchange methods (at least one required)
"CONFIG_MBEDTLS_KEY_EXCHANGE_RSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA",
# Optional but useful
"CONFIG_MBEDTLS_SSL_RENEGOTIATION",
"CONFIG_MBEDTLS_SSL_ALPN",
])
except Exception:
pass

View File

@@ -0,0 +1,10 @@
{
"name": "mbedtls_ssl",
"version": "3.6.5",
"description": "mbedtls SSL/TLS module compiled from source (Tasmota platform strips this from libmbedtls.a)",
"platforms": ["espressif32"],
"build": {
"extraScript": "configure.py",
"libArchive": false
}
}

View File

@@ -0,0 +1,684 @@
/**
* \file alignment.h
*
* \brief Utility code for dealing with unaligned memory accesses
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_LIBRARY_ALIGNMENT_H
#define MBEDTLS_LIBRARY_ALIGNMENT_H
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
/*
* Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory
* accesses are known to be efficient.
*
* All functions defined here will behave correctly regardless, but might be less
* efficient when this is not defined.
*/
#if defined(__ARM_FEATURE_UNALIGNED) \
|| defined(MBEDTLS_ARCH_IS_X86) || defined(MBEDTLS_ARCH_IS_X64) \
|| defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
/*
* __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
* (and later versions) for Arm v7 and later; all x86 platforms should have
* efficient unaligned access.
*
* https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment
* specifies that on Windows-on-Arm64, unaligned access is safe (except for uncached
* device memory).
*/
#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
#endif
#if defined(__IAR_SYSTEMS_ICC__) && \
(defined(MBEDTLS_ARCH_IS_ARM64) || defined(MBEDTLS_ARCH_IS_ARM32) \
|| defined(__ICCRX__) || defined(__ICCRL78__) || defined(__ICCRISCV__))
#pragma language=save
#pragma language=extended
#define MBEDTLS_POP_IAR_LANGUAGE_PRAGMA
/* IAR recommend this technique for accessing unaligned data in
* https://www.iar.com/knowledge/support/technical-notes/compiler/accessing-unaligned-data
* This results in a single load / store instruction (if unaligned access is supported).
* According to that document, this is only supported on certain architectures.
*/
#define UINT_UNALIGNED
typedef uint16_t __packed mbedtls_uint16_unaligned_t;
typedef uint32_t __packed mbedtls_uint32_unaligned_t;
typedef uint64_t __packed mbedtls_uint64_unaligned_t;
#elif defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 40504) && \
((MBEDTLS_GCC_VERSION < 60300) || (!defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)))
/*
* gcc may generate a branch to memcpy for calls like `memcpy(dest, src, 4)` rather than
* generating some LDR or LDRB instructions (similar for stores).
*
* This is architecture dependent: x86-64 seems fine even with old gcc; 32-bit Arm
* is affected. To keep it simple, we enable for all architectures.
*
* For versions of gcc < 5.4.0 this issue always happens.
* For gcc < 6.3.0, this issue happens at -O0
* For all versions, this issue happens iff unaligned access is not supported.
*
* For gcc 4.x, this implementation will generate byte-by-byte loads even if unaligned access is
* supported, which is correct but not optimal.
*
* For performance (and code size, in some cases), we want to avoid the branch and just generate
* some inline load/store instructions since the access is small and constant-size.
*
* The manual states:
* "The packed attribute specifies that a variable or structure field should have the smallest
* possible alignment—one byte for a variable"
* https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Variable-Attributes.html
*
* Previous implementations used __attribute__((__aligned__(1)), but had issues with a gcc bug:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94662
*
* Tested with several versions of GCC from 4.5.0 up to 13.2.0
* We don't enable for older than 4.5.0 as this has not been tested.
*/
#define UINT_UNALIGNED_STRUCT
typedef struct {
uint16_t x;
} __attribute__((packed)) mbedtls_uint16_unaligned_t;
typedef struct {
uint32_t x;
} __attribute__((packed)) mbedtls_uint32_unaligned_t;
typedef struct {
uint64_t x;
} __attribute__((packed)) mbedtls_uint64_unaligned_t;
#endif
/*
* We try to force mbedtls_(get|put)_unaligned_uintXX to be always inline, because this results
* in code that is both smaller and faster. IAR and gcc both benefit from this when optimising
* for size.
*/
/**
* Read the unsigned 16 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint16_t mbedtls_get_unaligned_uint16(const void *p)
{
uint16_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = *p16;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = p16->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 16 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
*p16 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
p16->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 32 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint32_t mbedtls_get_unaligned_uint32(const void *p)
{
uint32_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = *p32;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = p32->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 32 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
*p32 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
p32->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 64 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint64_t mbedtls_get_unaligned_uint64(const void *p)
{
uint64_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = *p64;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = p64->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 64 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
*p64 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
p64->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
#if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA)
#pragma language=restore
#endif
/** Byte Reading Macros
*
* Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
* byte from x, where byte 0 is the least significant byte.
*/
#define MBEDTLS_BYTE_0(x) ((uint8_t) ((x) & 0xff))
#define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >> 8) & 0xff))
#define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff))
#define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff))
#define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff))
#define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff))
#define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff))
#define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff))
/*
* Detect GCC built-in byteswap routines
*/
#if defined(__GNUC__) && defined(__GNUC_PREREQ)
#if __GNUC_PREREQ(4, 8)
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif /* __GNUC_PREREQ(4,8) */
#if __GNUC_PREREQ(4, 3)
#define MBEDTLS_BSWAP32 __builtin_bswap32
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif /* __GNUC_PREREQ(4,3) */
#endif /* defined(__GNUC__) && defined(__GNUC_PREREQ) */
/*
* Detect Clang built-in byteswap routines
*/
#if defined(__clang__) && defined(__has_builtin)
#if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif /* __has_builtin(__builtin_bswap16) */
#if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 __builtin_bswap32
#endif /* __has_builtin(__builtin_bswap32) */
#if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif /* __has_builtin(__builtin_bswap64) */
#endif /* defined(__clang__) && defined(__has_builtin) */
/*
* Detect MSVC built-in byteswap routines
*/
#if defined(_MSC_VER)
#if !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 _byteswap_ushort
#endif
#if !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 _byteswap_ulong
#endif
#if !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 _byteswap_uint64
#endif
#endif /* defined(_MSC_VER) */
/* Detect armcc built-in byteswap routine */
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32)
#if defined(__ARM_ACLE) /* ARM Compiler 6 - earlier versions don't need a header */
#include <arm_acle.h>
#endif
#define MBEDTLS_BSWAP32 __rev
#endif
/* Detect IAR built-in byteswap routine */
#if defined(__IAR_SYSTEMS_ICC__)
#if defined(__ARM_ACLE)
#include <arm_acle.h>
#define MBEDTLS_BSWAP16(x) ((uint16_t) __rev16((uint32_t) (x)))
#define MBEDTLS_BSWAP32 __rev
#define MBEDTLS_BSWAP64 __revll
#endif
#endif
/*
* Where compiler built-ins are not present, fall back to C code that the
* compiler may be able to detect and transform into the relevant bswap or
* similar instruction.
*/
#if !defined(MBEDTLS_BSWAP16)
static inline uint16_t mbedtls_bswap16(uint16_t x)
{
return
(x & 0x00ff) << 8 |
(x & 0xff00) >> 8;
}
#define MBEDTLS_BSWAP16 mbedtls_bswap16
#endif /* !defined(MBEDTLS_BSWAP16) */
#if !defined(MBEDTLS_BSWAP32)
static inline uint32_t mbedtls_bswap32(uint32_t x)
{
return
(x & 0x000000ff) << 24 |
(x & 0x0000ff00) << 8 |
(x & 0x00ff0000) >> 8 |
(x & 0xff000000) >> 24;
}
#define MBEDTLS_BSWAP32 mbedtls_bswap32
#endif /* !defined(MBEDTLS_BSWAP32) */
#if !defined(MBEDTLS_BSWAP64)
static inline uint64_t mbedtls_bswap64(uint64_t x)
{
return
(x & 0x00000000000000ffULL) << 56 |
(x & 0x000000000000ff00ULL) << 40 |
(x & 0x0000000000ff0000ULL) << 24 |
(x & 0x00000000ff000000ULL) << 8 |
(x & 0x000000ff00000000ULL) >> 8 |
(x & 0x0000ff0000000000ULL) >> 24 |
(x & 0x00ff000000000000ULL) >> 40 |
(x & 0xff00000000000000ULL) >> 56;
}
#define MBEDTLS_BSWAP64 mbedtls_bswap64
#endif /* !defined(MBEDTLS_BSWAP64) */
#if !defined(__BYTE_ORDER__)
#if defined(__LITTLE_ENDIAN__)
/* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */
#define MBEDTLS_IS_BIG_ENDIAN 0
#elif defined(__BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
static const uint16_t mbedtls_byte_order_detector = { 0x100 };
#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
#endif
#else
#if (__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
#define MBEDTLS_IS_BIG_ENDIAN 0
#endif
#endif /* !defined(__BYTE_ORDER__) */
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint32((data) + (offset)) \
: MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
)
/**
* Put in memory a 32 bits unsigned integer in big-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
: mbedtls_get_unaligned_uint32((data) + (offset)) \
)
/**
* Put in memory a 32 bits unsigned integer in little-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
: mbedtls_get_unaligned_uint16((data) + (offset)) \
)
/**
* Put in memory a 16 bits unsigned integer in little-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint16((data) + (offset)) \
: MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
)
/**
* Put in memory a 16 bits unsigned integer in big-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_BE(data, offset) \
( \
((uint32_t) (data)[(offset)] << 16) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2]) \
)
/**
* Put in memory a 24 bits unsigned integer in big-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_BE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_2(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_0(n); \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_LE(data, offset) \
( \
((uint32_t) (data)[(offset)]) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2] << 16) \
)
/**
* Put in memory a 24 bits unsigned integer in little-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_LE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_0(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_2(n); \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint64((data) + (offset)) \
: MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
)
/**
* Put in memory a 64 bits unsigned integer in big-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
: mbedtls_get_unaligned_uint64((data) + (offset)) \
)
/**
* Put in memory a 64 bits unsigned integer in little-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
}
#endif /* MBEDTLS_LIBRARY_ALIGNMENT_H */

View File

@@ -0,0 +1,453 @@
/**
* \file common.h
*
* \brief Utility macros for internal use in the library
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_LIBRARY_COMMON_H
#define MBEDTLS_LIBRARY_COMMON_H
#include "mbedtls/build_info.h"
#include "alignment.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stddef.h>
#if defined(__ARM_NEON)
#include <arm_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
#include <arm64_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#endif
/** Helper to define a function as static except when building invasive tests.
*
* If a function is only used inside its own source file and should be
* declared `static` to allow the compiler to optimize for code size,
* but that function has unit tests, define it with
* ```
* MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... }
* ```
* and declare it in a header in the `library/` directory with
* ```
* #if defined(MBEDTLS_TEST_HOOKS)
* int mbedtls_foo(...);
* #endif
* ```
*/
#if defined(MBEDTLS_TEST_HOOKS)
#define MBEDTLS_STATIC_TESTABLE
#else
#define MBEDTLS_STATIC_TESTABLE static
#endif
#if defined(MBEDTLS_TEST_HOOKS)
extern void (*mbedtls_test_hook_test_fail)(const char *test, int line, const char *file);
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) \
do { \
if ((!(TEST)) && ((*mbedtls_test_hook_test_fail) != NULL)) \
{ \
(*mbedtls_test_hook_test_fail)( #TEST, __LINE__, __FILE__); \
} \
} while (0)
#else
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST)
#endif /* defined(MBEDTLS_TEST_HOOKS) */
/** \def ARRAY_LENGTH
* Return the number of elements of a static or stack array.
*
* \param array A value of array (not pointer) type.
*
* \return The number of elements of the array.
*/
/* A correct implementation of ARRAY_LENGTH, but which silently gives
* a nonsensical result if called with a pointer rather than an array. */
#define ARRAY_LENGTH_UNSAFE(array) \
(sizeof(array) / sizeof(*(array)))
#if defined(__GNUC__)
/* Test if arg and &(arg)[0] have the same type. This is true if arg is
* an array but not if it's a pointer. */
#define IS_ARRAY_NOT_POINTER(arg) \
(!__builtin_types_compatible_p(__typeof__(arg), \
__typeof__(&(arg)[0])))
/* A compile-time constant with the value 0. If `const_expr` is not a
* compile-time constant with a nonzero value, cause a compile-time error. */
#define STATIC_ASSERT_EXPR(const_expr) \
(0 && sizeof(struct { unsigned int STATIC_ASSERT : 1 - 2 * !(const_expr); }))
/* Return the scalar value `value` (possibly promoted). This is a compile-time
* constant if `value` is. `condition` must be a compile-time constant.
* If `condition` is false, arrange to cause a compile-time error. */
#define STATIC_ASSERT_THEN_RETURN(condition, value) \
(STATIC_ASSERT_EXPR(condition) ? 0 : (value))
#define ARRAY_LENGTH(array) \
(STATIC_ASSERT_THEN_RETURN(IS_ARRAY_NOT_POINTER(array), \
ARRAY_LENGTH_UNSAFE(array)))
#else
/* If we aren't sure the compiler supports our non-standard tricks,
* fall back to the unsafe implementation. */
#define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array)
#endif
/** Allow library to access its structs' private members.
*
* Although structs defined in header files are publicly available,
* their members are private and should not be accessed by the user.
*/
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
/**
* \brief Securely zeroize a buffer then free it.
*
* Similar to making consecutive calls to
* \c mbedtls_platform_zeroize() and \c mbedtls_free(), but has
* code size savings, and potential for optimisation in the future.
*
* Guaranteed to be a no-op if \p buf is \c NULL and \p len is 0.
*
* \param buf Buffer to be zeroized then freed.
* \param len Length of the buffer in bytes
*/
void mbedtls_zeroize_and_free(void *buf, size_t len);
/** Return an offset into a buffer.
*
* This is just the addition of an offset to a pointer, except that this
* function also accepts an offset of 0 into a buffer whose pointer is null.
* (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
* A null pointer is a valid buffer pointer when the size is 0, for example
* as the result of `malloc(0)` on some platforms.)
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline unsigned char *mbedtls_buffer_offset(
unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/** Return an offset into a read-only buffer.
*
* Similar to mbedtls_buffer_offset(), but for const pointers.
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline const unsigned char *mbedtls_buffer_offset_const(
const unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/* Always inline mbedtls_xor() for similar reasons as mbedtls_xor_no_simd(). */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_HAVE_NEON_INTRINSICS) && \
(!(defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_GCC_VERSION < 70300))
/* Old GCC versions generate a warning here, so disable the NEON path for these compilers */
for (; (i + 16) <= n; i += 16) {
uint8x16_t v1 = vld1q_u8(a + i);
uint8x16_t v2 = vld1q_u8(b + i);
uint8x16_t x = veorq_u8(v1, v2);
vst1q_u8(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 16.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 16 == 0) {
return;
}
#endif
#elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Always inline mbedtls_xor_no_simd() as we see significant perf regressions when it does not get
* inlined (e.g., observed about 3x perf difference in gcm_mult_largetable with gcc 7 - 12) */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* In some situations, this can perform better than mbedtls_xor() (e.g., it's about 5%
* better in AES-CBC).
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor_no_simd(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 8.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Fix MSVC C99 compatible issue
* MSVC support __func__ from visual studio 2015( 1900 )
* Use MSVC predefine macro to avoid name check fail.
*/
#if (defined(_MSC_VER) && (_MSC_VER <= 1900))
#define /*no-check-names*/ __func__ __FUNCTION__
#endif
/* Define `asm` for compilers which don't define it. */
/* *INDENT-OFF* */
#ifndef asm
#if defined(__IAR_SYSTEMS_ICC__)
#define asm __asm
#else
#define asm __asm__
#endif
#endif
/* *INDENT-ON* */
/*
* Define the constraint used for read-only pointer operands to aarch64 asm.
*
* This is normally the usual "r", but for aarch64_32 (aka ILP32,
* as found in watchos), "p" is required to avoid warnings from clang.
*
* Note that clang does not recognise '+p' or '=p', and armclang
* does not recognise 'p' at all. Therefore, to update a pointer from
* aarch64 assembly, it is necessary to use something like:
*
* uintptr_t uptr = (uintptr_t) ptr;
* asm( "ldr x4, [%x0], #8" ... : "+r" (uptr) : : )
* ptr = (void*) uptr;
*
* Note that the "x" in "%x0" is neccessary; writing "%0" will cause warnings.
*/
#if defined(__aarch64__) && defined(MBEDTLS_HAVE_ASM)
#if UINTPTR_MAX == 0xfffffffful
/* ILP32: Specify the pointer operand slightly differently, as per #7787. */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "p"
#elif UINTPTR_MAX == 0xfffffffffffffffful
/* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r"
#else
#error "Unrecognised pointer size for aarch64"
#endif
#endif
/* Always provide a static assert macro, so it can be used unconditionally.
* It does nothing on systems where we don't know how to define a static assert.
*/
/* Can't use the C11-style `defined(static_assert)` on FreeBSD, since it
* defines static_assert even with -std=c99, but then complains about it.
*/
#if defined(static_assert) && !defined(__FreeBSD__)
#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#else
/* Make sure `MBEDTLS_STATIC_ASSERT(expr, msg);` is valid both inside and
* outside a function. We choose a struct declaration, which can be repeated
* any number of times and does not need a matching definition. */
#define MBEDTLS_STATIC_ASSERT(expr, msg) \
struct ISO_C_does_not_allow_extra_semicolon_outside_of_a_function
#endif
#if defined(__has_builtin)
#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
#else
#define MBEDTLS_HAS_BUILTIN(x) 0
#endif
/* Define compiler branch hints */
#if MBEDTLS_HAS_BUILTIN(__builtin_expect)
#define MBEDTLS_LIKELY(x) __builtin_expect(!!(x), 1)
#define MBEDTLS_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define MBEDTLS_LIKELY(x) x
#define MBEDTLS_UNLIKELY(x) x
#endif
/* MBEDTLS_ASSUME may be used to provide additional information to the compiler
* which can result in smaller code-size. */
#if MBEDTLS_HAS_BUILTIN(__builtin_assume)
/* clang provides __builtin_assume */
#define MBEDTLS_ASSUME(x) __builtin_assume(x)
#elif MBEDTLS_HAS_BUILTIN(__builtin_unreachable)
/* gcc and IAR can use __builtin_unreachable */
#define MBEDTLS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
#elif defined(_MSC_VER)
/* Supported by MSVC since VS 2005 */
#define MBEDTLS_ASSUME(x) __assume(x)
#else
#define MBEDTLS_ASSUME(x) do { } while (0)
#endif
/* For gcc -Os, override with -O2 for a given function.
*
* This will not affect behaviour for other optimisation settings, e.g. -O0.
*/
#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__OPTIMIZE_SIZE__)
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE __attribute__((optimize("-O2")))
#else
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE
#endif
/* Suppress compiler warnings for unused functions and variables. */
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__has_attribute)
# if __has_attribute(unused)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__GNUC__)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__IAR_SYSTEMS_ICC__) && defined(__VER__)
/* IAR does support __attribute__((unused)), but only if the -e flag (extended language support)
* is given; the pragma always works.
* Unfortunately the pragma affects the rest of the file where it is used, but this is harmless.
* Check for version 5.2 or later - this pragma may be supported by earlier versions, but I wasn't
* able to find documentation).
*/
# if (__VER__ >= 5020000)
# define MBEDTLS_MAYBE_UNUSED _Pragma("diag_suppress=Pe177")
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(_MSC_VER)
# define MBEDTLS_MAYBE_UNUSED __pragma(warning(suppress:4189))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED)
# define MBEDTLS_MAYBE_UNUSED
#endif
/* GCC >= 15 has a warning 'unterminated-string-initialization' which complains if you initialize
* a string into an array without space for a terminating NULL character. In some places in the
* codebase this behaviour is intended, so we add the macro MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
* to suppress the warning in these places.
*/
#if defined(__has_attribute)
#if __has_attribute(nonstring)
#define MBEDTLS_HAS_ATTRIBUTE_NONSTRING
#endif /* __has_attribute(nonstring) */
#endif /* __has_attribute */
#if defined(MBEDTLS_HAS_ATTRIBUTE_NONSTRING)
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING __attribute__((nonstring))
#else
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
#endif /* MBEDTLS_HAS_ATTRIBUTE_NONSTRING */
#endif /* MBEDTLS_LIBRARY_COMMON_H */

View File

@@ -0,0 +1,579 @@
/**
* Constant-time functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H
#define MBEDTLS_CONSTANT_TIME_INTERNAL_H
#include <stdint.h>
#include <stddef.h>
#include "common.h"
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
/* The constant-time interface provides various operations that are likely
* to result in constant-time code that does not branch or use conditional
* instructions for secret data (for secret pointers, this also applies to
* the data pointed to).
*
* It has three main parts:
*
* - boolean operations
* These are all named mbedtls_ct_<type>_<operation>.
* They operate over <type> and return mbedtls_ct_condition_t.
* All arguments are considered secret.
* example: bool x = y | z => x = mbedtls_ct_bool_or(y, z)
* example: bool x = y == z => x = mbedtls_ct_uint_eq(y, z)
*
* - conditional data selection
* These are all named mbedtls_ct_<type>_if and mbedtls_ct_<type>_if_else_0
* All arguments are considered secret.
* example: size_t a = x ? b : c => a = mbedtls_ct_size_if(x, b, c)
* example: unsigned a = x ? b : 0 => a = mbedtls_ct_uint_if_else_0(x, b)
*
* - block memory operations
* Only some arguments are considered secret, as documented for each
* function.
* example: if (x) memcpy(...) => mbedtls_ct_memcpy_if(x, ...)
*
* mbedtls_ct_condition_t must be treated as opaque and only created and
* manipulated via the functions in this header. The compiler should never
* be able to prove anything about its value at compile-time.
*
* mbedtls_ct_uint_t is an unsigned integer type over which constant time
* operations may be performed via the functions in this header. It is as big
* as the larger of size_t and mbedtls_mpi_uint, i.e. it is safe to cast
* to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other
* not-larger integer types).
*
* For Arm (32-bit, 64-bit and Thumb), x86 and x86-64, assembly implementations
* are used to ensure that the generated code is constant time. For other
* architectures, it uses a plain C fallback designed to yield constant-time code
* (this has been observed to be constant-time on latest gcc, clang and MSVC
* as of May 2023).
*
* For readability, the static inline definitions are separated out into
* constant_time_impl.h.
*/
#if (SIZE_MAX > 0xffffffffffffffffULL)
/* Pointer size > 64-bit */
typedef size_t mbedtls_ct_condition_t;
typedef size_t mbedtls_ct_uint_t;
typedef ptrdiff_t mbedtls_ct_int_t;
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(SIZE_MAX))
#elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64)
/* 32-bit < pointer size <= 64-bit, or 64-bit MPI */
typedef uint64_t mbedtls_ct_condition_t;
typedef uint64_t mbedtls_ct_uint_t;
typedef int64_t mbedtls_ct_int_t;
#define MBEDTLS_CT_SIZE_64
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT64_MAX))
#else
/* Pointer size <= 32-bit, and no 64-bit MPIs */
typedef uint32_t mbedtls_ct_condition_t;
typedef uint32_t mbedtls_ct_uint_t;
typedef int32_t mbedtls_ct_int_t;
#define MBEDTLS_CT_SIZE_32
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT32_MAX))
#endif
#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(0))
/* ============================================================================
* Boolean operations
*/
/** Convert a number into a mbedtls_ct_condition_t.
*
* \param x Number to convert.
*
* \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0
*
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x);
/** Boolean "not equal" operation.
*
* Functionally equivalent to:
*
* \p x != \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
/** Boolean "equals" operation.
*
* Functionally equivalent to:
*
* \p x == \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "less than" operation.
*
* Functionally equivalent to:
*
* \p x < \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
/** Boolean "greater than" operation.
*
* Functionally equivalent to:
*
* \p x > \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "greater or equal" operation.
*
* Functionally equivalent to:
*
* \p x >= \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x >= \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "less than or equal" operation.
*
* Functionally equivalent to:
*
* \p x <= \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x <= \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean not-equals operation.
*
* Functionally equivalent to:
*
* \p x != \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \note This is more efficient than mbedtls_ct_uint_ne if both arguments are
* mbedtls_ct_condition_t.
*
* \return MBEDTLS_CT_TRUE if \p x != \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "and" operation.
*
* Functionally equivalent to:
*
* \p x && \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x && \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "or" operation.
*
* Functionally equivalent to:
*
* \p x || \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x || \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "not" operation.
*
* Functionally equivalent to:
*
* ! \p x
*
* \param x The value to invert
*
* \return MBEDTLS_CT_FALSE if \p x, otherwise MBEDTLS_CT_TRUE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x);
/* ============================================================================
* Data selection operations
*/
/** Choose between two size_t values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
size_t if1,
size_t if0);
/** Choose between two unsigned values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,
unsigned if1,
unsigned if0);
/** Choose between two mbedtls_ct_condition_t values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_if(mbedtls_ct_condition_t condition,
mbedtls_ct_condition_t if1,
mbedtls_ct_condition_t if0);
#if defined(MBEDTLS_BIGNUM_C)
/** Choose between two mbedtls_mpi_uint values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
mbedtls_mpi_uint if1, \
mbedtls_mpi_uint if0);
#endif
/** Choose between an unsigned value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_uint_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1);
/** Choose between an mbedtls_ct_condition_t and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_bool_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_if_else_0(mbedtls_ct_condition_t condition,
mbedtls_ct_condition_t if1);
/** Choose between a size_t value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_size_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1);
#if defined(MBEDTLS_BIGNUM_C)
/** Choose between an mbedtls_mpi_uint value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_mpi_uint_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition,
mbedtls_mpi_uint if1);
#endif
/** Constant-flow char selection
*
* \param low Secret. Bottom of range
* \param high Secret. Top of range
* \param c Secret. Value to compare to range
* \param t Secret. Value to return, if in range
*
* \return \p t if \p low <= \p c <= \p high, 0 otherwise.
*/
static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
unsigned char high,
unsigned char c,
unsigned char t);
/** Choose between two error values. The values must be in the range [-32767..0].
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline int mbedtls_ct_error_if(mbedtls_ct_condition_t condition, int if1, int if0);
/** Choose between an error value and 0. The error value must be in the range [-32767..0].
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_error_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline int mbedtls_ct_error_if_else_0(mbedtls_ct_condition_t condition, int if1);
/* ============================================================================
* Block memory operations
*/
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
/** Conditionally set a block of memory to zero.
*
* Regardless of the condition, every byte will be read once and written to
* once.
*
* \param condition Secret. Condition to test.
* \param buf Secret. Pointer to the start of the buffer.
* \param len Number of bytes to set to zero.
*
* \warning Unlike mbedtls_platform_zeroize, this does not have the same guarantees
* about not being optimised away if the memory is never read again.
*/
void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len);
/** Shift some data towards the left inside a buffer.
*
* Functionally equivalent to:
*
* memmove(start, start + offset, total - offset);
* memset(start + (total - offset), 0, offset);
*
* Timing independence comes at the expense of performance.
*
* \param start Secret. Pointer to the start of the buffer.
* \param total Total size of the buffer.
* \param offset Secret. Offset from which to copy \p total - \p offset bytes.
*/
void mbedtls_ct_memmove_left(void *start,
size_t total,
size_t offset);
#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
/** Conditional memcpy.
*
* Functionally equivalent to:
*
* if (condition) {
* memcpy(dest, src1, len);
* } else {
* if (src2 != NULL)
* memcpy(dest, src2, len);
* }
*
* It will always read len bytes from src1.
* If src2 != NULL, it will always read len bytes from src2.
* If src2 == NULL, it will instead read len bytes from dest (as if src2 == dest).
*
* \param condition The condition
* \param dest Secret. Destination pointer.
* \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE).
* This may be equal to \p dest, but may not overlap in other ways.
* \param src2 Secret (contents only - may branch to determine if this parameter is NULL).
* Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). May be NULL.
* This may be equal to \p dest, but may not overlap it in other ways. It may overlap with \p src1.
* \param len Number of bytes to copy.
*/
void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
unsigned char *dest,
const unsigned char *src1,
const unsigned char *src2,
size_t len
);
/** Copy data from a secret position.
*
* Functionally equivalent to:
*
* memcpy(dst, src + offset, len)
*
* This function copies \p len bytes from \p src + \p offset to
* \p dst, with a code flow and memory access pattern that does not depend on
* \p offset, but only on \p offset_min, \p offset_max and \p len.
*
* \note This function reads from \p dest, but the value that
* is read does not influence the result and this
* function's behavior is well-defined regardless of the
* contents of the buffers. This may result in false
* positives from static or dynamic analyzers, especially
* if \p dest is not initialized.
*
* \param dest Secret. The destination buffer. This must point to a writable
* buffer of at least \p len bytes.
* \param src Secret. The base of the source buffer. This must point to a
* readable buffer of at least \p offset_max + \p len
* bytes. Shouldn't overlap with \p dest
* \param offset Secret. The offset in the source buffer from which to copy.
* This must be no less than \p offset_min and no greater
* than \p offset_max.
* \param offset_min The minimal value of \p offset.
* \param offset_max The maximal value of \p offset.
* \param len The number of bytes to copy.
*/
void mbedtls_ct_memcpy_offset(unsigned char *dest,
const unsigned char *src,
size_t offset,
size_t offset_min,
size_t offset_max,
size_t len);
/* Documented in include/mbedtls/constant_time.h. a and b are secret.
int mbedtls_ct_memcmp(const void *a,
const void *b,
size_t n);
*/
#if defined(MBEDTLS_NIST_KW_C)
/** Constant-time buffer comparison without branches.
*
* Similar to mbedtls_ct_memcmp, except that the result only depends on part of
* the input data - differences in the head or tail are ignored. Functionally equivalent to:
*
* memcmp(a + skip_head, b + skip_head, size - skip_head - skip_tail)
*
* Time taken depends on \p n, but not on \p skip_head or \p skip_tail .
*
* Behaviour is undefined if ( \p skip_head + \p skip_tail) > \p n.
*
* \param a Secret. Pointer to the first buffer, containing at least \p n bytes. May not be NULL.
* \param b Secret. Pointer to the second buffer, containing at least \p n bytes. May not be NULL.
* \param n The number of bytes to examine (total size of the buffers).
* \param skip_head Secret. The number of bytes to treat as non-significant at the start of the buffer.
* These bytes will still be read.
* \param skip_tail Secret. The number of bytes to treat as non-significant at the end of the buffer.
* These bytes will still be read.
*
* \return Zero if the contents of the two buffers are the same, otherwise non-zero.
*/
int mbedtls_ct_memcmp_partial(const void *a,
const void *b,
size_t n,
size_t skip_head,
size_t skip_tail);
#endif
/* Include the implementation of static inline functions above. */
#include "constant_time_impl.h"
#endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */

View File

@@ -0,0 +1,172 @@
/**
* \file debug_internal.h
*
* \brief Internal part of the public "debug.h".
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_DEBUG_INTERNAL_H
#define MBEDTLS_DEBUG_INTERNAL_H
#include "mbedtls/debug.h"
/**
* \brief Print a message to the debug output. This function is always used
* through the MBEDTLS_SSL_DEBUG_MSG() macro, which supplies the ssl
* context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the message has occurred in
* \param line line number the message has occurred at
* \param format format specifier, in printf format
* \param ... variables used by the format specifier
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_msg(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *format, ...) MBEDTLS_PRINTF_ATTRIBUTE(5, 6);
/**
* \brief Print the return value of a function to the debug output. This
* function is always used through the MBEDTLS_SSL_DEBUG_RET() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text the name of the function that returned the error
* \param ret the return code value
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_ret(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, int ret);
/**
* \brief Output a buffer of size len bytes to the debug output. This function
* is always used through the MBEDTLS_SSL_DEBUG_BUF() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the buffer being dumped. Normally the
* variable or buffer name
* \param buf the buffer to be outputted
* \param len length of the buffer
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_buf(const mbedtls_ssl_context *ssl, int level,
const char *file, int line, const char *text,
const unsigned char *buf, size_t len);
#if defined(MBEDTLS_BIGNUM_C)
/**
* \brief Print a MPI variable to the debug output. This function is always
* used through the MBEDTLS_SSL_DEBUG_MPI() macro, which supplies the
* ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the MPI being output. Normally the
* variable name
* \param X the MPI variable
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_mpi *X);
#endif
#if defined(MBEDTLS_ECP_LIGHT)
/**
* \brief Print an ECP point to the debug output. This function is always
* used through the MBEDTLS_SSL_DEBUG_ECP() macro, which supplies the
* ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the ECP point being output. Normally the
* variable name
* \param X the ECP point
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_ecp(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_ecp_point *X);
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C) && !defined(MBEDTLS_X509_REMOVE_INFO)
/**
* \brief Print a X.509 certificate structure to the debug output. This
* function is always used through the MBEDTLS_SSL_DEBUG_CRT() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the certificate being output
* \param crt X.509 certificate structure
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_crt(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_x509_crt *crt);
#endif
/* Note: the MBEDTLS_ECDH_C guard here is mandatory because this debug function
only works for the built-in implementation. */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED) && \
defined(MBEDTLS_ECDH_C)
typedef enum {
MBEDTLS_DEBUG_ECDH_Q,
MBEDTLS_DEBUG_ECDH_QP,
MBEDTLS_DEBUG_ECDH_Z,
} mbedtls_debug_ecdh_attr;
/**
* \brief Print a field of the ECDH structure in the SSL context to the debug
* output. This function is always used through the
* MBEDTLS_SSL_DEBUG_ECDH() macro, which supplies the ssl context, file
* and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param ecdh the ECDH context
* \param attr the identifier of the attribute being output
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_printf_ecdh(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const mbedtls_ecdh_context *ecdh,
mbedtls_debug_ecdh_attr attr);
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED &&
MBEDTLS_ECDH_C */
#endif /* MBEDTLS_DEBUG_INTERNAL_H */

View File

@@ -0,0 +1,9 @@
/*
* Stub header to trigger PlatformIO Library Dependency Finder.
*
* The Tasmota Arduino platform ships a stripped libmbedtls.a that is missing
* the core SSL/TLS implementation (mbedtls_ssl_read, mbedtls_ssl_write, etc.).
* This library compiles the official mbedtls 3.6.5 SSL source files so that
* esp_tls and other components that depend on mbedtls SSL can link.
*/
#pragma once

View File

@@ -0,0 +1,26 @@
/**
* Translation between MD and PSA identifiers (algorithms, errors).
*
* Note: this internal module will go away when everything becomes based on
* PSA Crypto; it is a helper for the transition period.
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_MD_PSA_H
#define MBEDTLS_MD_PSA_H
#include "common.h"
#include "mbedtls/md.h"
#include "psa/crypto.h"
/** Convert PSA status to MD error code.
*
* \param status PSA status.
*
* \return The corresponding MD error code,
*/
int mbedtls_md_error_from_psa(psa_status_t status);
#endif /* MBEDTLS_MD_PSA_H */

View File

@@ -0,0 +1,100 @@
/**
* \file psa_util_internal.h
*
* \brief Internal utility functions for use of PSA Crypto.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_PSA_UTIL_INTERNAL_H
#define MBEDTLS_PSA_UTIL_INTERNAL_H
/* Include the public header so that users only need one include. */
#include "mbedtls/psa_util.h"
#include "psa/crypto.h"
#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
/*************************************************************************
* FFDH
************************************************************************/
#define MBEDTLS_PSA_MAX_FFDH_PUBKEY_LENGTH \
PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS)
/*************************************************************************
* ECC
************************************************************************/
#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH \
PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
#define MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH \
PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
/*************************************************************************
* Error translation
************************************************************************/
typedef struct {
/* Error codes used by PSA crypto are in -255..-128, fitting in 16 bits. */
int16_t psa_status;
/* Error codes used by Mbed TLS are in one of the ranges
* -127..-1 (low-level) or -32767..-4096 (high-level with a low-level
* code optionally added), fitting in 16 bits. */
int16_t mbedtls_error;
} mbedtls_error_pair_t;
#if defined(MBEDTLS_MD_LIGHT)
extern const mbedtls_error_pair_t psa_to_md_errors[4];
#endif
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
extern const mbedtls_error_pair_t psa_to_cipher_errors[4];
#endif
#if defined(MBEDTLS_LMS_C)
extern const mbedtls_error_pair_t psa_to_lms_errors[3];
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
extern const mbedtls_error_pair_t psa_to_ssl_errors[7];
#endif
#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) || \
defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC)
extern const mbedtls_error_pair_t psa_to_pk_rsa_errors[8];
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO) && \
defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
extern const mbedtls_error_pair_t psa_to_pk_ecdsa_errors[7];
#endif
/* Generic fallback function for error translation,
* when the received state was not module-specific. */
int psa_generic_status_to_mbedtls(psa_status_t status);
/* This function iterates over provided local error translations,
* and if no match was found - calls the fallback error translation function. */
int psa_status_to_mbedtls(psa_status_t status,
const mbedtls_error_pair_t *local_translations,
size_t local_errors_num,
int (*fallback_f)(psa_status_t));
/* The second out of three-stage error handling functions of the pk module,
* acts as a fallback after RSA / ECDSA error translation, and if no match
* is found, it itself calls psa_generic_status_to_mbedtls. */
int psa_pk_status_to_mbedtls(psa_status_t status);
/* Utility macro to shorten the defines of error translator in modules. */
#define PSA_TO_MBEDTLS_ERR_LIST(status, error_list, fallback_f) \
psa_status_to_mbedtls(status, error_list, \
sizeof(error_list)/sizeof(error_list[0]), \
fallback_f)
#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
#endif /* MBEDTLS_PSA_UTIL_INTERNAL_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
/**
* TLS 1.2 and 1.3 client-side functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_SSL_CLIENT_H
#define MBEDTLS_SSL_CLIENT_H
#include "common.h"
#if defined(MBEDTLS_SSL_TLS_C)
#include "ssl_misc.h"
#endif
#include <stddef.h>
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_write_client_hello(mbedtls_ssl_context *ssl);
#endif /* MBEDTLS_SSL_CLIENT_H */

View File

@@ -0,0 +1,83 @@
/**
* \file ssl_debug_helpers.h
*
* \brief Automatically generated helper functions for debugging
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_SSL_DEBUG_HELPERS_H
#define MBEDTLS_SSL_DEBUG_HELPERS_H
#include "common.h"
#if defined(MBEDTLS_DEBUG_C)
#include "mbedtls/ssl.h"
#include "ssl_misc.h"
const char *mbedtls_ssl_states_str(mbedtls_ssl_states in);
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
const char *mbedtls_ssl_early_data_status_str(mbedtls_ssl_early_data_status in);
const char *mbedtls_ssl_early_data_state_str(mbedtls_ssl_early_data_state in);
#endif
const char *mbedtls_ssl_protocol_version_str(mbedtls_ssl_protocol_version in);
const char *mbedtls_tls_prf_types_str(mbedtls_tls_prf_types in);
const char *mbedtls_ssl_key_export_type_str(mbedtls_ssl_key_export_type in);
const char *mbedtls_ssl_sig_alg_to_str(uint16_t in);
const char *mbedtls_ssl_named_group_to_str(uint16_t in);
const char *mbedtls_ssl_get_extension_name(unsigned int extension_type);
void mbedtls_ssl_print_extensions(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
int hs_msg_type, uint32_t extensions_mask,
const char *extra);
void mbedtls_ssl_print_extension(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
int hs_msg_type, unsigned int extension_type,
const char *extra_msg0, const char *extra_msg1);
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
void mbedtls_ssl_print_ticket_flags(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
unsigned int flags);
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
#define MBEDTLS_SSL_PRINT_EXTS(level, hs_msg_type, extensions_mask) \
mbedtls_ssl_print_extensions(ssl, level, __FILE__, __LINE__, \
hs_msg_type, extensions_mask, NULL)
#define MBEDTLS_SSL_PRINT_EXT(level, hs_msg_type, extension_type, extra) \
mbedtls_ssl_print_extension(ssl, level, __FILE__, __LINE__, \
hs_msg_type, extension_type, \
extra, NULL)
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
#define MBEDTLS_SSL_PRINT_TICKET_FLAGS(level, flags) \
mbedtls_ssl_print_ticket_flags(ssl, level, __FILE__, __LINE__, flags)
#endif
#else
#define MBEDTLS_SSL_PRINT_EXTS(level, hs_msg_type, extension_mask)
#define MBEDTLS_SSL_PRINT_EXT(level, hs_msg_type, extension_type, extra)
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
#define MBEDTLS_SSL_PRINT_TICKET_FLAGS(level, flags)
#endif
#endif /* MBEDTLS_DEBUG_C */
#endif /* MBEDTLS_SSL_DEBUG_HELPERS_H */

View File

@@ -0,0 +1,251 @@
/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */
/**
* \file ssl_debug_helpers_generated.c
*
* \brief Automatically generated helper functions for debugging
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*
*/
#include "ssl_misc.h"
#if defined(MBEDTLS_DEBUG_C)
#include "ssl_debug_helpers.h"
const char *mbedtls_ssl_named_group_to_str( uint16_t in )
{
switch( in )
{
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP192K1:
return "secp192k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP192R1:
return "secp192r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP224K1:
return "secp224k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP224R1:
return "secp224r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP256K1:
return "secp256k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1:
return "secp256r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1:
return "secp384r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP521R1:
return "secp521r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP256R1:
return "bp256r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP384R1:
return "bp384r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP512R1:
return "bp512r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_X25519:
return "x25519";
case MBEDTLS_SSL_IANA_TLS_GROUP_X448:
return "x448";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE2048:
return "ffdhe2048";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE3072:
return "ffdhe3072";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE4096:
return "ffdhe4096";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE6144:
return "ffdhe6144";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE8192:
return "ffdhe8192";
};
return "UNKNOWN";
}
const char *mbedtls_ssl_sig_alg_to_str( uint16_t in )
{
switch( in )
{
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA256:
return "rsa_pkcs1_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA384:
return "rsa_pkcs1_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA512:
return "rsa_pkcs1_sha512";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256:
return "ecdsa_secp256r1_sha256";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP384R1_SHA384:
return "ecdsa_secp384r1_sha384";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP521R1_SHA512:
return "ecdsa_secp521r1_sha512";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA256:
return "rsa_pss_rsae_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA384:
return "rsa_pss_rsae_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA512:
return "rsa_pss_rsae_sha512";
case MBEDTLS_TLS1_3_SIG_ED25519:
return "ed25519";
case MBEDTLS_TLS1_3_SIG_ED448:
return "ed448";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA256:
return "rsa_pss_pss_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA384:
return "rsa_pss_pss_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA512:
return "rsa_pss_pss_sha512";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA1:
return "rsa_pkcs1_sha1";
case MBEDTLS_TLS1_3_SIG_ECDSA_SHA1:
return "ecdsa_sha1";
case MBEDTLS_TLS1_3_SIG_NONE:
return "none";
};
return "UNKNOWN";
}
const char *mbedtls_ssl_states_str( mbedtls_ssl_states in )
{
switch (in) {
case MBEDTLS_SSL_HELLO_REQUEST:
return "MBEDTLS_SSL_HELLO_REQUEST";
case MBEDTLS_SSL_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_HELLO:
return "MBEDTLS_SSL_SERVER_HELLO";
case MBEDTLS_SSL_SERVER_CERTIFICATE:
return "MBEDTLS_SSL_SERVER_CERTIFICATE";
case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
return "MBEDTLS_SSL_SERVER_KEY_EXCHANGE";
case MBEDTLS_SSL_CERTIFICATE_REQUEST:
return "MBEDTLS_SSL_CERTIFICATE_REQUEST";
case MBEDTLS_SSL_SERVER_HELLO_DONE:
return "MBEDTLS_SSL_SERVER_HELLO_DONE";
case MBEDTLS_SSL_CLIENT_CERTIFICATE:
return "MBEDTLS_SSL_CLIENT_CERTIFICATE";
case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
return "MBEDTLS_SSL_CLIENT_KEY_EXCHANGE";
case MBEDTLS_SSL_CERTIFICATE_VERIFY:
return "MBEDTLS_SSL_CERTIFICATE_VERIFY";
case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
return "MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC";
case MBEDTLS_SSL_CLIENT_FINISHED:
return "MBEDTLS_SSL_CLIENT_FINISHED";
case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
return "MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC";
case MBEDTLS_SSL_SERVER_FINISHED:
return "MBEDTLS_SSL_SERVER_FINISHED";
case MBEDTLS_SSL_FLUSH_BUFFERS:
return "MBEDTLS_SSL_FLUSH_BUFFERS";
case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
return "MBEDTLS_SSL_HANDSHAKE_WRAPUP";
case MBEDTLS_SSL_NEW_SESSION_TICKET:
return "MBEDTLS_SSL_NEW_SESSION_TICKET";
case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT:
return "MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT";
case MBEDTLS_SSL_HELLO_RETRY_REQUEST:
return "MBEDTLS_SSL_HELLO_RETRY_REQUEST";
case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS:
return "MBEDTLS_SSL_ENCRYPTED_EXTENSIONS";
case MBEDTLS_SSL_END_OF_EARLY_DATA:
return "MBEDTLS_SSL_END_OF_EARLY_DATA";
case MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY:
return "MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY";
case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED:
return "MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED";
case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO:
return "MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO";
case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST:
return "MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST";
case MBEDTLS_SSL_HANDSHAKE_OVER:
return "MBEDTLS_SSL_HANDSHAKE_OVER";
case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET:
return "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET";
case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:
return "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH";
default:
return "UNKNOWN_VALUE";
}
}
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
const char *mbedtls_ssl_early_data_status_str( mbedtls_ssl_early_data_status in )
{
switch (in) {
case MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_INDICATED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_INDICATED";
case MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED";
case MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED";
default:
return "UNKNOWN_VALUE";
}
}
#endif /* defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) */
const char *mbedtls_ssl_protocol_version_str( mbedtls_ssl_protocol_version in )
{
switch (in) {
case MBEDTLS_SSL_VERSION_UNKNOWN:
return "MBEDTLS_SSL_VERSION_UNKNOWN";
case MBEDTLS_SSL_VERSION_TLS1_2:
return "MBEDTLS_SSL_VERSION_TLS1_2";
case MBEDTLS_SSL_VERSION_TLS1_3:
return "MBEDTLS_SSL_VERSION_TLS1_3";
default:
return "UNKNOWN_VALUE";
}
}
const char *mbedtls_tls_prf_types_str( mbedtls_tls_prf_types in )
{
switch (in) {
case MBEDTLS_SSL_TLS_PRF_NONE:
return "MBEDTLS_SSL_TLS_PRF_NONE";
case MBEDTLS_SSL_TLS_PRF_SHA384:
return "MBEDTLS_SSL_TLS_PRF_SHA384";
case MBEDTLS_SSL_TLS_PRF_SHA256:
return "MBEDTLS_SSL_TLS_PRF_SHA256";
case MBEDTLS_SSL_HKDF_EXPAND_SHA384:
return "MBEDTLS_SSL_HKDF_EXPAND_SHA384";
case MBEDTLS_SSL_HKDF_EXPAND_SHA256:
return "MBEDTLS_SSL_HKDF_EXPAND_SHA256";
default:
return "UNKNOWN_VALUE";
}
}
const char *mbedtls_ssl_key_export_type_str( mbedtls_ssl_key_export_type in )
{
switch (in) {
case MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET";
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_EARLY_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_EARLY_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_EARLY_EXPORTER_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_EARLY_EXPORTER_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET";
#endif
default:
return "UNKNOWN_VALUE";
}
}
#endif /* MBEDTLS_DEBUG_C */
/* End of automatically generated file. */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

10187
lib/mbedtls_ssl/src/ssl_tls.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,668 @@
/*
* TLS 1.3 key schedule
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#if !defined(MBEDTLS_SSL_TLS1_3_KEYS_H)
#define MBEDTLS_SSL_TLS1_3_KEYS_H
/* This requires MBEDTLS_SSL_TLS1_3_LABEL( idx, name, string ) to be defined at
* the point of use. See e.g. the definition of mbedtls_ssl_tls13_labels_union
* below. */
#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \
MBEDTLS_SSL_TLS1_3_LABEL(finished, "finished") \
MBEDTLS_SSL_TLS1_3_LABEL(resumption, "resumption") \
MBEDTLS_SSL_TLS1_3_LABEL(traffic_upd, "traffic upd") \
MBEDTLS_SSL_TLS1_3_LABEL(exporter, "exporter") \
MBEDTLS_SSL_TLS1_3_LABEL(key, "key") \
MBEDTLS_SSL_TLS1_3_LABEL(iv, "iv") \
MBEDTLS_SSL_TLS1_3_LABEL(c_hs_traffic, "c hs traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(c_ap_traffic, "c ap traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(c_e_traffic, "c e traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_hs_traffic, "s hs traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_ap_traffic, "s ap traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_e_traffic, "s e traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(e_exp_master, "e exp master") \
MBEDTLS_SSL_TLS1_3_LABEL(res_master, "res master") \
MBEDTLS_SSL_TLS1_3_LABEL(exp_master, "exp master") \
MBEDTLS_SSL_TLS1_3_LABEL(ext_binder, "ext binder") \
MBEDTLS_SSL_TLS1_3_LABEL(res_binder, "res binder") \
MBEDTLS_SSL_TLS1_3_LABEL(derived, "derived") \
MBEDTLS_SSL_TLS1_3_LABEL(client_cv, "TLS 1.3, client CertificateVerify") \
MBEDTLS_SSL_TLS1_3_LABEL(server_cv, "TLS 1.3, server CertificateVerify")
#define MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED 0
#define MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED 1
#define MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL 0
#define MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION 1
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
/* We need to tell the compiler that we meant to leave out the null character. */
#define MBEDTLS_SSL_TLS1_3_LABEL(name, string) \
const unsigned char name [sizeof(string) - 1] MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING;
union mbedtls_ssl_tls13_labels_union {
MBEDTLS_SSL_TLS1_3_LABEL_LIST
};
struct mbedtls_ssl_tls13_labels_struct {
MBEDTLS_SSL_TLS1_3_LABEL_LIST
};
#undef MBEDTLS_SSL_TLS1_3_LABEL
extern const struct mbedtls_ssl_tls13_labels_struct mbedtls_ssl_tls13_labels;
#define MBEDTLS_SSL_TLS1_3_LBL_LEN(LABEL) \
sizeof(mbedtls_ssl_tls13_labels.LABEL)
#define MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(LABEL) \
mbedtls_ssl_tls13_labels.LABEL, \
MBEDTLS_SSL_TLS1_3_LBL_LEN(LABEL)
/* Maximum length of the label field in the HkdfLabel struct defined in
* RFC 8446, Section 7.1, excluding the "tls13 " prefix. */
#define MBEDTLS_SSL_TLS1_3_HKDF_LABEL_MAX_LABEL_LEN 249
/* The maximum length of HKDF contexts used in the TLS 1.3 standard.
* Since contexts are always hashes of message transcripts, this can
* be approximated from above by the maximum hash size. */
#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN \
PSA_HASH_MAX_SIZE
/* Maximum desired length for expanded key material generated
* by HKDF-Expand-Label. This algorithm can output up to 255 * hash_size
* bytes of key material where hash_size is the output size of the
* underlying hash function. */
#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN \
(255 * MBEDTLS_TLS1_3_MD_MAX_SIZE)
/**
* \brief The \c HKDF-Expand-Label function from
* the TLS 1.3 standard RFC 8446.
*
* <tt>
* HKDF-Expand-Label( Secret, Label, Context, Length ) =
* HKDF-Expand( Secret, HkdfLabel, Length )
* </tt>
*
* \param hash_alg The identifier for the hash algorithm to use.
* \param secret The \c Secret argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length
* \p secret_len Bytes.
* \param secret_len The length of \p secret in Bytes.
* \param label The \c Label argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length
* \p label_len Bytes.
* \param label_len The length of \p label in Bytes.
* \param ctx The \c Context argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length \p ctx_len Bytes.
* \param ctx_len The length of \p context in Bytes.
* \param buf The destination buffer to hold the expanded secret.
* This must be a writable buffer of length \p buf_len Bytes.
* \param buf_len The desired size of the expanded secret in Bytes.
*
* \returns \c 0 on success.
* \return A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_hkdf_expand_label(
psa_algorithm_t hash_alg,
const unsigned char *secret, size_t secret_len,
const unsigned char *label, size_t label_len,
const unsigned char *ctx, size_t ctx_len,
unsigned char *buf, size_t buf_len);
/**
* \brief This function is part of the TLS 1.3 key schedule.
* It extracts key and IV for the actual client/server traffic
* from the client/server traffic secrets.
*
* From RFC 8446:
*
* <tt>
* [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
* [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length)*
* </tt>
*
* \param hash_alg The identifier for the hash algorithm to be used
* for the HKDF-based expansion of the secret.
* \param client_secret The client traffic secret.
* This must be a readable buffer of size
* \p secret_len Bytes
* \param server_secret The server traffic secret.
* This must be a readable buffer of size
* \p secret_len Bytes
* \param secret_len Length of the secrets \p client_secret and
* \p server_secret in Bytes.
* \param key_len The desired length of the key to be extracted in Bytes.
* \param iv_len The desired length of the IV to be extracted in Bytes.
* \param keys The address of the structure holding the generated
* keys and IVs.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_make_traffic_keys(
psa_algorithm_t hash_alg,
const unsigned char *client_secret,
const unsigned char *server_secret, size_t secret_len,
size_t key_len, size_t iv_len,
mbedtls_ssl_key_set *keys);
/**
* \brief The \c Derive-Secret function from the TLS 1.3 standard RFC 8446.
*
* <tt>
* Derive-Secret( Secret, Label, Messages ) =
* HKDF-Expand-Label( Secret, Label,
* Hash( Messages ),
* Hash.Length ) )
* </tt>
*
* \param hash_alg The identifier for the hash function used for the
* applications of HKDF.
* \param secret The \c Secret argument to the \c Derive-Secret function.
* This must be a readable buffer of length
* \p secret_len Bytes.
* \param secret_len The length of \p secret in Bytes.
* \param label The \c Label argument to the \c Derive-Secret function.
* This must be a readable buffer of length
* \p label_len Bytes.
* \param label_len The length of \p label in Bytes.
* \param ctx The hash of the \c Messages argument to the
* \c Derive-Secret function, or the \c Messages argument
* itself, depending on \p ctx_hashed.
* \param ctx_len The length of \p ctx in Bytes.
* \param ctx_hashed This indicates whether the \p ctx contains the hash of
* the \c Messages argument in the application of the
* \c Derive-Secret function
* (value MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED), or whether
* it is the content of \c Messages itself, in which case
* the function takes care of the hashing
* (value MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED).
* \param dstbuf The target buffer to write the output of
* \c Derive-Secret to. This must be a writable buffer of
* size \p dtsbuf_len Bytes.
* \param dstbuf_len The length of \p dstbuf in Bytes.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_secret(
psa_algorithm_t hash_alg,
const unsigned char *secret, size_t secret_len,
const unsigned char *label, size_t label_len,
const unsigned char *ctx, size_t ctx_len,
int ctx_hashed,
unsigned char *dstbuf, size_t dstbuf_len);
/**
* \brief Derive TLS 1.3 early data key material from early secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels.
*
* <tt>
* Early Secret
* |
* +-----> Derive-Secret(., "c e traffic", ClientHello)
* | = client_early_traffic_secret
* |
* +-----> Derive-Secret(., "e exp master", ClientHello)
* . = early_exporter_master_secret
* .
* .
* </tt>
*
* \note To obtain the actual key and IV for the early data traffic,
* the client secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \note The binder key, which is also generated from the early secret,
* is omitted here. Its calculation is part of the separate routine
* mbedtls_ssl_tls13_create_psk_binder().
*
* \param hash_alg The hash algorithm associated with the PSK for which
* early data key material is being derived.
* \param early_secret The early secret from which the early data key material
* should be derived. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p md_size.
* \param transcript The transcript of the handshake so far, calculated with
* respect to \p hash_alg. This must be a readable buffer
* whose length is the digest size of the hash algorithm
* represented by \p md_size.
* \param derived The address of the structure in which to store
* the early data key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_early_secrets(
psa_algorithm_t hash_alg,
unsigned char const *early_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_early_secrets *derived);
/**
* \brief Derive TLS 1.3 handshake key material from the handshake secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* <tt>
* Handshake Secret
* |
* +-----> Derive-Secret( ., "c hs traffic",
* | ClientHello...ServerHello )
* | = client_handshake_traffic_secret
* |
* +-----> Derive-Secret( ., "s hs traffic",
* . ClientHello...ServerHello )
* . = server_handshake_traffic_secret
* .
* </tt>
*
* \note To obtain the actual key and IV for the encrypted handshake traffic,
* the client and server secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \param hash_alg The hash algorithm associated with the ciphersuite
* that's being used for the connection.
* \param handshake_secret The handshake secret from which the handshake key
* material should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake so far, calculated
* with respect to \p hash_alg. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param derived The address of the structure in which to
* store the handshake key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_handshake_secrets(
psa_algorithm_t hash_alg,
unsigned char const *handshake_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_handshake_secrets *derived);
/**
* \brief Derive TLS 1.3 application key material from the master secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* <tt>
* Master Secret
* |
* +-----> Derive-Secret( ., "c ap traffic",
* | ClientHello...server Finished )
* | = client_application_traffic_secret_0
* |
* +-----> Derive-Secret( ., "s ap traffic",
* | ClientHello...Server Finished )
* | = server_application_traffic_secret_0
* |
* +-----> Derive-Secret( ., "exp master",
* . ClientHello...server Finished)
* . = exporter_master_secret
* .
* </tt>
*
* \note To obtain the actual key and IV for the (0-th) application traffic,
* the client and server secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \param hash_alg The hash algorithm associated with the ciphersuite
* that's being used for the connection.
* \param master_secret The master secret from which the application key
* material should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake up to and including
* the ServerFinished message, calculated with respect
* to \p hash_alg. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p hash_alg.
* \param derived The address of the structure in which to
* store the application key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_application_secrets(
psa_algorithm_t hash_alg,
unsigned char const *master_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_application_secrets *derived);
/**
* \brief Derive TLS 1.3 resumption master secret from the master secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* \param hash_alg The hash algorithm used in the application for which
* key material is being derived.
* \param application_secret The application secret from which the resumption master
* secret should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake up to and including
* the ClientFinished message, calculated with respect
* to \p hash_alg. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p hash_alg.
* \param transcript_len The length of \p transcript in Bytes.
* \param derived The address of the structure in which to
* store the resumption master secret.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_resumption_master_secret(
psa_algorithm_t hash_alg,
unsigned char const *application_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_application_secrets *derived);
/**
* \brief Compute the next secret in the TLS 1.3 key schedule
*
* The TLS 1.3 key schedule proceeds as follows to compute
* the three main secrets during the handshake: The early
* secret for early data, the handshake secret for all
* other encrypted handshake messages, and the master
* secret for all application traffic.
*
* <tt>
* 0
* |
* v
* PSK -> HKDF-Extract = Early Secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* (EC)DHE -> HKDF-Extract = Handshake Secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* 0 -> HKDF-Extract = Master Secret
* </tt>
*
* Each of the three secrets in turn is the basis for further
* key derivations, such as the derivation of traffic keys and IVs;
* see e.g. mbedtls_ssl_tls13_make_traffic_keys().
*
* This function implements one step in this evolution of secrets:
*
* <tt>
* old_secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* input -> HKDF-Extract = new_secret
* </tt>
*
* \param hash_alg The identifier for the hash function used for the
* applications of HKDF.
* \param secret_old The address of the buffer holding the old secret
* on function entry. If not \c NULL, this must be a
* readable buffer whose size matches the output size
* of the hash function represented by \p hash_alg.
* If \c NULL, an all \c 0 array will be used instead.
* \param input The address of the buffer holding the additional
* input for the key derivation (e.g., the PSK or the
* ephemeral (EC)DH secret). If not \c NULL, this must be
* a readable buffer whose size \p input_len Bytes.
* If \c NULL, an all \c 0 array will be used instead.
* \param input_len The length of \p input in Bytes.
* \param secret_new The address of the buffer holding the new secret
* on function exit. This must be a writable buffer
* whose size matches the output size of the hash
* function represented by \p hash_alg.
* This may be the same as \p secret_old.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_evolve_secret(
psa_algorithm_t hash_alg,
const unsigned char *secret_old,
const unsigned char *input, size_t input_len,
unsigned char *secret_new);
/**
* \brief Calculate a TLS 1.3 PSK binder.
*
* \param ssl The SSL context. This is used for debugging only and may
* be \c NULL if MBEDTLS_DEBUG_C is disabled.
* \param hash_alg The hash algorithm associated to the PSK \p psk.
* \param psk The buffer holding the PSK for which to create a binder.
* \param psk_len The size of \p psk in bytes.
* \param psk_type This indicates whether the PSK \p psk is externally
* provisioned (#MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL) or a
* resumption PSK (#MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION).
* \param transcript The handshake transcript up to the point where the
* PSK binder calculation happens. This must be readable,
* and its size must be equal to the digest size of
* the hash algorithm represented by \p hash_alg.
* \param result The address at which to store the PSK binder on success.
* This must be writable, and its size must be equal to the
* digest size of the hash algorithm represented by
* \p hash_alg.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_create_psk_binder(mbedtls_ssl_context *ssl,
const psa_algorithm_t hash_alg,
unsigned char const *psk, size_t psk_len,
int psk_type,
unsigned char const *transcript,
unsigned char *result);
/**
* \bref Setup an SSL transform structure representing the
* record protection mechanism used by TLS 1.3
*
* \param transform The SSL transform structure to be created. This must have
* been initialized through mbedtls_ssl_transform_init() and
* not used in any other way prior to calling this function.
* In particular, this function does not clean up the
* transform structure prior to installing the new keys.
* \param endpoint Indicates whether the transform is for the client
* (value #MBEDTLS_SSL_IS_CLIENT) or the server
* (value #MBEDTLS_SSL_IS_SERVER).
* \param ciphersuite The numerical identifier for the ciphersuite to use.
* This must be one of the identifiers listed in
* ssl_ciphersuites.h.
* \param traffic_keys The key material to use. No reference is stored in
* the SSL transform being generated, and the caller
* should destroy the key material afterwards.
* \param ssl (Debug-only) The SSL context to use for debug output
* in case of failure. This parameter is only needed if
* #MBEDTLS_DEBUG_C is set, and is ignored otherwise.
*
* \return \c 0 on success. In this case, \p transform is ready to
* be used with mbedtls_ssl_transform_decrypt() and
* mbedtls_ssl_transform_encrypt().
* \return A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_populate_transform(mbedtls_ssl_transform *transform,
int endpoint,
int ciphersuite,
mbedtls_ssl_key_set const *traffic_keys,
mbedtls_ssl_context *ssl);
/*
* TLS 1.3 key schedule evolutions
*
* Early -> Handshake -> Application
*
* Small wrappers around mbedtls_ssl_tls13_evolve_secret().
*/
/**
* \brief Begin TLS 1.3 key schedule by calculating early secret.
*
* The TLS 1.3 key schedule can be viewed as a simple state machine
* with states Initial -> Early -> Handshake -> Application, and
* this function represents the Initial -> Early transition.
*
* \param ssl The SSL context to operate on.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_key_schedule_stage_early(mbedtls_ssl_context *ssl);
/**
* \brief Compute TLS 1.3 resumption master secret.
*
* \param ssl The SSL context to operate on. This must be in
* key schedule stage \c Application, see
* mbedtls_ssl_tls13_key_schedule_stage_application().
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_resumption_master_secret(mbedtls_ssl_context *ssl);
/**
* \brief Calculate the verify_data value for the client or server TLS 1.3
* Finished message.
*
* \param ssl The SSL context to operate on. This must be in
* key schedule stage \c Handshake, see
* mbedtls_ssl_tls13_key_schedule_stage_application().
* \param dst The address at which to write the verify_data value.
* \param dst_len The size of \p dst in bytes.
* \param actual_len The address at which to store the amount of data
* actually written to \p dst upon success.
* \param which The message to calculate the `verify_data` for:
* - #MBEDTLS_SSL_IS_CLIENT for the Client's Finished message
* - #MBEDTLS_SSL_IS_SERVER for the Server's Finished message
*
* \note Both client and server call this function twice, once to
* generate their own Finished message, and once to verify the
* peer's Finished message.
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_calculate_verify_data(mbedtls_ssl_context *ssl,
unsigned char *dst,
size_t dst_len,
size_t *actual_len,
int which);
#if defined(MBEDTLS_SSL_EARLY_DATA)
/**
* \brief Compute TLS 1.3 early transform
*
* \param ssl The SSL context to operate on.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*
* \warning The function does not compute the early master secret. Call
* mbedtls_ssl_tls13_key_schedule_stage_early() before to
* call this function to generate the early master secret.
* \note For a client/server endpoint, the function computes only the
* encryption/decryption part of the transform as the decryption/
* encryption part is not defined by the specification (no early
* traffic from the server to the client).
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_early_transform(mbedtls_ssl_context *ssl);
#endif /* MBEDTLS_SSL_EARLY_DATA */
/**
* \brief Compute TLS 1.3 handshake transform
*
* \param ssl The SSL context to operate on. The early secret must have been
* computed.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_handshake_transform(mbedtls_ssl_context *ssl);
/**
* \brief Compute TLS 1.3 application transform
*
* \param ssl The SSL context to operate on. The early secret must have been
* computed.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_application_transform(mbedtls_ssl_context *ssl);
#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
/**
* \brief Export TLS 1.3 PSK from handshake context
*
* \param[in] ssl The SSL context to operate on.
* \param[out] psk PSK output pointer.
* \param[out] psk_len Length of PSK.
*
* \returns \c 0 if there is a configured PSK and it was exported
* successfully.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_export_handshake_psk(mbedtls_ssl_context *ssl,
unsigned char **psk,
size_t *psk_len);
#endif
/**
* \brief Calculate TLS-Exporter function as defined in RFC 8446, Section 7.5.
*
* \param[in] hash_alg The hash algorithm.
* \param[in] secret The secret to use. (Should be the exporter master secret.)
* \param[in] secret_len Length of secret.
* \param[in] label The label of the exported key.
* \param[in] label_len The length of label.
* \param[out] out The output buffer for the exported key. Must have room for at least out_len bytes.
* \param[in] out_len Length of the key to generate.
*/
int mbedtls_ssl_tls13_exporter(const psa_algorithm_t hash_alg,
const unsigned char *secret, const size_t secret_len,
const unsigned char *label, const size_t label_len,
const unsigned char *context_value, const size_t context_len,
uint8_t *out, const size_t out_len);
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
#endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */

137
pio_local.ini_bak Normal file
View File

@@ -0,0 +1,137 @@
; example custom platformio ini file for EMS-ESP
[common]
; custom build flags to use in my_build_flags
; -DEMSESP_UART_DEBUG ; debugging UART
; -DEMSESP_DEBUG ; enables DEBUG to the log. Will generate a lot of extra traffic on Console and Syslog
; -DEMSESP_DEFAULT_BOARD_PROFILE=\"NODEMCU\" ; hard code the default board name
; -DEMSESP_DEBUG_SENSOR ; additional debug for the sensors
; -DCORE_DEBUG_LEVEL=5 ; verbose core level debugging 5=verbose, 4=debug, 3=info
; -DEMSESP_TEST ; enable the tests. EN language only
; -DEMSESP_DE_ONLY ; only DE translated entity names
; -DEMSESP_EN_ONLY ; only EN translated entity names
; -DEMSESP_PINGTEST ; send log message every 1/2 second
; my_build_flags = -DEMSESP_TEST -DEMSESP_DEBUG
; my_build_flags = -DEMSESP_DEBUG -DEMSESP_TEST -DEMSESP_PINGTEST
; my_build_flags = -DEMSESP_DEBUG -DCORE_DEBUG_LEVEL=5
; my_build_flags = -DEMSESP_EN_ONLY -DEMSESP_TEST -DCORE_DEBUG_LEVEL=5 -DARDUINO_USB_CDC_ON_BOOT=1
; my_build_flags = -DEMSESP_DEBUG
my_build_flags =
[platformio]
default_envs = s_16M_P ; build the web interface and the firmware for BBQKees E32V2
; default_envs = build_webUI ; build the web interface only
; default_envs = s3_16M_P ; BBQKees S3
; default_envs = s_4M ; BBQKees older S32, 4MB no psram
; default_envs = s_16M ; BBQKees newer S32 V2, 16MB no psram
; default_envs = c6 ; XIAO ESP32C
; default_envs = debug
; default_envs = core3
[env]
; uncomment if you want to upload the firmware via OTA (must have upload_protocol = custom)
extra_scripts =
post:scripts/rename_fw.py ; renames the firmware .bin file
scripts/upload.py ; optionally upload the firmware via OTA (must have upload_protocol = custom)
; set the username and password for the admin account (default password is admin)
custom_username = admin
custom_password = admin
; ** upload settings **
; for direct USB, which is the default you can set an optional port for example:
; upload_port = /dev/ttyUSB0
;
; for direct via HTTP (OTA) set:
; upload_protocol = custom
; custom_emsesp_ip = <ip address> or ems-esp.local
upload_protocol = custom
; custom_emsesp_ip = 10.10.10.175 ; Wemos Lolin S3
; custom_emsesp_ip = 192.168.1.65 ; E32V2.2 (test)
custom_emsesp_ip = 192.168.1.223 ; E32V2.1 (production/live)
; custom_emsesp_ip = 192.168.1.173 ; S32
; custom_emsesp_ip = 192.168.1.59 ; S32 (old) 4MB blue board
; lib_deps =
; bblanchon/ArduinoJson @ 7.4.2
; ESP32Async/AsyncTCP @ 3.4.10
; ESP32Async/ESPAsyncWebServer @ 3.9.5
; ; file://${PROJECT_DIR}/../modules/EMS-ESP-Modules
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
; [espressif32_base_16M]
; framework = arduino
; board_build.partitions = partitions/esp32_partition_16M.csv
; board_upload.flash_size = 16MB
; board_build.app_partition_name = app0
; ; platform = espressif32@6.12.0 ; Arduino Core v2.0.17 / IDF v4.4.7
; ; platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip ; Arduino Core v3.2.0 / ESP-IDF v5.4.1
; platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30/platform-espressif32.zip ; Arduino Core 3.3.0, IDF 5.5.0
; ** debug settings **
; to be used with an ESP32-S3 which has an onboard JTAG, connect the OTG USB port to the PC
; if using an external JTAG board like the ESP-PROG set debug_tool = esp-prog, and use zadig to set the correct driver for the USB port
; see https://docs.platformio.org/en/stable/projectconf/sections/env/options/debug/debug_init_break.html for settings
; use with my_build_flags = -DEMSESP_EN_ONLY -DEMSESP_TEST -DCORE_DEBUG_LEVEL=5 -DARDUINO_USB_CDC_ON_BOOT=1
[env:debug]
board = esp32-s3-devkitc-1
framework = arduino
platform = espressif32@6.12.0 ; Arduino Core v2.0.17 / IDF v4.4.7
board_build.partitions = partitions/esp32_partition_16M.csv
board_upload.flash_size = 16MB
board_build.app_partition_name = app0
board_build.filesystem = littlefs
upload_protocol = esptool
build_type = debug
monitor_raw = no
monitor_filters = colorize, esp32_exception_decoder
debug_tool = esp-builtin
debug_init_break =
upload_speed = 2000000
monitor_speed = 115200
extra_scripts =
[env:core3]
framework = arduino, espidf
board_build.partitions = partitions/esp32_partition_16M.csv
board_upload.flash_size = 16MB
board_build.app_partition_name = app0
; platform = espressif32@6.12.0 ; Arduino Core 2.0.17 / IDF 4.4.7
platform = espressif32
board = s_16M_P_T
lib_ignore = Zigbee
Micro-RTSP
epdiy
BLE
BluetoothSerial
SimpleBLE
WiFiProv
ESP_I2S
ESP_NOW
ESP_SR
Insights
Matter
OpenThread
RainMaker
SPIFFS
USB
NetworkClientSecure
custom_sdkconfig = file://${PROJECT_DIR}/sdkconfig_tasmota_esp32.txt
custom_component_remove = espressif/network_provisioning
espressif/esp-zboss-lib
espressif/esp-zigbee-lib
espressif/esp_rainmaker
espressif/rmaker_common
espressif/esp_insights
espressif/esp_diag_data_store
espressif/esp_diagnostics
espressif/cbor
espressif/qrcode
espressif/esp-sr
espressif/libsodium
espressif/esp-modbus
chmorgan/esp-libhelix-mp3
espressif/esp32-camera

View File

@@ -15,14 +15,13 @@ description = EMS-ESP Firmware for the ESP32
src_dir = src
lib_dir = lib
boards_dir = boards
; build_cache_dir = .pio/build_cache
extra_configs =
factory_settings.ini
pio_local.ini
[common]
core_build_flags = -std=c++17 -std=gnu++17 -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format
core_build_flags = -std=c++17 -std=gnu++17 -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format -Wno-missing-field-initializers
core_unbuild_flags = -std=gnu++11 -fno-lto
my_build_flags =
@@ -60,7 +59,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_16M.csv
board_upload.flash_size = 16MB
board_build.app_partition_name = app0
platform = espressif32@6.12.0 ; Arduino Core 2.0.17 / IDF 4.4.7
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
; 32MB Flash variants
[espressif32_base_32M]
@@ -68,7 +67,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_32M.csv
board_upload.flash_size = 32MB
board_build.app_partition_name = app0
platform = espressif32@6.12.0 ; Arduino Core 2.0.17 / IDF 4.4.7
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
; use Tasmota's library for 4MB Flash variants.
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
@@ -77,9 +76,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_4M.csv
board_upload.flash_size = 4MB
board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
; use Tasmota's library for 16MB Flash variants.
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
@@ -88,9 +85,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_16M.csv
board_upload.flash_size = 16MB
board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
[env]
build_flags =
@@ -107,8 +102,7 @@ lib_deps =
bblanchon/ArduinoJson @ 7.4.2
ESP32Async/AsyncTCP @ 3.4.10
ESP32Async/ESPAsyncWebServer @ 3.9.6
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
; builds the web interface only, not the firmware
[env:build_webUI]
@@ -174,8 +168,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_4M.csv
board_upload.flash_size = 4MB
board_build.app_partition_name = app0
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21-2/platform-espressif32.zip ; Arduino Release v3.2.1 based on ESP-IDF v5.4.2
; platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip ; Arduino Release v3.3.0 based on ESP-IDF v5.5.0
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip ; Arduino Release v3.3.0 based on ESP-IDF v5.5.0
board = seeed_xiao_esp32c6
build_flags =
${common.build_flags}

View File

@@ -76,11 +76,7 @@ void APSettingsService::manageAP() {
}
void APSettingsService::startAP() {
#if ESP_IDF_VERSION_MAJOR < 5
WiFi.softAPenableIpV6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
#else
WiFi.softAPenableIPv6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
#endif
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);

View File

@@ -66,21 +66,16 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) {
}
/*
* ESP32 uses mbedtls, with decent HMAC implementations supporting sha256, as well as others.
* No need to pull in additional crypto libraries - lets use what we already have.
* HMAC-SHA256 using mbedtls
*/
String ArduinoJsonJWT::sign(String & payload) {
std::array<unsigned char, 32> hmacResult{};
{
mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
mbedtls_md_hmac_starts(&ctx, reinterpret_cast<const unsigned char *>(_secret.c_str()), _secret.length());
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length());
mbedtls_md_hmac_finish(&ctx, hmacResult.data());
mbedtls_md_free(&ctx);
}
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
reinterpret_cast<const unsigned char *>(_secret.c_str()),
_secret.length(),
reinterpret_cast<const unsigned char *>(payload.c_str()),
payload.length(),
hmacResult.data());
return encode(reinterpret_cast<const char *>(hmacResult.data()), hmacResult.size());
}

View File

@@ -41,7 +41,7 @@ void MqttSettingsService::startClient() {
delete _mqttClient;
_mqttClient = nullptr;
}
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
if (_state.enableTLS) {
isSecure = true;
if (emsesp::EMSESP::system_.PSram() == 0) {
@@ -182,7 +182,7 @@ bool MqttSettingsService::configureMqtt() {
}
_reconfigureMqtt = false;
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
if (_state.enableTLS) {
if (_state.rootCA == "insecure") {
emsesp::EMSESP::logger().debug("Start insecure MQTT");
@@ -219,7 +219,7 @@ bool MqttSettingsService::configureMqtt() {
}
void MqttSettings::read(MqttSettings & settings, JsonObject root) {
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
root["enableTLS"] = settings.enableTLS;
root["rootCA"] = settings.rootCA;
#endif
@@ -258,7 +258,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
MqttSettings newSettings;
bool changed = false;
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
newSettings.enableTLS = root["enableTLS"];
newSettings.rootCA = root["rootCA"] | "";
#else
@@ -385,7 +385,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
}
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
// strip down to certificate only
newSettings.rootCA.replace("\r", "");
newSettings.rootCA.replace("\n", "");

View File

@@ -67,19 +67,15 @@ void NetworkSettingsService::loop() {
void NetworkSettingsService::manageSTA() {
// Abort if already connected, or if we have no SSID
if (WiFi.isConnected() || _state.ssid.length() == 0) {
#if ESP_IDF_VERSION_MAJOR >= 5
if (_state.ssid.length() == 0) {
ETH.enableIPv6(true);
}
#endif
return;
}
// Connect or reconnect as required
if ((WiFi.getMode() & WIFI_STA) == 0) {
#if ESP_IDF_VERSION_MAJOR >= 5
WiFi.enableIPv6(true);
#endif
if (_state.staticIPConfig) {
WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); // configure for static IP
}
@@ -305,7 +301,7 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
connectcount_++; // count the number of WiFi reconnects
connectcount_ = connectcount_ + 1; // count the number of WiFi reconnects
emsesp::EMSESP::logger().warning("WiFi disconnected (#%d). Reason: %s (%d)",
connectcount_,
disconnectReason(info.wifi_sta_disconnected.reason),
@@ -360,25 +356,15 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
if (_state.tx_power == 0) {
setWiFiPowerOnRSSI();
}
#if ESP_IDF_VERSION_MAJOR < 5
WiFi.enableIpV6(); // force ipv6
#endif
break;
case ARDUINO_EVENT_ETH_CONNECTED:
#if ESP_IDF_VERSION_MAJOR < 5
ETH.enableIpV6(); // force ipv6
#endif
break;
// IPv6 specific - WiFi/Eth
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
case ARDUINO_EVENT_ETH_GOT_IP6: {
#if !TASMOTA_SDK && ESP_IDF_VERSION_MAJOR < 5
auto ip6 = IPv6Address((uint8_t *)info.got_ip6.ip6_info.ip.addr).toString();
#else
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
#endif
const char * link = event == ARDUINO_EVENT_ETH_GOT_IP6 ? "Eth" : "WiFi";
if (ip6.startsWith("fe80")) {
emsesp::EMSESP::logger().info("IPv6 (%s) local: %s", link, ip6.c_str());

View File

@@ -2,7 +2,7 @@
#include <emsesp.h>
#ifdef TASMOTA_SDK
#ifdef NO_TLS_SUPPORT
#include "lwip/dns.h"
#endif
@@ -32,21 +32,12 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
if (ethernet_connected) {
// Ethernet
root["local_ip"] = ETH.localIP().toString();
#if ESP_IDF_VERSION_MAJOR < 5
root["local_ipv6"] = ETH.localIPv6().toString();
#else
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
#endif
root["mac_address"] = ETH.macAddress();
root["subnet_mask"] = ETH.subnetMask().toString();
root["gateway_ip"] = ETH.gatewayIP().toString();
#ifdef TASMOTA_SDK
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
#else
IPAddress dnsIP1 = ETH.dnsIP(0);
IPAddress dnsIP2 = ETH.dnsIP(1);
#endif
if (IPUtils::isSet(dnsIP1)) {
root["dns_ip_1"] = dnsIP1.toString();
}
@@ -55,11 +46,7 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
}
} else if (wifi_status == WL_CONNECTED) {
root["local_ip"] = WiFi.localIP().toString();
#if ESP_IDF_VERSION_MAJOR < 5
root["local_ipv6"] = WiFi.localIPv6().toString();
#else
root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
#endif
root["mac_address"] = WiFi.macAddress();
root["rssi"] = WiFi.RSSI();
root["ssid"] = WiFi.SSID();
@@ -71,14 +58,8 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
if (WiFi.gatewayIP() != INADDR_NONE) {
root["gateway_ip"] = WiFi.gatewayIP().toString();
}
#ifdef TASMOTA_SDK
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
#else
IPAddress dnsIP1 = WiFi.dnsIP(0);
IPAddress dnsIP2 = WiFi.dnsIP(1);
#endif
if (dnsIP1 != INADDR_NONE) {
root["dns_ip_1"] = dnsIP1.toString();
}

View File

@@ -0,0 +1,31 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include <emsesp.h>
void ModuleLibrary::list(JsonObject output) {};
void ModuleLibrary::loop() {};
void ModuleLibrary::start(emsesp::EMSESP * emsesp_main, bool test_mode) {};
bool ModuleLibrary::enable(const char * key, const char * license, bool enable) {
return true;
};

52
src/core/ModuleLibrary.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MODULELIBRARY_H
#define MODULELIBRARY_H
#include <Arduino.h>
#include <memory>
#include <vector>
#include <emsesp.h>
class ModuleLibrary {
public:
class Modules {
public:
Modules(const char * key, std::unique_ptr<Module> module)
: key(key)
, module(std::move(module)) {
}
const char * key;
std::unique_ptr<Module> module;
};
void start(emsesp::EMSESP * emsesp_main, bool test_mode = false);
void loop();
void list(JsonObject output);
bool enable(const char * key, const char * license, bool enable);
static uuid::log::Logger logger_;
private:
std::vector<Modules> modules_;
};
#endif

View File

@@ -346,23 +346,13 @@ void AnalogSensor::reload(bool get_nvs) {
sensor.polltime_ = sensor.value() != 0 ? uuid::get_uptime() + (sensor.factor() * 1000) : 0;
} else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) {
LOG_DEBUG("PWM output on GPIO %02d", sensor.gpio());
#if ESP_IDF_VERSION_MAJOR >= 5
ledcAttach(sensor.gpio(), sensor.factor(), 13);
#else
uint8_t channel = sensor.type() - AnalogType::PWM_0;
ledcSetup(channel, sensor.factor(), 13);
ledcAttachPin(sensor.gpio(), channel);
#endif
if (sensor.offset() > 100) {
sensor.set_offset(100);
} else if (sensor.offset() < 0) {
sensor.set_offset(0);
}
#if ESP_IDF_VERSION_MAJOR >= 5
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
#else
ledcWrite(channel, (uint32_t)(sensor.offset() * 8191 / 100));
#endif
sensor.set_value(sensor.offset());
sensor.set_uom(DeviceValueUOM::PERCENT);
publish_sensor(sensor);
@@ -1002,12 +992,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) {
}
sensor.set_offset(val);
sensor.set_value(val);
#if ESP_IDF_VERSION_MAJOR >= 5
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
#else
uint8_t channel = sensor.type() - AnalogType::PWM_0;
ledcWrite(channel, (uint32_t)(val * 8191 / 100));
#endif
} else {
return false;
}

View File

@@ -86,6 +86,6 @@ using string_vector = std::vector<const char *>;
// Translation count - dynamically calculated at compile-time
enum { EMSESP_TRANSLATION_COUNT_END = __COUNTER__ };
static constexpr uint16_t EMSESP_TRANSLATION_COUNT = EMSESP_TRANSLATION_COUNT_END - EMSESP_TRANSLATION_COUNT_START - 1;
static constexpr uint16_t EMSESP_TRANSLATION_COUNT = static_cast<int>(EMSESP_TRANSLATION_COUNT_END) - static_cast<int>(EMSESP_TRANSLATION_COUNT_START) - 1;
#endif

View File

@@ -293,12 +293,9 @@ enum {
#ifndef STRINGIZE
#define STRINGIZE(s) #s
#endif
#ifdef TASMOTA_SDK
#define ARDUINO_VERSION_STR(major, minor, patch) "Tasmota Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
#else
#define ARDUINO_VERSION_STR(major, minor, patch) "ESP32 Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
#endif
#define ARDUINO_VERSION ARDUINO_VERSION_STR(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
#endif
#endif
#endif

View File

@@ -604,20 +604,11 @@ void System::start() {
appfree_ = esp_ota_get_running_partition()->size / 1024 - appused_;
refreshHeapMem(); // refresh free heap and max alloc heap
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR < 5
temp_sensor_config_t temp_sensor = TSENS_CONFIG_DEFAULT();
temp_sensor_get_config(&temp_sensor);
temp_sensor.dac_offset = TSENS_DAC_DEFAULT; // DEFAULT: range:-10℃ ~ 80℃, error < 1℃.
temp_sensor_set_config(temp_sensor);
temp_sensor_start();
temp_sensor_read_celsius(&temperature_);
#else
temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
temperature_sensor_install(&temp_sensor_config, &temperature_handle_);
temperature_sensor_enable(temperature_handle_);
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
#endif
#endif
#endif
EMSESP::esp32React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
@@ -838,16 +829,9 @@ void System::send_info_mqtt() {
doc["IPv4 gateway"] = uuid::printable_to_string(WiFi.gatewayIP());
doc["IPv4 nameserver"] = uuid::printable_to_string(WiFi.dnsIP());
#if ESP_IDF_VERSION_MAJOR < 5
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
doc["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6());
}
#else
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
doc["IPv6 address"] = uuid::printable_to_string(WiFi.linkLocalIPv6());
}
#endif
}
#endif
Mqtt::queue_publish_retain(F_(info), doc.as<JsonObject>()); // topic called "info" and it's Retained
@@ -956,13 +940,8 @@ void System::network_init() {
delay(500);
digitalWrite(eth_power_, HIGH);
}
#if ESP_IDF_VERSION_MAJOR < 5
eth_present_ = ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
#else
eth_present_ = ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode);
#endif
#endif
}
// check health of system, done every 5 seconds
@@ -973,13 +952,9 @@ void System::system_check() {
#ifndef EMSESP_STANDALONE
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR < 5
temp_sensor_read_celsius(&temperature_);
#else
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
#endif
#endif
#endif
#ifdef EMSESP_PINGTEST
static uint64_t ping_count = 0;
@@ -1265,16 +1240,9 @@ void System::show_system(uuid::console::Shell & shell) {
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str());
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(WiFi.gatewayIP()).c_str());
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(WiFi.dnsIP()).c_str());
#if ESP_IDF_VERSION_MAJOR < 5
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.localIPv6()).c_str());
}
#else
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.linkLocalIPv6()).c_str());
}
#endif
break;
case WL_CONNECT_FAILED:
@@ -1305,15 +1273,9 @@ void System::show_system(uuid::console::Shell & shell) {
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str());
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(ETH.gatewayIP()).c_str());
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(ETH.dnsIP()).c_str());
#if ESP_IDF_VERSION_MAJOR < 5
if (ETH.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.localIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.localIPv6()).c_str());
}
#else
if (ETH.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.linkLocalIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.linkLocalIPv6()).c_str());
}
#endif
}
shell.println();

View File

@@ -37,11 +37,7 @@
#include <uuid/log.h>
#include <PButton.h>
#if ESP_ARDUINO_VERSION_MAJOR < 3
#define EMSESP_RGB_WRITE neopixelWrite
#else
#define EMSESP_RGB_WRITE rgbLedWrite
#endif
#if CONFIG_IDF_TARGET_ESP32
// there is no official API available on the original ESP32
@@ -49,12 +45,8 @@ extern "C" {
uint8_t temprature_sens_read();
}
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR < 5
#include "driver/temp_sensor.h"
#else
#include "driver/temperature_sensor.h"
#endif
#endif
using uuid::console::Shell;
@@ -501,9 +493,7 @@ class System {
uint32_t appfree_;
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR >= 5
temperature_sensor_handle_t temperature_handle_ = NULL;
#endif
#endif
float temperature_ = 0;
};

View File

@@ -52,7 +52,7 @@ void EMSuart::uart_event_task(void * pvParameters) {
uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
EMSESP::incoming_telegram(telegram, (uint8_t)(length - 1));
} else { // flush buffer up to break
uint8_t buf[UART_FIFO_LEN];
uint8_t buf[SOC_UART_FIFO_LEN];
uart_read_bytes(EMSUART_NUM, buf, length, portMAX_DELAY);
}
length = 0;
@@ -74,12 +74,8 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_APB
#if ESP_ARDUINO_VERSION_MAJOR >= 3
,
.flags = {0, 0}
#endif
};
.source_clk = UART_SCLK_APB,
.flags = {0}};
#if defined(EMSUART_RX_INVERT)
inverse_mask |= UART_SIGNAL_RXD_INV;
#endif
@@ -89,7 +85,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
uart_param_config(EMSUART_NUM, &uart_config);
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_set_line_inverse(EMSUART_NUM, inverse_mask);
uart_driver_install(EMSUART_NUM, UART_FIFO_LEN + 1, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
uart_driver_install(EMSUART_NUM, SOC_UART_FIFO_LEN + 1, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
uart_set_rx_full_threshold(EMSUART_NUM, 1);
uart_set_rx_timeout(EMSUART_NUM, 0); // disable

View File

@@ -458,23 +458,14 @@ void WebSettings::set_board_profile(WebSettings & settings) {
#if CONFIG_IDF_TARGET_ESP32
// check for no PSRAM, could be a E32 or S32?
if (!ESP.getPsramSize()) {
#if ESP_ARDUINO_VERSION_MAJOR < 3
if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) {
#else
if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
#endif
settings.board_profile = "E32"; // Ethernet without PSRAM
} else {
settings.board_profile = "S32"; // ESP32 standard WiFi without PSRAM
}
} else {
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
#if ESP_ARDUINO_VERSION_MAJOR < 3
if (ETH.begin(0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) {
#else
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
#endif
if (analogReadMilliVolts(39) > 700) { // core voltage > 2.6V
settings.board_profile = "E32V2_2"; // Ethernet, PSRAM, internal sensors
} else {