Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing ClientNonce in OpenSecureChannel message #393

Open
markusgraube opened this issue Jan 17, 2017 · 11 comments
Open

Missing ClientNonce in OpenSecureChannel message #393

markusgraube opened this issue Jan 17, 2017 · 11 comments
Labels

Comments

@markusgraube
Copy link
Contributor

I am trying to connect to a OPC UA server on a Wago PLC. I am using freeopcua-0.90.1 under Python 3.5.2+. Other clients can connect well to the server.

However, using freeopcua leads to following error:

In [1]: from opcua import Client

In [2]: c = Client("opc.tcp://10.0.51.9:4840")

In [3]: c.connect()                           
Received an error: MessageAbort(error:StatusCode(BadOutOfMemory), reason:None)
Received an error: MessageAbort(error:StatusCode(BadOutOfMemory), reason:None)
---------------------------------------------------------------------------
TimeoutError                              Traceback (most recent call last)
<ipython-input-3-fe870a4d911f> in <module>()
----> 1 c.connect()

/home/mgraube/.local/lib/python3.5/site-packages/opcua/client/client.py in connect(self)
    225         self.connect_socket()
    226         self.send_hello()
--> 227         self.open_secure_channel()
    228         self.create_session()
    229         self.activate_session(username=self.server_url.username, password=self.server_url.password, certificate=self.user_certificate)

/home/mgraube/.local/lib/python3.5/site-packages/opcua/client/client.py in open_secure_channel(self, renew)
    267         nonce = utils.create_nonce(self.security_policy.symmetric_key_size)   # length should be equal to the length of key of symmetric encryption
    268         params.ClientNonce = nonce      # this nonce is used to create a symmetric key
--> 269         result = self.uaclient.open_secure_channel(params)
    270         self.security_policy.make_symmetric_key(nonce, result.ServerNonce)
    271         self.secure_channel_timeout = result.SecurityToken.RevisedLifetime

/home/mgraube/.local/lib/python3.5/site-packages/opcua/client/ua_client.py in open_secure_channel(self, params)
    222 
    223     def open_secure_channel(self, params):
--> 224         return self._uasocket.open_secure_channel(params)
    225 
    226     def close_secure_channel(self):

/home/mgraube/.local/lib/python3.5/site-packages/opcua/client/ua_client.py in open_secure_channel(self, params)
    163         # FIXME: we have a race condition here
    164         # we can get a packet with the new token id before we reach to store it..
--> 165         response = ua.OpenSecureChannelResponse.from_binary(future.result(self.timeout))
    166         response.ResponseHeader.ServiceResult.check()
    167         self._connection.set_channel(response.Parameters)

/usr/lib/python3.5/concurrent/futures/_base.py in result(self, timeout)
    405                 return self.__get_result()
    406             else:
--> 407                 raise TimeoutError()
    408 
    409     def exception(self, timeout=None):

TimeoutError: 

The difference in the wireshark dumps is that the OpenSecureChannel message of freeopcua has a missing ClientNonce

42	11.821363912	10.0.53.67	10.0.51.9	OpcUa	198	OpenSecureChannel message: OpenSecureChannelRequest
Frame 42: 198 bytes on wire (1584 bits), 198 bytes captured (1584 bits) on interface 0
Ethernet II, Src: LcfcHefe_47:21:a1 (50:7b:9d:47:21:a1), Dst: WagoKont_41:2c:82 (00:30:de:41:2c:82)
Internet Protocol Version 4, Src: 10.0.53.67, Dst: 10.0.51.9
Transmission Control Protocol, Src Port: 43314, Dst Port: 4840, Seq: 57, Ack: 29, Len: 132
OpcUa Binary Protocol
    Message Type: OPN
    Chunk Type: F
    Message Size: 132
    SecureChannelId: 0
    SecurityPolicyUri: http://opcfoundation.org/UA/SecurityPolicy#None
    SenderCertificate: <MISSING>[OpcUa Null ByteString]
    ReceiverCertificateThumbprint: <MISSING>[OpcUa Null ByteString]
    SequenceNumber: 1
    RequestId: 1
    Message : Encodeable Object
        TypeId : ExpandedNodeId
            NodeId EncodingMask: Four byte encoded Numeric (0x01)
            NodeId Namespace Index: 0
            NodeId Identifier Numeric: OpenSecureChannelRequest (446)
        OpenSecureChannelRequest
            RequestHeader: RequestHeader
            ClientProtocolVersion: 0
            SecurityTokenRequestType: Issue (0x00000000)
            MessageSecurityMode: None (0x00000001)
            ClientNonce: <MISSING>[OpcUa Empty ByteString]
            RequestedLifetime: 3600000

So, I think that clientNonce should not be empty to be conform to the standard.

@oroulet
Copy link
Member

oroulet commented Jan 17, 2017

What is in ClientNonde when using uaexpert (or another client that works)?
What happens if you modify the open_secure_channel and put an empty string instead of None in ClientNonce?

@paltmann-tud
Copy link

This is what it looks like in UaExpert:

Frame 939: 187 bytes on wire (1496 bits), 187 bytes captured (1496 bits) on interface 0
Ethernet II, Src: LcfcHefe_6b:48:cb (50:7b:9d:6b:48:cb), Dst: WagoKont_41:2c:82 (00:30:de:41:2c:82)
Internet Protocol Version 4, Src: 10.0.53.136, Dst: 10.0.51.9
Transmission Control Protocol, Src Port: 52108, Dst Port: 4840, Seq: 57, Ack: 29, Len: 133
OpcUa Binary Protocol
    Message Type: OPN
    Chunk Type: F
    Message Size: 133
    SecureChannelId: 0
    SecurityPolicyUri: http://opcfoundation.org/UA/SecurityPolicy#None
    SenderCertificate: <MISSING>[OpcUa Null ByteString]
    ReceiverCertificateThumbprint: <MISSING>[OpcUa Null ByteString]
    SequenceNumber: 51
    RequestId: 1
    Message : Encodeable Object
        TypeId : ExpandedNodeId
            NodeId EncodingMask: Four byte encoded Numeric (0x01)
            NodeId Namespace Index: 0
            NodeId Identifier Numeric: OpenSecureChannelRequest (446)
        OpenSecureChannelRequest
            RequestHeader: RequestHeader
            ClientProtocolVersion: 0
            SecurityTokenRequestType: Issue (0x00000000)
            MessageSecurityMode: None (0x00000001)
            ClientNonce: 00
            RequestedLifetime: 300000

and as Hex Dump

0000   00 30 de 41 2c 82 50 7b 9d 6b 48 cb 08 00 45 00
0010   00 ad 17 29 40 00 80 06 00 00 0a 00 35 88 0a 00
0020   33 09 cb 8c 12 e8 f6 93 c5 fa c6 ce f8 9a 50 18
0030   40 22 7d 30 00 00 4f 50 4e 46 85 00 00 00 00 00
0040   00 00 2f 00 00 00 68 74 74 70 3a 2f 2f 6f 70 63
0050   66 6f 75 6e 64 61 74 69 6f 6e 2e 6f 72 67 2f 55
0060   41 2f 53 65 63 75 72 69 74 79 50 6f 6c 69 63 79
0070   23 4e 6f 6e 65 ff ff ff ff ff ff ff ff 33 00 00
0080   00 01 00 00 00 01 00 be 01 00 00 bb c4 d9 ca ad
0090   70 d2 01 00 00 00 00 00 00 00 00 ff ff ff ff 00
00a0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00
00b0   00 00 01 00 00 00 00 e0 93 04 00

and for direct comparison, the freeopcua version again

