Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,18 @@ It builds on a baseline that simulates the sort of device you might be adding th
measures itself: see [docs/baseline.md](docs/baseline.md) for what the baseline is, how the
figures are made, and how to run it.

## This stage — Private SD-ELEMENT
## This stage — Mutual TLS

RFC 5424 records carry structured data: named groups of key/value pairs a collector parses rather
than pattern-matches out of the message text. Everything used so far has been standard elements,
which mean the same on any device. This stage defines one of our own — which is where a product
says what only it knows, and `app/syslog/SyslogPipelineSd.c` is all it takes to write one.
The device presents its own certificate, and the collector moves to 6515 — the port that requires
one, and refuses any client that cannot produce it.

`logPipeline@32473` reports the protection the record's own path was under: `transport="tls"`,
`atRest="hmac-sha256"`, under our IANA enterprise number so a private name cannot collide with
anyone else's. A collector can confirm that rather than assume it, and alert on a device whose
pipeline has weakened.
Server-authenticated TLS proves the device is talking to the right collector. Mutual TLS also
proves to the collector which device is talking, so a record is attributable to the holder of a
provisioned key rather than to anything that could reach the port.

<!-- STAGE-COST:START (generated by scripts/gen-cost-table.py — do not edit by hand) -->

**Cost above baseline: Flash +13,548 B, RAM +35,688 B.**
**Cost above baseline: Flash +13,624 B, RAM +37,740 B.**

<!-- STAGE-COST:END -->

Expand Down Expand Up @@ -56,6 +53,7 @@ committed as [`run-report.md`](run-report.md), and rewritten by every stage.
| TLS | a collector the device authenticates, and records no longer readable on the wire | +13,076 | +35,664 |
| HMAC at rest | stored records that cannot be edited undetected, not merely checked for corruption | +13,424 | +35,684 |
| Private SD-ELEMENT | a record that states the protection its own log pipeline was under | +13,548 | +35,688 |
| Mutual TLS | a collector that knows which device sent the record, not just that one did | +13,624 | +37,740 |

*Deltas are bytes above the baseline, which is itself Flash 350,308 B, RAM 111,192 B.*

Expand Down
2 changes: 1 addition & 1 deletion app/AppConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@
* headroom, not spare capacity: buffer_alloc hands out contiguous space, so a
* buffer only a little over the peak fails on fragmentation rather than on
* capacity. Applied again wherever more is asked of mbedTLS. */
#define SIMULATED_APP_MBEDTLS_HEAP_BYTES (53 * 1024)
#define SIMULATED_APP_MBEDTLS_HEAP_BYTES (55 * 1024)

#endif /* APP_CONFIG_H */
11 changes: 9 additions & 2 deletions app/syslog/Syslog.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
* the resolver numeric-only — no DNS, so no LWIP_DNS and no DNS resolver
* component to compile. */
#define SYSLOG_COLLECTOR_HOST "10.0.2.2"
#define SYSLOG_COLLECTOR_PORT ((uint16_t) 6514U)
#define SYSLOG_COLLECTOR_PORT ((uint16_t) 6515U)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/* Absorbs records logged while the service task is busy sending. Many devices can
* reduce this further: the store holds the backlog, so the ring only has to cover
Expand Down Expand Up @@ -147,13 +147,20 @@ void Syslog_Start(void)

struct SolidSyslogLwipRawTcpStreamConfig tcpConfig = {.Sleep = SyslogSleep};

/* Both must be set: either one NULL disables mTLS silently, which is why the
* pipeline element reports what was configured rather than what was intended. */
struct mbedtls_x509_crt* clientChain = DeviceCertStore_ClientChain();
struct mbedtls_pk_context* clientKey = DeviceCertStore_ClientKey();

/* ServerName must match the name in the collector's certificate. */
struct SolidSyslogMbedTlsStreamConfig tlsConfig = {
.Transport = SolidSyslogLwipRawTcpStream_Create(&tcpConfig),
.Sleep = SyslogSleep,
.Rng = DeviceCertStore_Rng(),
.CaChain = DeviceCertStore_CaChain(),
.ServerName = SYSLOG_COLLECTOR_HOST,
.ClientCertChain = clientChain,
.ClientKey = clientKey,
};

/* No EndpointVersion — this collector never moves, so the sender resolves
Expand Down Expand Up @@ -183,7 +190,7 @@ void Syslog_Start(void)
.GetIpAt = SyslogOriginIpAt,
};
s_sd[2] = SolidSyslogOriginSd_Create(&originConfig);
s_sd[3] = SyslogPipelineSd_Get();
s_sd[3] = SyslogPipelineSd_Init((clientChain != NULL) && (clientKey != NULL));

struct SolidSyslogMbedTlsHmacSha256PolicyConfig hmacConfig = {.GetKey = SyslogStoreKey};

Expand Down
7 changes: 5 additions & 2 deletions app/syslog/SyslogPipelineSd.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
#include "SolidSyslogSdValue.h"
#include "SolidSyslogStructuredDataDefinition.h"

static const char* s_transport = "tls";

/* A non-zero enterprise number is what makes the SD-ID private: _Begin emits
* "name@number" for one, a bare IANA "name" for 0. */
static void SyslogPipelineSd_Format(struct SolidSyslogStructuredData* base, struct SolidSyslogSdElement* element)
{
(void) base;

SolidSyslogSdElement_Begin(element, "logPipeline", SYSLOG_ENTERPRISE_NUMBER);
SolidSyslogSdValue_String(SolidSyslogSdElement_Param(element, "transport"), "tls");
SolidSyslogSdValue_String(SolidSyslogSdElement_Param(element, "transport"), s_transport);
SolidSyslogSdValue_String(SolidSyslogSdElement_Param(element, "atRest"), "hmac-sha256");
SolidSyslogSdElement_End(element);
}
Expand All @@ -24,7 +26,8 @@ static void SyslogPipelineSd_Format(struct SolidSyslogStructuredData* base, stru
* stateless one is a vtable this application owns. */
static struct SolidSyslogStructuredData s_pipelineSd = {SyslogPipelineSd_Format};

struct SolidSyslogStructuredData* SyslogPipelineSd_Get(void)
struct SolidSyslogStructuredData* SyslogPipelineSd_Init(bool mutualTls)
{
s_transport = mutualTls ? "mtls" : "tls";
return &s_pipelineSd;
}
8 changes: 6 additions & 2 deletions app/syslog/SyslogPipelineSd.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
#ifndef APP_SYSLOG_PIPELINE_SD_H
#define APP_SYSLOG_PIPELINE_SD_H

#include <stdbool.h>

struct SolidSyslogStructuredData;

/** The shared instance, for SolidSyslogConfig.Sd. Stateless, so never NULL. */
struct SolidSyslogStructuredData* SyslogPipelineSd_Get(void);
/** Records what the pipeline was configured with and returns the shared instance,
* for SolidSyslogConfig.Sd. Never NULL. @p mutualTls must reflect the stream
* config, not the intent. */
struct SolidSyslogStructuredData* SyslogPipelineSd_Init(bool mutualTls);

#endif /* APP_SYSLOG_PIPELINE_SD_H */
13 changes: 13 additions & 0 deletions measurements/mtls.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# mtls figures (bytes) — captured by scripts/run.sh (CAPTURE=1).
# The device reads measurements/Baseline.csv as its frozen baseline and reports current-minus-Baseline.
flash_text,363280
flash_data,652
static_bss,148280
heap_used,4440
mbedtls_peak,37244
mbedtls_free,19076
lwip_mem_free,7576
lwip_pbufs_free,13
stack_log,832
stack_service,3852
stack_harness,2848
1 change: 1 addition & 0 deletions measurements/stages.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ origin-ip Origin address the device's own address in the record, which a relay o
tls TLS a collector the device authenticates, and records no longer readable on the wire
hmac HMAC at rest stored records that cannot be edited undetected, not merely checked for corruption
pipeline-sd Private SD-ELEMENT a record that states the protection its own log pipeline was under
mtls Mutual TLS a collector that knows which device sent the record, not just that one did
34 changes: 17 additions & 17 deletions run-report.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# solid-syslog-example — run (pipeline-sd)
# solid-syslog-example — run (mtls)

## Device (self-measured)

Expand All @@ -10,14 +10,14 @@
[device] first record logged: yes
[report] --- SolidSyslog cost above baseline (simulated existing application) ---
[report] key,current,baseline,used_above_baseline
[report] flash_text,363208,349992,13216
[report] flash_data,648,316,332
[report] static_bss,146232,110876,35356
[report] flash_text,363280,349992,13288
[report] flash_data,652,316,336
[report] static_bss,148280,110876,37404
[report] heap_used,4440,4440,0
[report] mbedtls_peak,36096,21332,14764
[report] mbedtls_free,18176,11436,6740
[report] mbedtls_peak,37244,21332,15912
[report] mbedtls_free,19076,11436,7640
[report] lwip_mem_free,7576,7576,0
[report] lwip_pbufs_free,14,14,0
[report] lwip_pbufs_free,13,14,-1
[report] stack_log,832,120,712
[report] stack_service,3852,52,3800
[report] stack_harness,2848,2840,8
Expand All @@ -29,7 +29,7 @@

```text
text data bss dec hex filename
363200 656 146232 510088 7c888 /w/build/baseline-cross/baseline.elf
363272 660 148280 512212 7d0d4 /w/build/baseline-cross/baseline.elf
```

## Listeners (proved before the device ran)
Expand All @@ -47,21 +47,21 @@
## Collector (syslog-ng) received

```text
wire <134>1 2026-07-29T10:57:51.850000Z 10.0.2.15 solid-syslog-example - BOOT [meta sequenceId="1" sysUpTime="385"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"][logPipeline@32473 transport="tls" atRest="hmac-sha256"] device started
parsed PRIORITY=134 TIMESTAMP=2026-07-29T10:57:51+00:00 HOSTNAME=10.0.2.15 APP_NAME=solid-syslog-example PROCID= MSGID=BOOT STRUCTURED_DATA=[meta sequenceId="1" sysUpTime="385"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"][logPipeline@32473 transport="tls" atRest="hmac-sha256"] MSG=device started
wire <134>1 2026-07-29T11:06:52.430000Z 10.0.2.15 solid-syslog-example - BOOT [meta sequenceId="1" sysUpTime="243"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"][logPipeline@32473 transport="mtls" atRest="hmac-sha256"] device started
parsed PRIORITY=134 TIMESTAMP=2026-07-29T11:06:52+00:00 HOSTNAME=10.0.2.15 APP_NAME=solid-syslog-example PROCID= MSGID=BOOT STRUCTURED_DATA=[meta sequenceId="1" sysUpTime="243"][timeQuality tzKnown="1" isSynced="0"][origin software="solid-syslog-example" swVersion="0.1.0" enterpriseId="32473" ip="10.0.2.15"][logPipeline@32473 transport="mtls" atRest="hmac-sha256"] MSG=device started
```

## Self-check (vs measurements/pipeline-sd.csv)
## Self-check (vs measurements/mtls.csv)

```text
OK flash_text: 363208 (expected 363208, Δ0)
OK flash_data: 648 (expected 648, Δ0)
OK static_bss: 146232 (expected 146232, Δ0)
OK flash_text: 363280 (expected 363280, Δ0)
OK flash_data: 652 (expected 652, Δ0)
OK static_bss: 148280 (expected 148280, Δ0)
OK heap_used: 4440 (expected 4440, Δ0)
OK mbedtls_peak: 36096 (expected 36096, Δ0)
OK mbedtls_free: 18176 (expected 18176, Δ0)
OK mbedtls_peak: 37244 (expected 37244, Δ0)
OK mbedtls_free: 19076 (expected 19076, Δ0)
OK lwip_mem_free: 7576 (expected 7576, Δ0)
OK lwip_pbufs_free: 14 (expected 14, Δ0)
OK lwip_pbufs_free: 13 (expected 13, Δ0)
OK stack_log: 832 (expected 832, Δ0)
OK stack_service: 3852 (expected 3852, Δ0)
OK stack_harness: 2848 (expected 2848, Δ0)
Expand Down
Loading