Skip to content

Hardened: present a client certificate for mutual TLS - #24

Merged
DavidCozens merged 1 commit into
mainfrom
hardened-mtls
Jul 28, 2026
Merged

Hardened: present a client certificate for mutual TLS#24
DavidCozens merged 1 commit into
mainfrom
hardened-mtls

Conversation

@DavidCozens

@DavidCozens DavidCozens commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What this tag adds

Mutual TLS: ClientCertChain and ClientKey join the stream config, and the collector
moves to 6515. The device now authenticates itself to the collector as well as
verifying it.

  wire ... [logPipeline@32473 transport="mtls" atRest="hmac-sha256"] device started

  Flash        14,452 B      (+72)
  Static RAM    5,048 B         (0)
  Heap         17,776 B   (+1,256)
  Log stack       712 B         (0)
  Service stack 3,800 B         (0)

72 bytes of flash, and neither stack moves — client authentication is another leg of
a handshake the service task already had the depth for. The heap is what the handshake
holds to prove the device's identity.

Both handles come from the cert store, which has parsed them since boot. A device that
already speaks mTLS elsewhere was carrying them before SolidSyslog arrived, so what is
charged here is presenting them, not holding them.

Delivery is the proof

6515 is configured peer-verify(required-trusted), and scripts/smoke-oracle.sh proves
it refusing a client that presents no certificate — every run, before the device starts.
So a record arriving on 6515 is a record whose sender authenticated. That pairing matters:
the certless-rejection check alone would pass if there were no listener at all.

One trap worth knowing

ClientCertChain and ClientKey must both be set. Either one NULL disables mTLS and
the connection silently falls back to server authentication only — it still succeeds
against a permissive listener, which is exactly how this regression would go unnoticed.
Using a required-trusted port is what turns that silence into a failure.

Checklist

  • Application-only — app/syslog/Syslog.c and the pipeline element's transport
    value, which this step makes true.
  • measurements/<State>.csv committed, and a row added to measurements/tags.tsv.
    Tag boundaries deferred to the release pass.
  • README cost table regenerated — nothing to regenerate until a state's CSV is frozen.
  • ./run.sh green; record delivered on 6515 and confirmed in the collector's parsed
    output.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Secure syslog transport now supports mutual TLS, including correct structured-data labeling as mtls when enabled.
    • Syslog collector communication uses the updated collector port.
  • Bug Fixes

    • Mutual TLS is now handled safely when required client certificate material isn’t available, ensuring transport metadata stays consistent.
    • Updated secure run report values and timestamps, including the collector transport field changing from tls to mtls.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0ab191cf-f7e0-4351-8b10-7f4fa095601e

📥 Commits

Reviewing files that changed from the base of the PR and between 36bfd1c and e8f8d0b.

📒 Files selected for processing (4)
  • app/syslog/Syslog.c
  • app/syslog/SyslogPipelineSd.c
  • app/syslog/SyslogPipelineSd.h
  • run-report.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • run-report.txt

📝 Walkthrough

Walkthrough

The syslog collector port changes to 6515, TLS setup adds optional client certificate and key material from DeviceCertStore, and structured-data transport labeling now reflects TLS versus mTLS configuration. Run-report resource figures and mTLS output are updated.

Changes

Syslog mTLS transport

Layer / File(s) Summary
Configure the mTLS collector connection
app/syslog/Syslog.c
The collector endpoint moves to port 6515, DeviceCertStore credentials are wired into TLS, and pipeline initialization detects whether both credentials are present.
Update transport metadata and validation output
app/syslog/SyslogPipelineSd.*, run-report.txt
The structured-data API selects tls or mtls from the configured stream, while run-report transport output and resource figures are updated.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Syslog_Start
  participant DeviceCertStore
  participant TlsStream
  participant SyslogPipelineSd
  participant SyslogCollector
  Syslog_Start->>DeviceCertStore: Read client certificate and key
  Syslog_Start->>TlsStream: Configure port 6515 and optional credentials
  Syslog_Start->>SyslogPipelineSd: Initialize transport metadata
  TlsStream->>SyslogCollector: Establish TLS or mTLS connection
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding client certificate presentation for mutual TLS.
Description check ✅ Passed The description follows the template and covers the feature plus checklist items, with only deferred non-critical entries.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hardened-mtls

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/syslog/SyslogPipelineSd.c`:
- Line 20: Update the transport assignment in SyslogPipelineSd.c to reflect the
active authentication mode: emit "mtls" only when client certificate
authentication is actually enabled, and otherwise derive the appropriate
non-mTLS value or omit the transport element. Reuse the same configuration or
mode determination used by Syslog.c so missing client certificate or key cannot
produce transport="mtls".

In `@run-report.txt`:
- Line 21: Update the size cross-check row in run-report.txt to match the
reported flash_text/flash_data metrics for the same baseline. If the row
represents a different artifact, explicitly label it with that binary instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4b1557f8-5b60-45f2-88f1-f7ef4f139f7c

📥 Commits

Reviewing files that changed from the base of the PR and between 9311bd5 and 36bfd1c.

📒 Files selected for processing (3)
  • app/syslog/Syslog.c
  • app/syslog/SyslogPipelineSd.c
  • run-report.txt

Comment thread app/syslog/SyslogPipelineSd.c Outdated
Comment thread run-report.txt Outdated
ClientCertChain and ClientKey join the stream config, and the collector moves to
6515. The device now authenticates itself to the collector as well as verifying it.

  Flash        14,504 B     (+124)
  Static RAM    5,052 B       (+4)
  Heap         17,776 B   (+1,256)
  Log stack       712 B         (0)
  Service stack 3,800 B         (0)

Neither stack moves: client authentication is another leg of a handshake the
service task already had the depth for. The heap is what the handshake holds to
prove the device's identity.

Both handles come from the cert store, which has parsed them since boot. This
figure is therefore the cost of *using* credentials the device already holds — a
device doing server-authenticated TLS only would also have to provision, store and
parse a client certificate and key to reach the same place.

Both must be set: either one NULL disables mTLS and the connection falls back to
server authentication only, without failing. That is why the pipeline element
reports what was configured rather than what was intended — an element claiming
protection the device does not have would be worse than not reporting it, since it
is exactly the weakening a collector is watching for.

Delivery is the proof. 6515 requires a client certificate, and scripts/smoke-oracle.sh
shows it refusing a client that presents none, so a record arriving there is a
record whose sender authenticated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@DavidCozens
DavidCozens merged commit bcf4e19 into main Jul 28, 2026
2 checks passed
@DavidCozens
DavidCozens deleted the hardened-mtls branch July 28, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant