The OPC UA Secure Conversation (UASC) mechanism described 6.7 is designed for use with asymmetric cryptography algorithms, such as RSA, that allow Public Keys to be used for encryption and for digital signatures. ECC is an asymmetric cryptography algorithm that only supports digital signatures. To accommodate algorithms like ECC, the UASC handshake changes to allow negotiation of inputs used for key derivation in 6.7.6 without making the keys available to eavesdroppers. This negotiation uses a Diffie-Hellman algorithm defined in IETF RFC 8422 and is shown in Figure 15.

image018.png

Figure 15 – ECC Key Negotiation

Certificates for ECC have a public-private key pair that are used to create and verify a digital signature. To negotiate the keys used for the SecureChannel the Client generates a new key pair (JC, KC) and passes the Public Key (JC) in the request. After verifying the signature on the request, the Server generates a new key pair (JS, KS) and returns the Public Key (JS) in the response. The new key pairs are used each time a SecureChannel is negotiated and they are called EphemeralKeys.

ECC public-private key pairs are always based on a specific elliptic curve function which is used for the ECC calculations. Many curves exist, however, ECC cryptography libraries support a finite set of "named curves" to allow for better interoperability. Each OPC UA SecurityPolicy defined in OPC 10000-7 specifies exactly one named curve which is used for the EphemeralKeys.

Each ECC Certificate is also based on a named curve. Each SecurityPolicy specifies a list of named curves which are permitted for use in the Certificate. This list always includes the named curve used for the EphemeralKey, however, it may allow other named curves. OPC UA applications that support ECC SecurityPolicies shall support multiple Certificates.

ECC Public Keys and digital signatures are the output of an ECC operation. The encoding of these outputs depends on the ECC curve and are described by the SecurityPolicy in OPC 10000-7.

Clause 6.7.4 specifies the contents of the OpenSecureChannel request and response messages. When using an ECC SecurityPolicy the ClientNonce is the Public Key for the Client’s EphemeralKey encoded using the Public Key encoding for the curve. Similarly, the ServerNonce is the Public Key for the Server’s EphemeralKey.

The encoding of the EphemeralKeys depends on the ECC curve used. For NIST and Brainpool curves the EphemeralKey is the x and y coordinate encoded as zero padded big-endian OctetString. For Edwards curves the EphemeralKey format is defined byIETF RFC 7748.

The EphemeralKeys are used to calculate a shared secret by using the Private Key of an EphemeralKey and the Public Key of the peer’s EphemeralKey. The exact algorithm to calculate the shared secret depends on the ECC curve and is defined by the SecurityPolicy. This shared secret is then used to derive key data using the following algorithm from IETF RFC 5869. Note that the algorithm is repeated here for clarity, however, the RFC is the normative source.

Step 1: Calculate Salts

ServerSalt = L | UTF8(opcua-server) | ServerNonce | ClientNonce

ClientSalt = L | UTF8(opcua-client) | ClientNonce | ServerNonce

Where

Step 2: Extract

PRK = HMAC-Hash(Salt, IKM)

Where

  • HMAC uses a Hash function specified by the KeyDerivationAlgorithm;
  • IKM is the shared secret calculated from the EphemeralKeys;
  • Salt is calculated in Step 1;
  • PRK is a pseudorandom output with length equal to the Hash size.

The encoding of the x-coordinate in IKM depends on the ECC curve used. For NIST and Brainpool curves the x-coordinate is encoded as a zero padded big-endian OctetString. For Edwards curves the coordinate format is defined by RFC 7748.

If SecureChannelEnhancements = TRUE and a SecureChannel is renewed (see 6.7.4), the IKM used to derive the current set of keys is XORed with the new IKM negotiated during renewal to create a value that is used to derive the new keys.

Step 3: Expand

N = ceil(L/HashLen)

T = T(1) | T(2) | T(3) | ... | T(N)

OKM = first L octets of T

where:

T(0) = empty string (zero length)

T(1) = HMAC-Hash(PRK, T(0) | Info | 0x01)

T(2) = HMAC-Hash(PRK, T(1) | Info | 0x02)

T(3) = HMAC-Hash(PRK, T(2) | Info | 0x03)

...

-

Where

  • HMAC uses a Hash function specified by the KeyDerivationAlgorithm;
  • PRK is the output from Step 1;
  • Info is the Salt used in Step 1;
  • L is the length of keying material;
  • 0x01 is the number 1 encoded as a byte.
  • OKM is the output with length equal to L bytes.

The client keys are extracted from the keying material created with IKM=shared secret, Salt=ClientSalt and Info=ClientSalt as shown in Table 67.

The SymmetricEncryptionAlgorithm for the SecurityPolicy sets the DerivedSignatureKeyLength, the EncryptionKeyLength and InitializationVectorLength. All constants referenced in the table are converted to bytes for the calculation of offsets and lengths.

Table 67 – Deriving Client Keys from Keying Material

Name

Offset

Length

ClientSigningKey

0

DerivedSignatureKeyLength

ClientEncryptingKey

DerivedSignatureKeyLength

EncryptionKeyLength

ClientInitializationVector

DerivedSignatureKeyLength + EncryptionKeyLength

InitializationVectorLength

The server keys are extracted from the keying material created with IKM=shared secret, Salt= ServerSalt and Info=ServerSalt as shown in Table 68.

Table 68 – Deriving Server Keys from Keying Material

Name

Offset

Length

ServerSigningKey

0

DerivedSignatureKeyLength

ServerEncryptingKey

DerivedSignatureKeyLength

EncryptionKeyLength

ServerInitializationVector

DerivedSignatureKeyLength + EncryptionKeyLength

InitializationVectorLength

The SymmetricEncryptionAlgorithm for the SecurityPolicy sets the DerivedSignatureKeyLength, the EncryptionKeyLength and InitializationVectorLength..

When using AuthenticatedEncryption, the DerivedSignatureKeyLength is set to zero in the calculation of L in Step 1. The process of signing and encrypting data with AuthenticatedEncryption is discussed in 6.7.1.

When not using AuthenticatedEncryption with Sign only, the EncryptionKeyLength and InitializationVectorLength are set to 0 in the calculation of L in Step 1. The SymmetricEncryptionAlgorithm is not used and the padding has length zero. The process of signing and encrypting data when not using AuthenticatedEncryption is discussed in 6.7.1.

When using AuthenticatedEncryption, a unique InitializationVector is required for each MessageChunk. This value is constructed from the ClientInitializationVector or ServerInitializationVector where the first 8 bytes are XORed with the values in Table 69 encoded as described in 5.2.2.2.

When not using AuthenticatedEncryption, the data changes for each Message so the InitializationVector can be calculated once with the keys and reused until the keys are changed.

Table 69 – Creating a Mask for the Initialization Vector

Name

Bytes

Length

TokenId

4

The TokenId specified in the SecurityHeader of MessageChunk being processed.

It is encoded as a UInt32 as described in 5.2.2.2.

LastSequenceNumber

4

The SequenceNumber specified in the SequenceHeader of last MessageChunk sent in the same direction on the SecureChannel.

The value is 0 to indicate there is no LastSequenceNumber for the first MessageChunk which is always the OpenSecureChannel Message.

It is encoded as a UInt32 as described in 5.2.2.2.

The ClientInitializationVector is used when the Client encrypts the MessageChunk and the ServerInitializationVector is used when the Server encrypts the MessageChunk.

The LastSequenceNumber is the SequenceNumber from the previously sent Message which normally requires the previous Message to be decrypted. If the receiver processes incoming Messages in parallel it can calculate the expected SequenceNumber based on the order in which the encrypted Messages are received.

Once the keys are derived ECC SecureChannels behave the same as RSA SecureChannels.

ActivateSession allows a Client to provide an encrypted UserIdentityToken using a SecurityPolicy specified by a UserTokenPolicy supported by the current Endpoint. With ECC, encryption requires that the Client and Server exchange EphemeralKeys and there is no mechanism in the current CreateSession/ActivateSession handshake to do this. For that reason, EphemeralKeys are returned in the AdditionalHeader field of the ResponseHeader of the CreateSession and ActivateSession responses. An overview of the handshake is shown in Figure 16.

image019.png

Figure 16 – ECC CreateSession/ActivateSession Handshake

The UserTokenPolicies are returned in the GetEndpoints response. A UserTokenPolicy may specify a SecurityPolicyUri that is different than the SecureChannel (see OPC 10000-4). For example, an EndpointDescription providing an ECC SecurityPolicyUri does not specify RSA SecurityPolicyUris in the UserTokenPolicies.

When a Client calls CreateSession via a SecureChannel based on an ECC or RSA_DH SecurityPolicy the Client specifies the ECDHPolicyUri it plans to use for the UserIdentityToken in the RequestHeader. The Server returns an EphemeralKey in the ResponseHeader that can be used for the ECDHPolicyUri specified by the Client. If the ECDHPolicyUri is not valid the Server returns Bad_SecurityPolicyRejected in the ResponseHeader instead of an EphemeralKey.

When the Client calls ActivateSession it creates an EccEncryptedSecret (see OPC 10000-4) using the most recent EphemeralKey provided in CreateSession or ActivateSession response.

The Server returns a new EphemeralKey in the response based on the following rules:

If ActivateSession is successful the Server shall not accept the same EphemeralKey again.

OPC 10000-4 defines AdditionalParametersType which is a list of name-value pairs. An instance of this type is passed in the AdditionalHeader field. Instances of the EphemeralKeyType defined in OPC 10000-4 are passed as values in the name-value pair list in the response messages. The names used for the parameters defined for the CreateSession/ActivateSession exchange are defined in Table 70.

Table 70 – Additional Header Key Names

Name

DataType

Description

ECDHPolicyUri

String

Specifies the SecurityPolicyUri used for the EphemeralKeys.

ECDHKey

EphemeralKeyType

Specifies an EphemeralKey.

If the EphemeralKey could not be created a StatusCode indicating the reason for the error is used instead of an instance of EphemeralKeyType.

OPC 10000-4 defines the layout of EccEncryptedSecret structure which is used to protect secrets with ECC and RSA-DH SecurityPolicies. Applying security with ECC or RSA-DH requires two EphemeralKeys generated by the sender and the receiver which are used to create the symmetric keys for encryption.

Clause 6.8.1 defines a mechanism that allows the sender to acquire the receiver EphemeralKey when using a Session. Using the EccEncryptedSecret in other contexts requires a different mechanism.

Once the sender has the receiver EphemeralKey, it creates its own EphemeralKey. For ECC algorithms, The ECC curve and key length for the EphemeralKeys are specified by the SecurityPolicy. For RSA-DH, the key length and finite field group are specified by the SecurityPolicy.

The encryption uses the symmetric encryption algorithm specified by the SecurityPolicyUri. The encrypting key and initialization vector are generated by using the EphemeralKeys to create the shared secret and then derive keys using the algorithm defined in 6.8.1. Step 1 is slightly different and defined as follows:

Step 1: Calculate Salt

SecretSalt = L | UTF8(opcua-secret) | SenderPublicKey | ReceiverPublicKey

Where:

  • L is the length of derived key material needed encoded as a 16-bit little endian integer;
  • UTF8(opcua-secret) is the UTF8 encoding of the string literal ‘opcua-secret’;
  • SenderPublicKey and ReceiverPublicKey are from EccEncryptedSecret;
  • | concatenates sequences of bytes;

Salt is a sequence of bytes.

The encryption keys are extracted from the keying material created with IKM=shared secret, Salt=SecretSalt and Info=SecretSalt as shown in Table 71.

Table 71 – Deriving Keys from Keying Material

Name

Offset

Length

EncryptingKey

0

EncryptionKeyLength

InitializationVector

EncryptionKeyLength

InitializationVectorLength

The EncryptionKeyLength and EncryptionBlockSize are specified by the Symmetric Encryption Algorithm for the SecurityPolicy. The Signature is created with the SigningCertificate and is calculated after encryption. Receivers shall validate the SigningCertificate and signature before decrypting the Secret.

The PayloadPadding calculated to ensure the encrypted data is a multiple of InitializationVectorLength when using block based symmetric encryption algorithms such as AES-CBC.

When using AuthenticatedEncryption, the PayloadPadding calculated to ensure the encrypted data is a multiple of 16 bytes and the additional data part shall include all headers in the EncryptedSecret. The AuthenticatedEncryption tag is appended after the PayloadPaddingSize and is verified when the Payload is decrypted.

The PayloadPaddingSize calculated with the following formula:

BlockSize = (AuthenticatedEncryption) ? 16 : InitializationVector.Length

Data.Length = 4 + Nonce.Length + 4 + Secret.Length + 2

PayloadPaddingSize = Data.Length % BlockSize == 0

? 0 : BlockSize - Data.Length % BlockSize;

if (PayloadPaddingSize + Secret.Length < BlockSize)

PayloadPaddingSize += BlockSize;

Where Data.Length includes two 4-byte values for the length of ByteString values and two bytes to store the PayloadPaddingSize. The value of all Padding bytes is the least significant byte of the PayloadPaddingSize. The calculation ensures the padding can never be zero.