Skip to content

Add Wireshark key log support for OPC UA secure channel decryption#1720

Merged
kevinherron merged 8 commits intomainfrom
feature/wireshark-keylog
Mar 28, 2026
Merged

Add Wireshark key log support for OPC UA secure channel decryption#1720
kevinherron merged 8 commits intomainfrom
feature/wireshark-keylog

Conversation

@kevinherron
Copy link
Copy Markdown
Contributor

@kevinherron kevinherron commented Mar 26, 2026

Summary

Add a callback-based key export mechanism that captures the symmetric keys derived during OpenSecureChannel handshakes and writes them in the Wireshark OPC UA key log format for offline traffic decryption.

Closes #1719.

  • Added SecurityKeysListener callback interface, SecurityKeyset immutable value object, and WiresharkKeyLogWriter file-based implementation in stack-core — the three core types that enable key export.
  • Wired the listener through the SDK config builders (OpcUaClientConfig, OpcUaServerConfig) and ApplicationContext bridge interfaces to the two transport-layer key derivation sites.
  • Added configureClient() / configureServer() hooks to ClientExample / ExampleServer so examples can customize both configs without reimplementing the runner.
  • Added KeyLogExample demonstrating end-to-end key logging with an encrypted client/server connection.
  • Feature reference: docs/features/wireshark-key-log.md

Key Changes

  • Core types (stack-core): SecurityKeyset is a Java record with defensive-copy on both construction and accessor return. WiresharkKeyLogWriter synchronizes on the callback and flushes per entry; I/O errors are logged rather than thrown so a write failure doesn't interrupt the Netty event loop.

  • Transport integration: The listener is invoked immediately after setChannelSecurity() in both UascClientMessageHandler.installSecurityToken() and UascServerAsymmetricHandler.openSecureChannel(), guarded by newKeys != null (null when security policy is None). The ApplicationContext interfaces gain a default method returning null for backward compatibility.

  • SDK configuration path: Follows the existing config-builder → ApplicationContext → transport-handler pattern used by getKeyPair(), getCertificateManager(), etc. Config interfaces expose Optional<SecurityKeysListener>; the ApplicationContext overrides bridge via .orElse(null).

  • Example infrastructure: configureClient() / configureServer() on ClientExample and new ExampleServer constructors are general-purpose hooks, not key-log-specific.

Testing

  • SecurityKeysetTest — defensive copy on construction, accessor return cloning, component round-trip.
  • WiresharkKeyLogWriterTest — single entry format validation, append mode (two entries → 12 lines), concurrent writes from 20 threads with interleaving check.
  • Verification: mvn -q clean verify

References

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an opt-in mechanism to export derived OPC UA SecureChannel symmetric keys in Wireshark’s OPC UA key log format, enabling offline decryption of encrypted traffic for debugging and analysis.

Changes:

  • Added SecurityKeysListener, SecurityKeyset, and a file-based WiresharkKeyLogWriter implementation (with unit tests).
  • Wired key export through SDK configs → application contexts → transport handlers (client + server) at key-derivation points.
  • Updated examples infrastructure and added a KeyLogExample demonstrating end-to-end key logging.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerAsymmetricHandler.java Emits derived key material to the configured listener after OpenSecureChannel.
opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/server/ServerApplicationContext.java Adds a default getSecurityKeysListener() bridge point (nullable) for server transport.
opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientMessageHandler.java Emits derived key material to the configured listener after installing the security token.
opc-ua-stack/transport/src/main/java/org/eclipse/milo/opcua/stack/transport/client/ClientApplicationContext.java Adds a default getSecurityKeysListener() bridge point (nullable) for client transport.
opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/channel/SecurityKeysListener.java Defines the callback interface for key export.
opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/channel/SecurityKeyset.java Adds an immutable value object (record) for exported symmetric key material.
opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/channel/WiresharkKeyLogWriter.java Implements a file writer that outputs keysets in Wireshark’s OPC UA key log format.
opc-ua-stack/stack-core/src/test/java/org/eclipse/milo/opcua/stack/core/channel/SecurityKeysetTest.java Tests defensive copying and accessors for SecurityKeyset.
opc-ua-stack/stack-core/src/test/java/org/eclipse/milo/opcua/stack/core/channel/WiresharkKeyLogWriterTest.java Tests output formatting, append behavior, and concurrent write behavior.
opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClientConfigBuilder.java Adds builder support for configuring a SecurityKeysListener.
opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClientConfig.java Exposes the listener on the client config API surface.
opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClient.java Bridges config listener into the transport ClientApplicationContext.
opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServerConfigBuilder.java Adds builder support for configuring a SecurityKeysListener.
opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServerConfig.java Exposes the listener on the server config API surface.
opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServer.java Bridges config listener into the transport ServerApplicationContext.
milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/ClientExample.java Adds configureClient() / configureServer() hooks for examples.
milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/ClientExampleRunner.java Uses endpoint port to bind the embedded server; invokes example config hooks.
milo-examples/server-examples/src/main/java/org/eclipse/milo/examples/server/ExampleServer.java Adds configurable bind port + config customizer hook for embedded server usage.
milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/KeyLogExample.java New example demonstrating client/server key logging and printing log output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

kevinherron and others added 2 commits March 25, 2026 20:30
…/client/OpcUaClientConfig.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…/server/OpcUaServerConfig.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 26, 2026

@kevinherron I've opened a new pull request, #1721, to work on those changes. Once the pull request is ready, I'll request review from you.

@kevinherron kevinherron merged commit 887e91e into main Mar 28, 2026
6 checks passed
@kevinherron kevinherron added this to the 1.1.2 milestone Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add OPC UA key log export for Wireshark traffic decryption

3 participants