FreeOpcUa / opcua-asyncio

OPC UA library for python >= 3.7
GNU Lesser General Public License v3.0
1.07k stars 351 forks source link

Error parsing server certificate in Siemens (Sinumerik 840D) miniweb OPC UA Server. Version 4.7 SW #1525

Open ShevKG opened 8 months ago

ShevKG commented 8 months ago

Hello. I am unable to connect to Siemens OPC UA server for Sinumerik 840D based device. Currently i am using a SinuTrain emulator for a lathe. I'm able to connect and read node values via CNCnetPDM.OpcUA.Client.exe image

My code

import asyncio
from asyncua import Client

async def main():
    url = "opc.tcp://127.0.0.1:4840"
    client = Client(url)

    client.set_user("OpcUaClient")
    client.set_password("OpcUaClient")

    await client.set_security_string("Basic128Rsa15,SignAndEncrypt,certificate.pem, key.pem")
    await client.connect()

    print(f"Connected to: {url}")

    servicelevel_node = client.get_node("ns=0;i=2267")

    servicelevel_node_value = servicelevel_node.get_value()
    print(servicelevel_node_value)

    client.disconnect()

asyncio.run(main())

Error

Using a code written above returns asn1 error ValueError: error parsing asn1 value: ParseError { kind: EncodedDefault, location: ["Certificate::tbs_cert", "TbsCertificate::raw_extensions", 0, "Extension::critical"] }

I have sucessfuly created certificate.pem, certificate.der and private_key.pem files via OpenSSL. But it seems that the main error is related to the server certificate from Siemens OPC UA Server.

Here's the simplified call stack:

  client.connect() 
   -> self.activate_session(username=self._username, password=self._password, certificate=self.user_certificate)
   -> pubkey = uacrypto.x509_from_der(self.security_policy.server_certificate).public_key()
   -> return x509.load_der_x509_certificate(data, default_backend())
   -> return rust_x509.load_der_x509_certificate(data)

Version

python==3.11.0 asyncua==1.0.5

schroeder- commented 8 months ago

Please post the total stacktrace your simplified call stack is no help here.

ShevKG commented 8 months ago

Sure! Sorry that i didn't do that in the first place. Here's the full stacktrace:

 File "C:\opc_ua_monitoring_client\1.py", line 22, in <module>
    asyncio.run(main())
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 650, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "C:\opc_ua_monitoring_client\1.py", line 10, in main
    await client.set_security_string("Basic128Rsa15,SignAndEncrypt,certificate.der, key.pem")
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python311\Lib\site-packages\asyncua\client\client.py", line 181, in set_security_string
    return await self.set_security(policy_class, parts[2], parts[3], client_key_password, parts[4] if len(parts) >= 5 else None, mode)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python311\Lib\site-packages\asyncua\client\client.py", line 217, in set_security
    server_certificate = uacrypto.x509_from_der(endpoint.ServerCertificate)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python311\Lib\site-packages\asyncua\crypto\uacrypto.py", line 62, in x509_from_der
    return x509.load_der_x509_certificate(data, default_backend())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Администратор\AppData\Local\Programs\Python\Python311\Lib\site-packages\cryptography\x509\base.py", line 594, in load_der_x509_certificate
    return rust_x509.load_der_x509_certificate(data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: error parsing asn1 value: ParseError { kind: EncodedDefault, location: ["Certificate::tbs_cert", "TbsCertificate::raw_extensions", 0, "Extension::critical"] }
PS C:\opc_ua_monitoring_client> 

And also a certificate file as buffer:

b'0\x82\x03f0\x82\x02\xcf\xa0\x03\x02\x01\x02\x02\x04n@\x00\x000\r\x06\t\x86H\x86\xf7\r\x01\x01\x05\x05\x000\x81\x941\x0b0\t\x06\x03U\x04\x06\x13\x02DE1\x100\x0e\x06\x03U\x04\x08\x16\x07Bavaria1\x110\x0f\x06\x03U\x04\x07\x16\x08Erlangen1\x130\x11\x06\x03U\x04\n\x16\nSiemens AG1\x110\x0f\x06\x03U\x04\x0b\x16\x08Industry1 0\x1e\x06\t\x86H\x86\xf7\r\x01\t\x01\x16\x11opcua@siemens.com1\x160\x14\x06\x03U\x04\x03\x16\rNIOPO-COMP-020\x1e\x17\r231212113809Z\x17\r491213113809Z0\x81\x941\x0b0\t\x06\x03U\x04\x06\x13\x02DE1\x100\x0e\x06\x03U\x04\x08\x16\x07Bavaria1\x110\x0f\x06\x03U\x04\x07\x16\x08Erlangen1\x130\x11\x06\x03U\x04\n\x16\nSiemens AG1\x110\x0f\x06\x03U\x04\x0b\x16\x08Industry1 0\x1e\x06\t\x86H\x86\xf7\r\x01\t\x01\x16\x11opcua@siemens.com1\x160\x14\x06\x03U\x04\x03\x16\rNIOPO-COMP-020\x81\x9f0\r\x06\t\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x81\x8d\x000\x81\x89\x02\x81\x81\x00\xd2I\x1a\x13\x0e\x89\xbd\x1d\x89\xd5\x05%\xef\x88\xebj\xc7\xfb\xfdV\x10\xf5\x89j\x8b\xc7SO\xcbG\xf3R\xf7\xad!\xda:U;\xb8\xe7)\xd6dCx?\xd2k1\x9c\xb2)\xd5nlk\x92\xf7\xcf\xe7\xbcH\xfb\xdf\xe4O\x7f\x05 \x88\x9e\xed}\x92\x18\x1a{S>\xd2\xc2\x8b\xb4\x99\xc5\xb2\xe9\xf7\x1a\xf1a\x00&\x87+\xad\xe7\xe6\xa4\xe4K~\x1d\xa2\x00\xfa6\x17\xa0\xcc\x9fI@[\t\xd1\x87\x8e\x85Q\xbb\xc3\xfe\xbc&\x97\xc5\x02\x03\x01\x00\x01\xa3\x81\xc20\x81\xbf0(\x06\x03U\x1d#\x01\x01\x00\x04\x1e0\x1c\x80\x14\n\rF\xe5\x9a\xef3d\xc6\xeaX\xec\xe9D\xee\xc2\xa29\x1b\xfb\x82\x04n@\x00\x000 \x06\x03U\x1d\x0e\x01\x01\x00\x04\x16\x04\x14\n\rF\xe5\x9a\xef3d\xc6\xeaX\xec\xe9D\xee\xc2\xa29\x1b\xfb0\x0f\x06\x03U\x1d\x13\x01\x01\x00\x04\x050\x03\x01\x01\xff0\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\xf60 \x06\x03U\x1d%\x01\x01\xff\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x02\x06\x08+\x06\x01\x05\x05\x07\x03\x010.\x06\x03U\x1d\x11\x01\x01\x00\x04$0"\x82\tlocalhost\x86\x15urn:localhost:miniweb0\r\x06\t\x86H\x86\xf7\r\x01\x01\x05\x05\x00\x03\x81\x81\x00O\x80\xeb\x80(\x1e\xa2\xc6\xda\x9e\xf8I\x9e\xedl\x80z\x16\xba,@\xb8\x9e\xec\xa6\x16z\x8af2\xde\xa9\xcf\x00WE\x8e\x12\xc7/f\x12\x0f\x18\x16\xaa\x17\xfe\xfc<\xc7"\xeb\'R\xe1\x7fQ-\xa8r\xe8\x17\xcd\xb9g\xd0.\xca\xec\xef%\xbbq\x96\xfa\x11Y3\x10\xa1\xa2\xd7}xT\xb1\xb4\xdf\xbf\x89m\xab\x1a\x9cj-S\x04\xaf\xfb\xea\xef"I\x05\xb3cKR\xd3\xd3\x88\xca\x15\x92\x8e\x17`\x1dK\x11(\x1e\xbc\x12p'

schroeder- commented 8 months ago

Maybe it is a easy fix try change that code (remove space):

"Basic128Rsa15,SignAndEncrypt,certificate.pem, key.pem" -> "Basic128Rsa15,SignAndEncrypt,certificate.pem,key.pem"

ShevKG commented 8 months ago

This didn't help. In my code it didn't even get to certificate.pem and key.pem

Script crashes in this section of client.py:

            if server_certificate is None: # <- It tries to pull the server certificate from the server endpoint
            # Force unencrypted/unsigned SecureChannel to list the endpoints
            new_policy = ua.SecurityPolicy()
            self.security_policy = new_policy
            self.uaclient.security_policy = new_policy
            # load certificate from server's list of endpoints
            endpoints = await self.connect_and_get_server_endpoints()
            endpoint = Client.find_endpoint(endpoints, mode, policy.URI)
            print('out endpoint: %s' % endpoint)
            # If a server has certificate chain, the certificates are chained
            # this generates a error in our crypto part, so we strip everything after
            # the server cert. To do this we read byte 2:4 and get the length - 4
            cert_len_idx = 2
            len_bytestr = endpoint.ServerCertificate[cert_len_idx:cert_len_idx + 2]
            cert_len = int.from_bytes(len_bytestr, byteorder="big", signed=False) + 4

            with open("C:\opc_ua_monitoring_client\server_cert.der", 'wb') as f:
                f.write(endpoint.ServerCertificate)
            server_certificate = uacrypto.x509_from_der(endpoint.ServerCertificate[:cert_len])

Now I'm thinking that the error is more related to the cryptography module itself, neither than to asyncua library

johannesWen commented 2 months ago

@ShevKG

Hi, i have got the same problem. Do you have already an idea how to fix this?