Frame 1068: 186 bytes on wire (1488 bits), 186 bytes captured (1488 bits) on interface 0
Ethernet II, Src: LcfcHefe_6b:48:cb (50:7b:9d:6b:48:cb), Dst: WagoKont_41:2c:82 (00:30:de:41:2c:82)
Internet Protocol Version 4, Src: 10.0.53.136, Dst: 10.0.51.9
Transmission Control Protocol, Src Port: 52246, Dst Port: 4840, Seq: 57, Ack: 29, Len: 132
OpcUa Binary Protocol
    Message Type: OPN
    Chunk Type: F
    Message Size: 132
    SecureChannelId: 0
    SecurityPolicyUri: http://opcfoundation.org/UA/SecurityPolicy#None
    SenderCertificate: <MISSING>[OpcUa Null ByteString]
    ReceiverCertificateThumbprint: <MISSING>[OpcUa Null ByteString]
    SequenceNumber: 1
    RequestId: 1
    Message : Encodeable Object
        TypeId : ExpandedNodeId
            NodeId EncodingMask: Four byte encoded Numeric (0x01)
            NodeId Namespace Index: 0
            NodeId Identifier Numeric: OpenSecureChannelRequest (446)
        OpenSecureChannelRequest
            RequestHeader: RequestHeader
            ClientProtocolVersion: 0
            SecurityTokenRequestType: Issue (0x00000000)
            MessageSecurityMode: None (0x00000001)
            ClientNonce: <MISSING>[OpcUa Empty ByteString]
            RequestedLifetime: 3600000
0000   00 30 de 41 2c 82 50 7b 9d 6b 48 cb 08 00 45 00
0010   00 ac 1e 67 40 00 80 06 00 00 0a 00 35 88 0a 00
0020   33 09 cc 16 12 e8 8e af 27 b6 02 92 90 04 50 18
0030   40 22 7d 2f 00 00 4f 50 4e 46 84 00 00 00 00 00
0040   00 00 2f 00 00 00 68 74 74 70 3a 2f 2f 6f 70 63
0050   66 6f 75 6e 64 61 74 69 6f 6e 2e 6f 72 67 2f 55
0060   41 2f 53 65 63 75 72 69 74 79 50 6f 6c 69 63 79
0070   23 4e 6f 6e 65 ff ff ff ff ff ff ff ff 01 00 00
0080   00 01 00 00 00 01 00 be 01 00 00 b4 db 6b 6a af
0090   70 d2 01 01 00 00 00 00 00 00 00 ff ff ff ff e8
00a0   03 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00
00b0   00 00 00 00 00 00 80 ee 36 00

@oroulet
Copy link
Member

oroulet commented Jan 17, 2017

so uaexpert sends an empty bytestring and not None. Then try to change code and let us know

@markusgraube
Copy link
Contributor Author

If clientNonce is modfied to some bytetring, the channel can be opened.

The problem seems to be that freeopcua tries to generate a nonce with 0 bytes length (which is None) when no symmetric key is given

However, we fail now at ActivateSessionRequest:

