From 024e47e2dff92503119bc8d5008645170e619a3f Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:28:28 +0200 Subject: [PATCH 01/12] feat: own Security Event types (#5, Flowduino/ESPressio-Event#36) --- src/ESPressio_SecurityEvents.hpp | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/ESPressio_SecurityEvents.hpp diff --git a/src/ESPressio_SecurityEvents.hpp b/src/ESPressio_SecurityEvents.hpp new file mode 100644 index 0000000..9a6a65f --- /dev/null +++ b/src/ESPressio_SecurityEvents.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include + +namespace ESPressio::Event { + +class TransportSecurityConfigurationChangedEvent final : public Event<> { +public: + const Security::TransportSecurityConfig Before; + const Security::TransportSecurityConfig After; + TransportSecurityConfigurationChangedEvent( + const Security::TransportSecurityConfig& before, + const Security::TransportSecurityConfig& after + ) : Before(before), After(after) {} +}; + +class TransportSecuritySessionResetEvent final : public Event<> { +public: + const uint64_t PreviousSessionID; + explicit TransportSecuritySessionResetEvent(uint64_t previousSessionID) + : PreviousSessionID(previousSessionID) {} +}; + +class TransportSecuritySessionEstablishedEvent final : public Event<> { +public: + const uint64_t SessionID; + explicit TransportSecuritySessionEstablishedEvent(uint64_t sessionID) + : SessionID(sessionID) {} +}; + +class TransportSecurityReplayProtectionResetEvent final : public Event<> {}; + +class TransportSecurityFailureEvent final : public Event<> { +public: + const Security::SecurityResult Result; + explicit TransportSecurityFailureEvent(const Security::SecurityResult& result) + : Result(result) {} +}; + +} // namespace ESPressio::Event From 3dde1cd68338350eb47e875d2a153a91c5f14368 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:28:38 +0200 Subject: [PATCH 02/12] feat: own transport Security Event bridge (#5, Flowduino/ESPressio-Event#36) --- ...ESPressio_TransportSecurityEventBridge.hpp | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/ESPressio_TransportSecurityEventBridge.hpp diff --git a/src/ESPressio_TransportSecurityEventBridge.hpp b/src/ESPressio_TransportSecurityEventBridge.hpp new file mode 100644 index 0000000..843476f --- /dev/null +++ b/src/ESPressio_TransportSecurityEventBridge.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include "ESPressio_SecurityEvents.hpp" + +namespace ESPressio::Event { + +class TransportSecurityEventBridge final : + public Security::ITransportSecurityObserver { +private: + Observable::ObserverHandlePtr _observerHandle; + bool _initialized = false; + +public: + TransportSecurityEventBridge() = default; + TransportSecurityEventBridge(const TransportSecurityEventBridge&) = delete; + TransportSecurityEventBridge& operator=(const TransportSecurityEventBridge&) = delete; + + bool Initialize(Security::TransportSecurity& security) { + if (_initialized) return true; + _observerHandle = security.RegisterObserver(this); + _initialized = static_cast(_observerHandle); + return _initialized; + } + + void Shutdown() { + _observerHandle.reset(); + _initialized = false; + } + + bool IsInitialized() const { return _initialized; } + + void OnTransportSecurityConfigurationChanged( + const Security::TransportSecurityConfig& before, + const Security::TransportSecurityConfig& after + ) override { + (new TransportSecurityConfigurationChangedEvent(before, after))->Queue(); + } + + void OnTransportSecuritySessionReset(uint64_t previousSessionID) override { + (new TransportSecuritySessionResetEvent(previousSessionID))->Queue(); + } + + void OnTransportSecuritySessionEstablished(uint64_t sessionID) override { + (new TransportSecuritySessionEstablishedEvent(sessionID))->Queue(); + } + + void OnTransportSecurityReplayProtectionReset() override { + (new TransportSecurityReplayProtectionResetEvent())->Queue(); + } + + void OnTransportSecurityFailure(const Security::SecurityResult& result) override { + (new TransportSecurityFailureEvent(result))->Queue(); + } +}; + +} // namespace ESPressio::Event From 8413efcfc8a1313904aa2c2fb1a5504873c9d16b Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:43:56 +0200 Subject: [PATCH 03/12] chore: prepare Security 0.3.0 metadata (#5) --- library.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 6eb1ead..c291eb4 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,8 @@ { "name": "ESPressio-Security", - "version": "0.2.0", + "version": "0.3.0", "description": "Transport-neutral authenticated encryption, authentication and replay protection for the ESPressio Development Platform", - "keywords": "espressio,security,encryption,aead,aes,gcm,ccm,chacha20,poly1305,transport,authentication,replay,observable", + "keywords": "espressio,security,encryption,aead,aes,gcm,ccm,chacha20,poly1305,transport,authentication,replay,observable,event", "repository": {"type": "git", "url": "https://github.com/Flowduino/ESPressio-Security.git"}, "authors": {"name": "Flowduino", "maintainer": true, "url": "https://flowduino.com"}, "license": "Apache-2.0", From d34f30e4600f6fdb34d3145070e03697bb85e26f Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:44:03 +0200 Subject: [PATCH 04/12] chore: prepare Security 0.3.0 Arduino metadata (#5) --- library.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index 2ec80fe..ddddeb8 100644 --- a/library.properties +++ b/library.properties @@ -1,11 +1,11 @@ name=ESPressio-Security -version=0.2.0 +version=0.3.0 author=Flowduino maintainer=Flowduino sentence=Transport-neutral authenticated encryption and replay protection for ESPressio. -paragraph=Provides pluggable AEAD algorithms, key providers, authenticated transport envelopes, replay protection, security policies, observable security lifecycle notifications, and generic secure transport decoration. Includes mbedTLS AES-GCM, AES-CCM and ChaCha20-Poly1305 implementations when available. +paragraph=Provides pluggable AEAD algorithms, key providers, authenticated transport envelopes, replay protection, security policies, observable security lifecycle notifications, generic secure transport decoration, and an opt-in Event 6.x bridge owned by Security. category=Communication url=https://github.com/Flowduino/ESPressio-Security architectures=* includes=ESPressio_Security.hpp -depends=Flowduino ESPressio-Observable (>=3.0.1) +depends=Flowduino ESPressio-Observable (>=3.0.1 && <4.0.0) From 455883447329f105320571467382a67a6183dced Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:44:12 +0200 Subject: [PATCH 05/12] chore: align Security component version with 0.3.0 (#5) --- component.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/component.mk b/component.mk index b53eaa0..599dab9 100644 --- a/component.mk +++ b/component.mk @@ -3,6 +3,6 @@ COMPONENT_SRCDIRS := CXXFLAGS += -std=gnu++17 -frtti ESPRESSIO_SECURITY_VERSION_MAJOR := 0 -ESPRESSIO_SECURITY_VERSION_MINOR := 2 +ESPRESSIO_SECURITY_VERSION_MINOR := 3 ESPRESSIO_SECURITY_VERSION_PATCH := 0 -ESPRESSIO_SECURITY_VERSION := 0.2.0 +ESPRESSIO_SECURITY_VERSION := 0.3.0 From b58d88b4f3e31dc1762fb080248a301111ed2e00 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:44:24 +0200 Subject: [PATCH 06/12] docs: add Security 0.3.0 changelog (#5) --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05064ce..5efc167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to ESPressio Security are documented in this file. +## [0.3.0] - 2026-08-21 + +### Added + +- Moved Security lifecycle Event types and `TransportSecurityEventBridge` ownership into ESPressio Security. +- Added an opt-in Security -> Event integration targeting ESPressio Event 6.0.0 while keeping the normal Security core independent of Event. + +### Changed + +- Preserved the existing `ESPressio_SecurityEvents.hpp` and `ESPressio_TransportSecurityEventBridge.hpp` public names in their new owning package. +- Updated package metadata, documentation, dependency charts, and CI for the 0.3.0 architecture. +- The normal Security umbrella remains Event-free; Event is required only when the Event bridge headers are selected. + +### Compatibility + +- Core Security, encryption, replay-protection, and Observer APIs are unchanged. +- Applications using the Event bridge must obtain the bridge headers from ESPressio Security 0.3.0 rather than ESPressio Event 6.0.0. + +### Tracking + +- Implements #5. +- Coordinated with Flowduino/ESPressio-Event#36. + ## [0.2.0] - 2026-08-20 ### Added From 2dc466406233bf157775bd2d1c7f62a8aec7881c Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:44:42 +0200 Subject: [PATCH 07/12] docs: document Security-owned Event bridge (#5) --- README.md | 368 ++++++------------------------------------------------ 1 file changed, 37 insertions(+), 331 deletions(-) diff --git a/README.md b/README.md index 4e126a0..dd661c9 100644 --- a/README.md +++ b/README.md @@ -1,363 +1,69 @@ # ESPressio Security -Transport-neutral authenticated encryption, authentication, replay protection and key abstraction for the Flowduino ESPressio Development Platform. +Transport-neutral authenticated encryption, authentication, replay protection, and security policy for the Flowduino ESPressio Development Platform. -ESPressio Security protects **opaque transport payloads** without knowing whether they contain Events, Commands, clock synchronization messages, application packets, or another protocol. Concrete transports such as ESP-NOW, UDP, TCP and WebSockets can therefore opt into the same security layer while higher-level application protocols remain independent of cryptography. +## Current Version — 0.3.0 -## 0.2.0 Development Update — Observable Callback Coverage +Security 0.3.0 owns the optional Event representation of its own transport-security lifecycle. The Security core remains independent of ESPressio Event; Event is acquired only when the application explicitly selects the Security Event integration. -The `feature/observable-callback-coverage` branch targets **ESPressio Security 0.2.0**. The stable-release information below remains the historical 0.1.0 documentation until 0.2.0 is released. - -For 0.2.0, ESPressio Security adds a required dependency on **ESPressio Observable >= 3.0.1 and < 4.0.0** and introduces `ITransportSecurityObserver`. `TransportSecurity` now exposes synchronous observations for material configuration changes, security-session reset/establishment, replay-protection reset, and Security failures while preserving the existing `SecurityResult` return contract. - -ESPressio Event remains **optional**. ESPressio Event 5.8.0 adds `TransportSecurityEventBridge`, which binds to a specific `TransportSecurity` instance and converts those observations into asynchronous Events without making Event a Security dependency. Key material is never exposed through the observer or Event surfaces. - -On ESP32/Arduino, Observable's typed observer dispatch requires RTTI. PlatformIO projects consuming Security 0.2.0 must therefore enable RTTI at the **project level** because Arduino's default `-fno-rtti` applies to the application translation unit and cannot be reliably removed by a dependency's `library.json` alone: - -```ini -build_flags = - -std=gnu++17 - -frtti - -build_unflags = - -std=gnu++11 - -fno-rtti -``` - -Development-branch PlatformIO dependencies are therefore: - -```ini -lib_deps = - https://github.com/Flowduino/ESPressio-Security.git#feature/observable-callback-coverage - flowduino/ESPressio-Observable@^3.0.1 -``` - -The 0.2.0 host-test suite includes dedicated observable lifecycle coverage. See [CHANGELOG.md](CHANGELOG.md) for the complete 0.2.0 change list. - -## Latest Stable Version - -ESPressio Security is currently **0.1.0**. - -This is the initial release of the library. For release-by-release history, see [CHANGELOG.md](CHANGELOG.md). - -## Compatibility - -ESPressio Security targets **C++17** and is designed primarily for the **ESP32 family under Arduino-ESP32 / ESP-IDF** as part of the ESPressio Development Platform. - -The core interfaces, envelope codec, replay protection, key-provider abstractions and transport decorator are platform-neutral and host-testable. Concrete production AEAD implementations use **mbedTLS** when the corresponding headers are available in the selected platform build. - -Compatibility should be verified against the exact compiler, Arduino-ESP32/ESP-IDF version and ESP32 target used by the consuming application. - -## ESPressio Development Platform - -The **ESPressio Development Platform** is a collection of discrete, composable component libraries developed around a common design ethos. - -The principal objectives are: - -- **Light-weight** — minimise memory consumption and operational overhead without sacrificing correctness. -- **Ease of Use** — provide developer-friendly, strongly typed abstractions over lower-level facilities. -- **Object-Oriented** — a type for everything, and everything in a type. -- **SOLID** — apply SRP, OCP, LSP, ISP and DIP to the maximum extent practical within C++, Arduino, FreeRTOS and microcontroller constraints. - -ESPressio Security follows these principles by placing cryptographic algorithms, key retrieval, randomness, replay tracking and concrete transport adaptation behind focused interfaces. - -## License - -ESPressio and its component libraries are licensed under the **Apache License 2.0**. - -See [LICENSE](LICENSE) for details. - -## ESPressio Library Dependencies - -ESPressio Security has **no required ESPressio dependencies** in the stable 0.1.0 release. **The 0.2.0 development branch adds ESPressio Observable >= 3.0.1 and < 4.0.0 as a required dependency**, as described in the development update above. - -It is intentionally foundational and transport-neutral. Concrete communication libraries should depend optionally on Security, rather than Security depending on them: +## Core dependency ```text -ESPressio ESP-Now - - -> ESPressio Security -ESPressio Sockets - - -> ESPressio Security -future transports - - -> ESPressio Security +Security 0.3.0 + -> Observable >= 3.0.1 < 4.0.0 ``` -Event, Command and Timing do not need to depend directly on Security merely because their messages may be transported securely. ESPressio Event 5.8.0's Security bridge remains opt-in. +Security remains independent of ESP-Now, Sockets, Command, Serial, and Event at the core layer. -See [ESPRESSIO_DEPENDENCY_CHART.md](ESPRESSIO_DEPENDENCY_CHART.md). +## Optional Event integration -## Namespace - -The public API resides beneath: +Security 0.3.0 provides: ```cpp -ESPressio::Security -``` - -Principal public types include: - -- `IAeadCipher` — authenticated-encryption algorithm abstraction. -- `AeadCipherRegistry` — runtime registry/resolver for AEAD implementations. -- `IKeyProvider` — key lookup/provisioning abstraction. -- `StaticKeyProvider` — simple in-memory key provider. -- `IRandomSource` — random-byte abstraction. -- `ESP32RandomSource` — ESP32 platform random source. -- `TransportSecurity` — protects and authenticates opaque protocol payloads. -- `ReplayWindow` — per-sender/per-key/per-session sliding replay detector. -- `ITransportSecurityCarrier` — minimal concrete-transport adapter contract. -- `SecureTransportDecorator` — generic secure wrapper for a carrier. -- `ITransportSecurityObserver` — 0.2.0 synchronous observer for externally meaningful Security lifecycle changes. - -## PlatformIO - -For the stable 0.1.0 release: - -```ini -lib_deps = - flowduino/ESPressio-Security@^0.1.0 - -build_flags = - -std=gnu++17 - -build_unflags = - -std=gnu++11 -``` - -For 0.2.0 on ESP32/Arduino, add ESPressio Observable 3.x and enable RTTI at project level: - -```ini -lib_deps = - flowduino/ESPressio-Security@^0.2.0 - flowduino/ESPressio-Observable@^3.0.1 - -build_flags = - -std=gnu++17 - -frtti - -build_unflags = - -std=gnu++11 - -fno-rtti -``` - -To deliberately consume the current repository instead of a release: - -```ini -lib_deps = - https://github.com/Flowduino/ESPressio-Security.git -``` - -## Why Transport-Level Security? - -Security belongs between the application protocol and concrete transport: - -```text -Event / Command / Clock Sync / application protocol - | - v - Secure Transport - | - authenticate + decrypt - | - v - Concrete Transport - ESP-NOW / UDP / TCP / WS / ... +#include +#include ``` -Outbound processing is the reverse. This avoids implementing different cryptographic semantics independently in ESP-NOW, TCP, UDP or each higher-level ESPressio protocol. - -## Security Guarantees - -When `TransportSecurityPolicy::Required` is selected and a production AEAD implementation/key source is correctly configured, ESPressio Security is designed to provide: - -- **Confidentiality** — payload bytes are encrypted. -- **Integrity** — modified ciphertext or authenticated metadata is rejected. -- **Authentication** — only a holder of valid key material can generate an accepted protected packet. -- **Protocol binding** — the protocol identifier is authenticated and cannot be relabelled without invalidating the packet. -- **Replay protection** — previously authenticated sequences are rejected independently per sender, key and authenticated sender session. -- **Reboot-safe sequence restart** — a sender can start its sequence again at `1` after reboot because a fresh authenticated session/epoch ID creates a new replay domain. - -No plaintext is delivered to the protocol consumer until authentication/decryption succeeds. - -## AEAD Algorithm Abstraction - -Encryption is deliberately represented by `IAeadCipher`. `TransportSecurity` contains no AES-, CCM-, GCM- or ChaCha-specific logic. - -Algorithms are resolved through `AeadCipherRegistry`, allowing new implementations without changing the transport-security processor and allowing receivers to support multiple algorithms concurrently during migration. - -## Included AEAD Implementations - -When supported by the platform's mbedTLS build, Security provides: - -| Algorithm | Key | Nonce | Tag | Class | -| --- | ---: | ---: | ---: | --- | -| AES-128-GCM | 128-bit | 96-bit | 128-bit | `AES128GCMCipher` | -| AES-256-GCM | 256-bit | 96-bit | 128-bit | `AES256GCMCipher` | -| AES-128-CCM | 128-bit | 96-bit | 128-bit | `AES128CCMCipher` | -| AES-256-CCM | 256-bit | 96-bit | 128-bit | `AES256CCMCipher` | -| ChaCha20-Poly1305 | 256-bit | 96-bit | 128-bit | `ChaCha20Poly1305Cipher` | - -Availability macros are exposed as `ESPRESSIO_SECURITY_HAS_MBEDTLS_GCM`, `ESPRESSIO_SECURITY_HAS_MBEDTLS_CCM` and `ESPRESSIO_SECURITY_HAS_MBEDTLS_CHACHAPOLY`. - -The default outbound algorithm is **AES-256-GCM**. Algorithm choice remains an application/security-policy decision; the library does not silently substitute one production algorithm for another. - -## Security Envelope - -Protected packets use a versioned transport-neutral envelope. Version 1 authenticates: +The integration requires: ```text -magic -version -algorithm -flags -protocol ID -key ID -sender ID -session / epoch ID -sequence -nonce length -tag length -ciphertext length +ESPressio Event >= 6.0.0 < 7.0.0 ``` -The fixed header is AEAD associated authenticated data. A valid encrypted Event packet therefore cannot be relabelled as a Command packet, assigned to another sender session, or have its sequence changed without authentication failure. The envelope carries **key IDs, never keys**. - -## Security Policies - -`TransportSecurityPolicy` provides three explicit modes: - -- `Disabled` — outbound data remains plaintext and plaintext inbound data is accepted. -- `Preferred` — security is used when the requested cipher/key is available; plaintext is accepted and outbound payloads may fall back to plaintext. This is a migration/interoperability mode. -- `Required` — protected outbound transmission fails if encryption cannot be performed, and plaintext inbound packets are rejected. - -`Required` is the recommended policy whenever security is an actual requirement. - -## Key Providers and Rotation - -Key retrieval is abstracted through `IKeyProvider`. The initial library includes `StaticKeyProvider` for simple applications/tests. +and converts `ITransportSecurityObserver` notifications into asynchronous Event types for configuration, session, replay-protection, and failure lifecycle changes. -Multiple key IDs can coexist, allowing receivers to accept an old and new key during rotation while transmitters move to a new `OutboundKeyID`. +The public header and class names remain unchanged from their previous location in ESPressio Event; ownership now matches the Security domain. -Production systems are encouraged to implement `IKeyProvider` using an appropriate secure provisioning/storage strategy rather than hard-coding secrets into source code. `StaticKeyProvider` performs best-effort in-memory erasure on removal/destruction but cannot guarantee that no historical compiler/platform copy exists elsewhere in memory. - -## Randomness, Nonces and Session IDs - -`IRandomSource` abstracts cryptographic randomness. On ESP32, use `ESP32RandomSource`, which uses the ESP platform random facility. - -`StandardRandomSource` exists for portable/host use. `std::random_device` quality is implementation-dependent and should not be assumed to provide production embedded cryptographic entropy on every platform. - -Each protected packet carries a nonce explicitly. AEAD nonce uniqueness for a given key remains security-critical. - -`TransportSecurityConfig::SessionID` defaults to zero. On the first protected transmission, `TransportSecurity` then generates a fresh non-zero 64-bit session ID from `IRandomSource`. The generated value remains stable for that `TransportSecurity` session and is exposed through `GetSessionID()` for diagnostics/identity correlation. - -Applications that manage epochs externally may supply a non-zero `SessionID` explicitly. Calling `SetConfig()` resets the outbound sequence and replay state; a zero `SessionID` causes a new automatic session to be generated on the next protected send. - -## Replay Protection - -Each authenticated envelope contains a non-zero 64-bit session ID and sequence number. `ReplayWindow` tracks sequences independently by: +## Dependency direction ```text -sender ID + key ID + session ID -``` - -A sliding window permits limited legitimate reordering while rejecting duplicates and stale packets within that session. Replay state is committed **only after successful AEAD authentication and protocol validation**, so forged packets cannot poison replay state. - -This permits a sender to reboot, generate a new authenticated session ID, reset its sequence to `1`, and remain acceptable to receivers that have already seen much larger sequence numbers from its previous session. - -`ResetReplayProtection()` remains available for explicit administrative/session-boundary use. - -## Observable Security Lifecycle (0.2.0) - -`TransportSecurity` can be observed directly: +Security core + -> Observable -```cpp -#include - -class SecurityObserver final : - public ESPressio::Security::ITransportSecurityObserver { -public: - void OnTransportSecuritySessionEstablished(uint64_t sessionID) override { - // Record or display the authenticated session identity. - } - - void OnTransportSecurityFailure( - const ESPressio::Security::SecurityResult& result - ) override { - // Diagnostics/metrics only; ordinary return-value handling remains authoritative. - } -}; - -SecurityObserver observer; -auto handle = security.RegisterObserver(&observer); -``` - -Available observations are: - -- configuration changed; -- security session reset; -- security session established; -- replay protection reset; -- security failure. - -The observation layer is intentionally passive. It does not replace the ordinary `Protect()` / `Unprotect()` result model and it never exposes key material. - -## Optional ESPressio Event Bridge (0.2.0) - -ESPressio Event **5.8.0+** provides the opt-in bridge: - -```cpp -#include - -ESPressio::Event::TransportSecurityEventBridge bridge(security); +Security Event integration + - - -> Event ``` -This converts Security observations to asynchronous ESPressio Events while keeping the dependency direction correct: Security depends only on Observable; Event optionally adapts Security. +Event 6.0.0 does not depend back on Security. The standard `ESPressio_Security.hpp` umbrella does not include the Event integration. -## Generic Transport Decoration +## Final coordinated generation -`SecureTransportDecorator` can wrap any `ITransportSecurityCarrier`: - -```cpp -SecureTransportDecorator secure(carrier, security); -secure.Send(protocolID, payload); +```text +Observable 3.0.1 +Serializable 0.10.2 +Units 0.2.3 +Timing 2.2.4 +Threads 3.1.4 +Command 0.4.0 +Security 0.3.0 +Event 6.0.0 +Sockets 0.6.0 +ESP-Now 0.6.0 +Serial 0.6.0 ``` -Inbound carrier packets are authenticated/decrypted before the registered receive callback is invoked. Authentication failure, replay rejection or protocol mismatch therefore prevents plaintext delivery. - -Concrete transport libraries may alternatively integrate `TransportSecurity` directly where their callback/threading model makes that more natural. - -## Concurrency Model - -The initial `TransportSecurity` implementation protects mutable outbound sequence/replay state and configuration transitions with a lightweight internal mutex when `` is available. - -For embedded integrations, applications should nevertheless prefer a single well-defined security ownership/execution context per security instance where practical. This keeps transport callback behavior deterministic and avoids avoidable contention. +See [TRANSPORT_SECURITY.md](TRANSPORT_SECURITY.md) for the transport-security model, [ESPRESSIO_DEPENDENCY_CHART.md](ESPRESSIO_DEPENDENCY_CHART.md) for dependency relationships, and [CHANGELOG.md](CHANGELOG.md) for release history. -## Testing - -Host tests cover: - -- envelope encode/decode; -- AES-GCM protect/unprotect where available; -- protocol binding; -- replay rejection; -- sender-session scoped replay behavior; -- automatic outbound session generation; -- tamper rejection; -- key rotation; -- policy behavior; -- transport decoration; -- Observable lifecycle notifications and observer-handle lifetime; -- compile coverage for the mbedTLS wrapper interfaces. - -ESP32 CI additionally builds the production examples with the documented project-level RTTI configuration required by Observable's typed observer dispatch. - -## Operational Notes - -- Prefer `TransportSecurityPolicy::Required` where secure transport is actually required. -- Avoid hard-coding production keys into firmware source. -- Treat authenticated sender/session metadata as identity input, not as authorization policy by itself. -- Use a secure provisioning/storage strategy appropriate to the deployment. -- Keep production mbedTLS/Arduino-ESP32/ESP-IDF versions under update and vulnerability-management processes. -- Treat `Preferred` as a migration mode, not equivalent security to `Required`. -- Keep replay windows sized for the expected amount of legitimate packet reordering. -- Ensure ESP32/Arduino PlatformIO builds enable RTTI (`-frtti` and removal of `-fno-rtti`) when using Observable-backed Security 0.2.x. - -## Changelog +## License -See [CHANGELOG.md](CHANGELOG.md). +Apache License 2.0. See [LICENSE](LICENSE). From 908887ed0e4011e0ccb2b65d9eec8da1be29f785 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:44:52 +0200 Subject: [PATCH 08/12] docs: update Security 0.3.0 dependency chart (#5) --- ESPRESSIO_DEPENDENCY_CHART.md | 50 +++++++++++++++-------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/ESPRESSIO_DEPENDENCY_CHART.md b/ESPRESSIO_DEPENDENCY_CHART.md index 5f2bed0..df3a20c 100644 --- a/ESPRESSIO_DEPENDENCY_CHART.md +++ b/ESPRESSIO_DEPENDENCY_CHART.md @@ -1,38 +1,32 @@ -# ESPressio Library Dependency Chart +# ESPressio Dependency Chart — Security 0.3.0 -ESPressio Security is a foundational, transport-neutral library. +![ESPressio Library Dependency Chart](ESPRESSIO_DEPENDENCY_CHART.svg) -## ESPressio Security 0.1.0 - -**Required ESPressio dependencies: none.** - -Security owns authenticated encryption, key lookup, security envelopes, replay protection and transport-security policy. It deliberately does not depend on concrete communication libraries. - -The intended opt-in dependency direction is: +## Security 0.3.0 ```text -ESPressio ESP-Now - - -> ESPressio Security -ESPressio Sockets - - -> ESPressio Security -future transports - - -> ESPressio Security +Security 0.3.0 + -> Observable >= 3.0.1 < 4.0.0 + - - -> Event >= 6.0.0 < 7.0.0 + Security Event types / TransportSecurityEventBridge only ``` -Higher-level protocols remain independent of cryptography: +The Event relationship is opt-in. Core Security remains Event-free and transport-neutral. + +## Final coordinated ecosystem ```text -Event / Command / Clock Synchronization / application protocol - | - v - Secure transport adapter - | - v - ESPressio Security - | - v - concrete transport +Observable 3.0.1 +Serializable 0.10.2 +Units 0.2.3 +Timing 2.2.4 +Threads 3.1.4 +Command 0.4.0 +Security 0.3.0 +Event 6.0.0 +Sockets 0.6.0 +ESP-Now 0.6.0 +Serial 0.6.0 ``` -Security therefore sits beside other foundational ESPressio facilities rather than beneath Event, Command, ESP-Now, or Sockets as a mandatory dependency. - -## Architectural rule - -Security is applied at the transport boundary. A received protected packet is authenticated and decrypted before its plaintext is delivered to the protocol consumer. Packets failing authentication, policy, protocol binding, envelope validation or replay checks are discarded before application processing. +Security owns its Security-specific Event bridge. Event 6.0.0 does not depend back on Security, so no reciprocal edge remains. From 424a9693c24bb6cb3a91c72bce8300fd8857cb3e Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:45:02 +0200 Subject: [PATCH 09/12] docs: add graphical Security 0.3.0 dependency chart (#5) --- ESPRESSIO_DEPENDENCY_CHART.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 ESPRESSIO_DEPENDENCY_CHART.svg diff --git a/ESPRESSIO_DEPENDENCY_CHART.svg b/ESPRESSIO_DEPENDENCY_CHART.svg new file mode 100644 index 0000000..dd6e1dc --- /dev/null +++ b/ESPRESSIO_DEPENDENCY_CHART.svg @@ -0,0 +1 @@ +ESPressio Dependency Chart — Security 0.3.0Observable 3.0.1Security 0.3.0Event 6.0.0optional Event bridgeCore Security depends only on Observable. Event is selected only by Security-owned Event integration headers. \ No newline at end of file From eea8f8c176721891f4dc96741eb58198fe3f5c4b Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 20:45:14 +0200 Subject: [PATCH 10/12] ci: validate Security-owned Event integration and optional boundary (#5) --- .github/workflows/host-tests.yml | 86 +++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 2c4e81d..27b393c 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -2,9 +2,6 @@ name: Tests on: push: - branches: - - main - - feature/observable-callback-coverage pull_request: branches: [main] @@ -13,6 +10,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Verify core Security remains Event-free + run: | + if grep -R -nE '#[[:space:]]*include[[:space:]]*[<\"]ESPressio_(Event|SecurityEvents|TransportSecurityEventBridge)' src/ESPressio_Security.hpp; then + echo 'Core Security umbrella must not acquire Event integration.' + exit 1 + fi - name: Configure run: cmake -S tests -B build - name: Build @@ -20,46 +23,69 @@ jobs: - name: Test run: ctest --test-dir build --output-on-failure - esp32-examples: + esp32-event-integration: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + path: project/ESPressio-Security - uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Observable ref: 3.0.1 - path: deps/ESPressio-Observable + path: project/dependencies/ESPressio-Observable + - uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Units + ref: 0.2.3 + path: project/dependencies/ESPressio-Units + - uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Timing + ref: 2.2.4 + path: project/dependencies/ESPressio-Timing + - uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Threads + ref: 3.1.4 + path: project/dependencies/ESPressio-Threads + - uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Event + ref: reintegration/6.0.0-event-architecture + path: project/dependencies/ESPressio-Event + - uses: actions/setup-python@v5 + with: + python-version: '3.x' - name: Install PlatformIO run: pip install platformio - - name: Create PlatformIO consumer project + - name: Create Event integration compile project shell: bash run: | - mkdir -p "$RUNNER_TEMP/espressio-security-ci/src" "$RUNNER_TEMP/espressio-security-ci/lib" - rsync -a --exclude='.git' --exclude='deps' --exclude='build' ./ "$RUNNER_TEMP/espressio-security-ci/lib/ESPressio-Security/" - cp -R deps/ESPressio-Observable "$RUNNER_TEMP/espressio-security-ci/lib/ESPressio-Observable" - cat > "$RUNNER_TEMP/espressio-security-ci/platformio.ini" <<'EOF' - [env:esp32dev] + mkdir -p project/compile/src + cat > project/compile/platformio.ini <<'EOF' + [env:esp32] platform = espressif32 board = esp32dev framework = arduino - build_flags = - -std=gnu++17 - -frtti - build_unflags = - -std=gnu++11 - -fno-rtti + build_flags = -std=gnu++17 -frtti + build_unflags = -std=gnu++11 -fno-rtti + lib_ldf_mode = deep+ lib_deps = - ESPressio-Security - ESPressio-Observable + ../dependencies/ESPressio-Observable + ../dependencies/ESPressio-Units + ../dependencies/ESPressio-Timing + ../dependencies/ESPressio-Threads + ../dependencies/ESPressio-Event + ../ESPressio-Security EOF - - name: Compile BasicSecurePayload - shell: bash - run: | - cp examples/BasicSecurePayload/BasicSecurePayload.ino "$RUNNER_TEMP/espressio-security-ci/src/main.cpp" - pio run -d "$RUNNER_TEMP/espressio-security-ci" - - name: Compile MbedTLSAlgorithms - shell: bash - run: | - rm -rf "$RUNNER_TEMP/espressio-security-ci/.pio" - cp examples/MbedTLSAlgorithms/MbedTLSAlgorithms.ino "$RUNNER_TEMP/espressio-security-ci/src/main.cpp" - pio run -d "$RUNNER_TEMP/espressio-security-ci" + cat > project/compile/src/main.cpp <<'EOF' + #include + #include + #include + #include + void setup() {} + void loop() {} + EOF + - name: Compile Security Event integration + run: pio run -d project/compile From 3f84a1379e7c89a33bfaa3c0278a2f4ac8b6addd Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 21:04:05 +0200 Subject: [PATCH 11/12] docs: record Security optional Event boundary (#5) --- DEPENDENCY_BOUNDARIES.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 DEPENDENCY_BOUNDARIES.md diff --git a/DEPENDENCY_BOUNDARIES.md b/DEPENDENCY_BOUNDARIES.md new file mode 100644 index 0000000..499fd29 --- /dev/null +++ b/DEPENDENCY_BOUNDARIES.md @@ -0,0 +1,7 @@ +# ESPressio Security Dependency Boundaries + +ESPressio Security owns Security-specific lifecycle semantics and their optional Event representation. + +The core Security mechanism depends on Observable and remains independent of ESPressio Event. `TransportSecurityEventBridge` and the Security Event family are optional integration headers owned by Security and may depend on Event only when explicitly selected. + +The normal Security umbrella must remain free of Event includes. From b7d2b308ac67154736766e054b028c3eb4dd4994 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 21:16:50 +0200 Subject: [PATCH 12/12] ci: validate Security Event integration against released Event 6.0.0 (#5) --- .github/workflows/host-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 27b393c..f623a4e 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -52,7 +52,7 @@ jobs: - uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Event - ref: reintegration/6.0.0-event-architecture + ref: 6.0.0 path: project/dependencies/ESPressio-Event - uses: actions/setup-python@v5 with: