python-opcua
python-opcua copied to clipboard
How to authenticate using Certificate and Private Key
Hello!
I want to create a secure connection with UA CPP Server.
Until now, I've got to connect with Basic256Sha256 + Sign&Encrypt Security Settings and Anonymously Authentication Settings. Now, I want to use the same Security Settings, but with Certificate and Private Key as Authentication Settings (instead of Anonymously).
For that, I am using these functions: client.user_certificate = ("/home/ii40asset/klabeak/my_cert.pem") client.user_private_key = ("/home/ii40asset/klabeak/my_private_key.pem")
I have created the certificates with python-opcua/examples/generate_certificate.sh file: openssl req -x509 -newkey rsa:2048 -keyout my_private_key.pem -out my_cert.pem -days 355 -nodes openssl x509 -outform der -in my_cert.pem -out my_cert.der
When I run the client program this error appears to me:

Could someone help me?
Thanks!!
Hello,
I use set_security_string method as you can see in my following example:
client = opcua.Client("opc.tcp://opcuaserver.com:48010", timeout=60)
client.application_uri = "urn:example.org:FreeOpcUa:python-opcua" # Should match in your certificate
client.set_security_string("Basic256Sha256,SignAndEncrypt,/home/ii40asset/klabeak/my_cert.pem,/home/ii40asset/klabeak/my_private_key.pem")
client.connect()
...
Note: to read the application_uri in a certificate use openssl (example with certificate in examples folder) openssl x509 -in examples/certificate-example.der -inform der -text -noout
And check URI value in Subject Alternative Name
X509v3 Subject Alternative Name:
URI:urn:example.org:FreeOpcUa:python-opcua
Hello @moimart1 !
First of all, thank you for your response.
Respect to the problem, I've get to connect with Sign&Encrypt Security Settings and Anonymously Authentication Settings. To Sign&Encrypt, I use the same funcion like you (client.set_security_string). This type of communication will be like this example in UaExpert:
But now, I want to keep the same security settings, and I want to add certificates to authenticate too:
I don't know how can I do this type of authentication (I don't how can I use client.user_certificate, client.user_private_key...)
Thanks!
And this is the code that brings me problems:
After...
client.user_certificate = ("/home/ii40asset/klabeak/Python-opcua_client/python_client.der")
client.user_private_key = ("/home/ii40asset/klabeak/Python-opcua_client/python_client_key.pem")

client.py



uacrypto.py

I'm not an expert in OPC but according to your error, client.user_certificate and client.user_private_key don't except a path but an object
You need to use client.load_client_certificateand client.load_private_key instead
I am experiencing a simliar, but not the same issue. I can connect using an application certificate by invoking set_security. However, using a user certificate via load_private_key and load_client_certificate yields to opcua.ua.uaerrors._auto.BadUserSignatureInvalid. I can use the same user certificate and private key in UA expert to connect to the server, so they are correct and the server is working correctly, too. The failing code is:
from opcua import Client, ua
from traceback import print_exc
uri = 'opc.tcp://opcuademonstrator:4840'
user_name = 'observer'
cert_file = 'user.der'
key_file = 'user.pem'
variable_id = ua.StringNodeId('MotionDeviceSystem.ProcessData.$TIMER')
client = Client(uri)
try:
client.set_user(user_name)
client.load_client_certificate(cert_file)
client.load_private_key(key_file)
client.connect()
variable = client.get_node(variable_id)
print(' ', variable)
# the following line failes with:
#
# opcua.ua.uaerrors._auto.BadUserSignatureInvalid:
# The user token signature is missing or invalid.
print(' ', variable.get_value())
print('TEST CASE PASSED')
except:
print('TEST CASE FAILED')
print_exc()
finally:
client.disconnect()
I am using an OPC UA server, which is built on top of the Unified Automation SDK. What am I missing here?
For information, I was stuck with the same error (BadUserSignatureInvalid) with this code :
client = Client( "opc.tcp://xx.xx.xx.xx:yyyyy/zzzzzz" ) client.application_uri="" client.load_client_certificate("user_cert.der") client.load_private_key("cert_key.pem") client.set_security_string( "Basic256,SignAndEncrypt,app_cert.der,app_cert_key.pem" ) client.connect()
I am not competent in cryptography but it seems to work for me by modifying the signature of the token in sha256.
In opcua/client/client.py def _add_certificate_auth(self, params, certificate, challenge):
Instead of sig = uacrypto.sign_sha(self.user_private_key, challenge)
Set sig = uacrypto.sign_sha256(self.user_private_key, challenge)
what server are you try to connect?
I don't know because I have only the IP.
some servers check the subjectaltname extention of the cert this has to fit to the client application uri and client ip address!
OK. The subjectaltname of the certificate must not be not good but this server does not block when I put an empty uri application client.
I confirm that in my case the client connects correctly when I force the signature in sha256 in the library.
do you use Basic256Sha256 + SignAndEncrypt?
client.set_security_string("Basic256Sha256,SignAndEncrypt,cert.pem,key.pem")
No, just Basic256 + sign/encrypt :
client.set_security_string( "Basic256,SignAndEncrypt,app_cert.der,app_cert_key.pem" )
sig = uacrypto.sign_sha256(self.user_private_key, challenge)
you force him to use a different sha algorithm! maybe you auth cert is not right but this is always hard to guess...
https://reference.opcfoundation.org/v104/Core/docs/Part4/5.6.3/#5.6.3.1 Bad_UserSignatureInvalid | The user token signature is missing or invalid.
Is it an compliant to OPC UA spec 1.04? In simple words is it an older OPCUA Server?
I looked through OPC UA Spec and the activate session and it looks right... there might be something with the cert or the server needs a copy of your cert as trusted
i mean even if your client uses a sha1 hash, the algotithem is part of the hash so he should be able to read it anyways
the thing is usually it should work! but if the server only accept sha256 sounds odd to me to be honest...
def sign_sha1(private_key, data):
return private_key.sign(
data,
padding.PKCS1v15(),
hashes.SHA1()
)
def sign_sha256(private_key, data):
return private_key.sign(
data,
padding.PKCS1v15(),
hashes.SHA256()
)
Thanks for all this information, I'm starting to understand better. In fact, I am using a certificate that I was given and which works under the UAexpert client. It is self signed and has been trusted on the server as a certificate. It's the same one I use for certificate authentication. So I think it was also approved for this endpoint. I have no information about the server except that it may be using software from the softing company.
I'm sorry if I'm not very clear, it's new to me.
Looking at the code of _add_certificate_auth, I have the impression that the signature is automatically declared in sha256 (params.UserTokenSignature.Algorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256") while it is signed in sha1:
def _add_certificate_auth(self, params, certificate, challenge):
params.UserIdentityToken = ua.X509IdentityToken()
params.UserIdentityToken.PolicyId = self.server_policy_id(ua.UserTokenType.Certificate, "certificate_basic256")
params.UserIdentityToken.CertificateData = uacrypto.der_from_x509(certificate)
# specs part 4, 5.6.3.1: the data to sign is created by appending
# the last serverNonce to the serverCertificate
sig = uacrypto.sign_sha1(self.user_private_key, challenge)
params.UserTokenSignature = ua.SignatureData()
params.UserTokenSignature.Algorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
params.UserTokenSignature.Signature = sig
After testing, it works leaving sign_sha1 but using rsa-sha1 definition:
params.UserTokenSignature.Algorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
to recap you use the client cert from ua expert? can you open it with a editor and post content here?
Sorry for the delay, here the certificate ( I removed the non useful data) cert.txt
I think I have the same type of problem as #811 Thank you
Hello i have an Issue with creting a secure connection between a Kepserver and a Python script as a Client. I created the private Key as well as the certificate in openssl with the command :
openssl req -x509 -newkey rsa:2048 -keyout my_private_key.pem -out my_cert.pem -days 355 -nodes -addext "subjectAltName = URI:urn:example.org:FreeOpcUa:python-opcua"
openssl x509 -outform der -in my_cert.pem -out my_cert.der
My Test script looks like:
client =Client(OPC_URL)
client.set_security_string("Basic256Sha256,SignAndEncrypt,e86c852b0bd1f2faecf98c947709607714f42ede.der,key.pem")
client.connect()
This doesnt really work out and iam getting the Message:
'No matching endpoints: 3, http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256'
The certificate that im using is in the script is made from the Kepserver and the PrivKey is made by my self with openssl. Whats am i missing here?
'No matching endpoints: 3, http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256' ... Whats am i missing here?
The code line that logs this is in client.py:
@staticmethod
def find_endpoint(endpoints, security_mode, policy_uri):
"""
Find endpoint with required security mode and policy URI
"""
for ep in endpoints:
if (ep.EndpointUrl.startswith(ua.OPC_TCP_SCHEME) and
ep.SecurityMode == security_mode and
ep.SecurityPolicyUri == policy_uri):
return ep
raise ua.UaError("No matching endpoints: {0}, {1}".format(security_mode, policy_uri))
policy_uri is correctly set to "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256". security_mode 3 corresponds to SignAndEncrypt, and ua.OPC_TCP_SCHEME is the string "opc.tcp".
Try to have the list of endpoints printed from client code, e.g. by manually splitting the connect sequence in the same way as the Client class would do. From the docs published over at KepWare, the endpoint that your security string describes should be the only one the server should emit. Can you somehow check in whatever server settings that it does? Can you ping?
Does your OPC_URL point to the right host and port? Does it start with opc.tcp? Is that port accessible from your client host?
What I don't understand, however, is your setup regarding the certificates. I hope you did create the certificate you send using the key you pack with it (or signed the DER file with the same key you encoded to key.pem). Otherwise the server shouldn't accept the two, but that ought to get you into different trouble than what you describe.
Are you sure the relative path that the security string evaluates to really is the location of the two files? To make double sure, giving an absolute path (e.g. using os.path.abspath()) might reduce trouble.
Hi, maybe some solution. I'm trying to create a server and connect to a client, but I can't do it even with UA Expert. I am generating the certificates with Openssl, I am uploading the cert.der and the key.pem to the server and client but both in the UA Expert and in the py Client and I cannot connect. Thank you very much for taking the time to reply to this message.
Attached generated project files. https://gist.github.com/admolina19/9cab8bc7bf0d09d70ca769828d571796
Error Server: Exception raised while parsing message from client, closing Traceback (most recent call last): File "C:\Users\PC\AppData\Local\Programs\Python\Python310\lib\site-packages\opcua\server\binary_server_asyncio.py", line 75, in _process_data ret = self.processor.process(hdr, buf) File "C:\Users\PC\AppData\Local\Programs\Python\Python310\lib\site-packages\opcua\server\uaprocessor.py", line 86, in process msg = self._connection.receive_from_header_and_body(header, body) File "C:\Users\PC\AppData\Local\Programs\Python\Python310\lib\site-packages\opcua\common\connection.py", line 306, in receive_from_header_and_body self.select_policy(security_header.SecurityPolicyURI, security_header.SenderCertificate) File "C:\Users\PC\AppData\Local\Programs\Python\Python310\lib\site-packages\opcua\common\connection.py", line 215, in select_policy self.security_policy = policy.create(peer_certificate) File "C:\Users\PC\AppData\Local\Programs\Python\Python310\lib\site-packages\opcua\ua\uaprotocol_hand.py", line 265, in create return self.cls(peer_certificate, self.certificate, self.private_key, self.mode) File "C:\Users\PC\AppData\Local\Programs\Python\Python310\lib\site-packages\opcua\crypto\security_policies.py", line 570, in init self.asymmetric_cryptography.Verifier = VerifierSha256(server_cert) File "C:\Users\PC\AppData\Local\Programs\Python\Python310\lib\site-packages\opcua\crypto\security_policies.py", line 338, in init self.key_size = self.server_cert.public_key().key_size // 8 AttributeError: 'bytearray' object has no attribute 'public_key'