opcua-asyncio
opcua-asyncio copied to clipboard
Can not connect to kepserver using client_set_security_string
kepserver opcua config:
python code:
error message:
C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\Scripts\python.exe C:/Users/yanzh/Desktop/codes/connect_to_opcua_security/main.py Exception raised while parsing message from server Traceback (most recent call last): File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\asyncua\client\ua_client.py", line 78, in _process_received_data msg = self._connection.receive_from_header_and_body(header, buf) File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\asyncua\common\connection.py", line 349, in receive_from_header_and_body chunk = MessageChunk.from_header_and_body(self.security_policy, header, body, use_prev_key=False) File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\asyncua\common\connection.py", line 60, in from_header_and_body decrypted = crypto.decrypt(data.read(len(data))) File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\asyncua\crypto\security_policies.py", line 198, in decrypt return self.Decryptor.decrypt(data) File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\asyncua\crypto\security_policies.py", line 309, in decrypt decrypted += self.decryptor(self.client_pk, File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\asyncua\crypto\uacrypto.py", line 123, in decrypt_rsa_oaep text = private_key.decrypt( File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\cryptography\hazmat\backends\openssl\rsa.py", line 433, in decrypt return _enc_dec_rsa(self._backend, self, ciphertext, padding) File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\cryptography\hazmat\backends\openssl\rsa.py", line 87, in _enc_dec_rsa return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding) File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\venv\lib\site-packages\cryptography\hazmat\backends\openssl\rsa.py", line 147, in _enc_dec_rsa_pkey_ctx res = crypt(pkey_ctx, buf, outlen, data, len(data)) TypeError: initializer for ctype 'unsigned char *' must be a cdata pointer, not bytearray disconnect_socket was called but connection is closed Traceback (most recent call last): File "C:\Program Files\Python310\lib\asyncio\tasks.py", line 456, in wait_for return fut.result() asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\yanzh\Desktop\codes\connect_to_opcua_security\main.py", line 20, in
Process finished with exit code 1
Something with your certificates triggers an error.
I am also not sure if a public certicate in pem format is supported.
Convert the certifcate.pem to a der file via openssl.
openssl x509 -outform der -in certificate.pem -out certificate.der
But the private key needs to stay in pem!
@schroeder- ".pem" should works as well!
@NieYanzhai did you add the client cert to the trusted list?
@NieYanzhai did you add the client cert to the trusted list?
Yes, client cert added to the trust list.
And, I connected to the kepserver using opcua, but can't connect using ayncua.
@schroeder- ".pem" should works as well!
pem works.
I'm facing the same issue with the exception that gets raised in the log of https://github.com/FreeOpcUa/opcua-asyncio/issues/827#issue-1157287320:
TypeError: initializer for ctype 'unsigned char *' must be a cdata pointer, not bytearray
On my side, I was able to work around this by going back to Python version 3.7.9. With version 3.10.1, I'm seeing theTypeError
exception.
This looks like a breaking change from: https://github.com/python/cpython/commit/568fb0ff4aa641329261cdde20795b0aa9278175
A brute force patch (not sure if that's the right place to fix it) would be to enforce that _data
is bytes
and not bytearray
in asyncua\common\utils.py
:
class Buffer:
"""
Alternative to io.BytesIO making debug easier
and added a few convenience methods.
"""
def __init__(self, data, start_pos=0, size=-1):
if isinstance(data, bytearray):
# we need bytes, not bytearray
self._data = bytes(data)
else:
self._data = data
After reviewing the code again, I assume that the better place to fix that is in asyncua.client.ua_client.UASocketProtocol.data_received
. This is where the data provided from asyncio
has changed from bytes
to bytearray
. In fact, the type hint on this function is not correct any more, either:
def data_received(self, data: bytes):
if self.receive_buffer:
data = self.receive_buffer + data
self.receive_buffer = None
self._process_received_data(data)
In this function, if data
is a bytearray
and not bytes
, we probably need to convert it from bytearray
to bytes
. This would make sure that we re-establish the legacy behavior where data
was delivered as bytes
. Something along the lines of:
def data_received(self, data: bytes or bytearray):
# `data`` might be a `bytearray` in more recent Python versions
# (see https://github.com/python/cpython/commit/568fb0ff4aa641329261cdde20795b0aa9278175)
# However, the downstream code still expects to see `bytes`:
if isinstance(data, bytearray):
data = bytes(data)
if self.receive_buffer:
data = self.receive_buffer + data
self.receive_buffer = None
self._process_received_data(data)
If you need a quick patch before this issue gets resolved in an official release, the following snippet works for me:
# Patch the `data_received` handler to work around the issue
# https://github.com/python/cpython/commit/568fb0ff4aa641329261cdde20795b0aa9278175
orig_data_rcvd = asyncua.client.ua_client.UASocketProtocol.data_received
def data_received_patch(self, data: bytes or bytearray):
# `data`` might be a `bytearray` in more recent Python versions
# However, the downstream code still expects to see `bytes`:
if isinstance(data, bytearray):
data = bytes(data)
orig_data_rcvd(self, data)
asyncua.client.ua_client.UASocketProtocol.data_received = data_received_patch
# create the OPC-UA client
client = asyncua.Client(url=server, timeout=timeout)