Frame 23992: 208 bytes on wire (1664 bits), 208 bytes captured (1664 bits) on interface 0
Ethernet II, Src: LcfcHefe_47:21:a1 (50:7b:9d:47:21:a1), Dst: WagoKont_41:2c:82 (00:30:de:41:2c:82)
Internet Protocol Version 4, Src: 10.0.53.67, Dst: 10.0.51.9
Transmission Control Protocol, Src Port: 53698, Dst Port: 4840, Seq: 459, Ack: 565, Len: 142
OpcUa Binary Protocol
    Message Type: MSG
    Chunk Type: F
    Message Size: 142
    SecureChannelId: 34179
    Security Token Id: 1
    Security Sequence Number: 3
    Security RequestId: 3
    OpcUa Service : Encodeable Object
        TypeId : ExpandedNodeId
        ActivateSessionRequest
            RequestHeader: RequestHeader
                AuthenticationToken: NodeId
                    .... 0000 = EncodingMask: Two byte encoded Numeric (0x0)
                    Identifier Numeric: 31
                Timestamp: Jan 17, 2017 14:36:11.650367000 CET
                RequestHandle: 3
                Return Diagnostics: 0x00000000
                AuditEntryId: [OpcUa Null String]
                TimeoutHint: 1000
                AdditionalHeader: ExtensionObject
                    TypeId: ExpandedNodeId
                        EncodingMask: 0x00, EncodingMask: Two byte encoded Numeric
                            .... 0000 = EncodingMask: Two byte encoded Numeric (0x0)
                            .0.. .... = has server index: False
                            0... .... = has namespace uri: False
                        Identifier Numeric: 0
                    EncodingMask: 0x00
                        .... ...0 = has binary body: False
                        .... ..0. = has xml body: False
            ClientSignature: SignatureData
                Algorithm: http://www.w3.org/2000/09/xmldsig#rsa-sha1
                Signature: <MISSING>[OpcUa Empty ByteString]
            ClientSoftwareCertificates: Array of SignedSoftwareCertificate
                ArraySize: 0
            LocaleIds: Array of String
                ArraySize: 1
                [0]: LocaleIds: en
            UserIdentityToken: ExtensionObject
                TypeId: ExpandedNodeId
                    EncodingMask: 0x01, EncodingMask: Four byte encoded Numeric
                        .... 0001 = EncodingMask: Four byte encoded Numeric (0x1)
                        .0.. .... = has server index: False
                        0... .... = has namespace uri: False
                    Namespace Index: 0
                    Identifier Numeric: 321
                EncodingMask: 0x01, has binary body
                    .... ...1 = has binary body: True
                    .... ..0. = has xml body: False
                AnonymousIdentityToken: AnonymousIdentityToken
                    PolicyId: [OpcUa Null String]
            UserTokenSignature: SignatureData
                Algorithm: [OpcUa Null String]
                Signature: <MISSING>[OpcUa Null ByteString]



OpcUa Binary Protocol
    Message Type: ERR
    Chunk Type: F
    Message Size: 16
    Error: 0x80030000 [BadOutOfMemory]
    Reason: [OpcUa Null String]

Here, I have no idea why it is failing.

@oroulet
Copy link
Member

oroulet commented Jan 17, 2017

You have no other choice than comparing data to one that succeed with another client. Not accepting a null bytestring is clearly a bug in your server, but we could change default..

@destogl
Copy link
Member

destogl commented Jan 18, 2017

But this should be somehow parametrized, for the servers that accept Null bytestring and for that which not. Otherwise we possibly drift from the standard...

@markusgraube
Copy link
Contributor Author

markusgraube commented Jan 20, 2017

If I set ClientSignature.Signature to None, also the second problem is solved for this server.

Can I achieve this also by correctly using client.set_security(...)? So, which parameters do I have to use to set freeopcua to use no security?

@oroulet
Copy link
Member

oroulet commented Jan 20, 2017

so what does work at the end? ClientNonde must be of length 0 and not None and Signature must be None? Isn't None the default?

@markusgraube
Copy link
Contributor Author

markusgraube commented Jan 20, 2017

This server works when ClientNonce is not of length 0 and when Signature is None. However, I have no idea how to integrate this in a wise way into the freeopcua code?

@markusgraube
Copy link
Contributor Author

The default for signature is b''

Nevertheless, now I have a userspace work around that allows me to communicate with this server with an unmodified freeopcua

from opcua import Client
from opcua.crypto import security_policies
from opcua.ua.uaprotocol_hand import CryptographyNone
import types

client = Client("opc.tcp://10.0.51.9:4840")
        
# Fix ClientNonce isssue (let symmetric_key_size of securityPolicy let be something else than 0)
sec_policy = security_policies.SecurityPolicy()
sec_policy.symmetric_key_size = 8
self.client.security_policy = sec_policy
        
# Fix signature method of CryptographyNone
def signature(self, data):
    return None
fixed_signature = types.MethodType(signature, CryptographyNone)
self.client.security_policy.asymmetric_cryptography.signature = fixed_signature

client.connect()

so, this issue is fixed for me now.
However, maybe you could think about modifying the default behaviour of the client.

@oroulet oroulet added the bug label Jan 24, 2017
@oroulet
Copy link
Member

oroulet commented Jan 24, 2017

OK thanks. leave the bug open

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants