Group-key security
PubSub secures messages with pre-shared group keys, not per-session handshakes. Choose a mode, supply the keys statically or from a Security Key Service.
PubSub has no session handshake — publishers and subscribers in a security group share keys out of band. The subscriber verifies (and decrypts) each NetworkMessage with the current group key.
Modes
PubSubSecurityMode (int-backed enum):
| Mode | Value | What happens |
|---|---|---|
None |
1 |
No signature, no encryption |
Sign |
2 |
HMAC-SHA256 signature over the message; verified on receipt |
SignAndEncrypt |
3 |
HMAC-SHA256 signature and AES-CTR payload encryption |
Signing uses HMAC-SHA256; encryption uses AES-CTR (128- or 256-bit,
selected by the encrypting-key length) with a counter block derived from the
key nonce. A datagram that fails verification or decryption is dropped and a
SecurityValidationFailed event fires.
Wiring it up
Pass a PubSubSecurityOptions to listenUdp() / listenOn():
mode
The security mode above.
keyProvider
Source of the group keys. Required for Sign / SignAndEncrypt; null for
None.
use PhpOpcua\Client\ExtTransportPubSub\Security\PubSubSecurityMode;
use PhpOpcua\Client\ExtTransportPubSub\Security\PubSubSecurityOptions;
$security = new PubSubSecurityOptions(
mode: PubSubSecurityMode::SignAndEncrypt,
keyProvider: $keyProvider,
);
SubscriberBuilder::create()
->onDataSetMessage($callback)
->listenUdp(endpoint: 'opc.udp://239.0.0.1:4840', readers: [$reader], security: $security);
Key providers
A GroupKeyProviderInterface supplies the four pieces the codec needs:
signingKey(), encryptingKey(), keyNonce(), tokenId(), plus refresh()
to rotate them.
StaticGroupKeyProvider — pre-shared keys
For fixed keys you distribute yourself.
signingKey
Raw HMAC-SHA256 signing key.
encryptingKey
Raw AES key (16 bytes for AES-128, 32 for AES-256).
keyNonce
Nonce used to build the AES-CTR counter block.
tokenId
Security token id. Default 1.
refresh() is a no-op — static keys never change.
Key hygiene
Keys are raw secret bytes. Load them from a secret store or environment, never
from source control, and match the encrypting-key length to your group's
policy (Aes128 vs Aes256).
SksGroupKeyProvider — live rotation from a Security Key Service
Pulls the current keys from an OPC UA Security Key Service by calling
GetSecurityKeys through the classic opcua-client. refresh() re-fetches,
so keys rotate without a restart.
client
A connected core client used to call the SKS.
securityGroupId
The security group to fetch keys for.
objectNodeId
SKS object node. Default i=14443 (the standard PublishSubscribe object).
methodNodeId
GetSecurityKeys method node. Default i=15215.
securityPolicyUri
Default SksGroupKeyProvider::POLICY_AES256_CTR
(…/SecurityPolicy#PubSub-Aes256-CTR); POLICY_AES128_CTR is also provided.
requestedKeyCount
How many future keys to request. Default 1.
use PhpOpcua\Client\ClientBuilder;
use PhpOpcua\Client\ExtTransportPubSub\Security\SksGroupKeyProvider;
$sksClient = ClientBuilder::create()->connect('opc.tcp://sks.plant.local:4840');
$keyProvider = new SksGroupKeyProvider(
client: $sksClient,
securityGroupId: 'group-1',
securityPolicyUri: SksGroupKeyProvider::POLICY_AES256_CTR,
);
See Rotating keys with an SKS for the refresh loop.