Add Wireshark key log support for OPC UA secure channel decryption#1720
Merged
kevinherron merged 8 commits intomainfrom Mar 28, 2026
Merged
Add Wireshark key log support for OPC UA secure channel decryption#1720kevinherron merged 8 commits intomainfrom
kevinherron merged 8 commits intomainfrom
Conversation
Contributor
There was a problem hiding this comment.
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-basedWiresharkKeyLogWriterimplementation (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
KeyLogExampledemonstrating 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.
milo-examples/client-examples/src/main/java/org/eclipse/milo/examples/client/KeyLogExample.java
Show resolved
Hide resolved
...ain/java/org/eclipse/milo/opcua/stack/transport/server/uasc/UascServerAsymmetricHandler.java
Show resolved
Hide resolved
...c/main/java/org/eclipse/milo/opcua/stack/transport/client/uasc/UascClientMessageHandler.java
Show resolved
Hide resolved
...tack-core/src/main/java/org/eclipse/milo/opcua/stack/core/channel/WiresharkKeyLogWriter.java
Show resolved
Hide resolved
opc-ua-sdk/sdk-client/src/main/java/org/eclipse/milo/opcua/sdk/client/OpcUaClientConfig.java
Outdated
Show resolved
Hide resolved
opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/OpcUaServerConfig.java
Outdated
Show resolved
Hide resolved
…/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>
Contributor
|
@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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
SecurityKeysListenercallback interface,SecurityKeysetimmutable value object, andWiresharkKeyLogWriterfile-based implementation instack-core— the three core types that enable key export.OpcUaClientConfig,OpcUaServerConfig) andApplicationContextbridge interfaces to the two transport-layer key derivation sites.configureClient()/configureServer()hooks toClientExample/ExampleServerso examples can customize both configs without reimplementing the runner.KeyLogExampledemonstrating end-to-end key logging with an encrypted client/server connection.docs/features/wireshark-key-log.mdKey Changes
Core types (
stack-core):SecurityKeysetis a Java record with defensive-copy on both construction and accessor return.WiresharkKeyLogWritersynchronizes 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 bothUascClientMessageHandler.installSecurityToken()andUascServerAsymmetricHandler.openSecureChannel(), guarded bynewKeys != null(null when security policy isNone). TheApplicationContextinterfaces gain adefaultmethod returningnullfor backward compatibility.SDK configuration path: Follows the existing config-builder →
ApplicationContext→ transport-handler pattern used bygetKeyPair(),getCertificateManager(), etc. Config interfaces exposeOptional<SecurityKeysListener>; theApplicationContextoverrides bridge via.orElse(null).Example infrastructure:
configureClient()/configureServer()onClientExampleand newExampleServerconstructors 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.mvn -q clean verifyReferences