OpenLEADR / openleadr-python

Python library for OpenADR
https://openleadr.org/docs
Apache License 2.0
131 stars 50 forks source link

Unable to use EC keys/certificates for signing XML messages #65

Open michal-kowalczyk opened 3 years ago

michal-kowalczyk commented 3 years ago

When passing an EC key and cert to OpenADRServer, it crashes after receiving the first message from the VEN:

Registration id generated: ba81402c-9a7a-4407-930c-b2b60d109693
Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/aiohttp/web_protocol.py", line 422, in _handle_request
    resp = await self._request_handler(request)
  File "/usr/local/lib/python3.8/dist-packages/aiohttp/web_app.py", line 499, in _handle
    resp = await handler(request)
  File "/openadr-ven-client/openleadr/openleadr/service/vtn_service.py", line 153, in handler
    msg = self._create_message(response_type, **response_payload)
  File "/openadr-ven-client/openleadr/openleadr/messaging.py", line 93, in create_message
    signature_tree = SIGNER.sign(tree,
  File "/openadr-ven-client/signxml/signxml/__init__.py", line 406, in sign
    signature = key.sign(signed_info_c14n, padding=PKCS1v15(), algorithm=hash_alg)
TypeError: sign() got an unexpected keyword argument 'padding'

The reason for that is the fact that they set default value for signature_algorithm to rsa-sha256 in the method __init__ of XMLSigner .

A simple workaround is applying the following diff:

diff --git a/openleadr/messaging.py b/openleadr/messaging.py
index 8ab7f0d..0e1312c 100644
--- a/openleadr/messaging.py
+++ b/openleadr/messaging.py
@@ -31,7 +31,8 @@ import logging
 logger = logging.getLogger('openleadr')

 SIGNER = XMLSigner(method=methods.detached,
-                   c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
+                   c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
+                   signature_algorithm="ecdsa-sha256")
 SIGNER.namespaces['oadr'] = "http://openadr.org/oadr-2.0b/2012/07"
 VERIFIER = XMLVerifier()

Here's is the key that I use:

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIF2/Odv+n2FfLFzhPsrsh2YjqJOKIsA2xPqDMpRRjNo/oAoGCCqGSM49
AwEHoUQDQgAExZQiFmzgfVK43skJMr/kv3t0HyftVIY1D/W+8K9QAdoDIOSZhO1e
VjCsk46I82oHT9zTromtIits/O8HgXAALw==
-----END EC PRIVATE KEY-----

and the certificate:

-----BEGIN CERTIFICATE-----
MIICZjCCAU4CFGI/TA0hQqPcgLBn8T9tSauyEsnnMA0GCSqGSIb3DQEBCwUAMEYx
CzAJBgNVBAYTAlBMMRAwDgYDVQQIDAdsb2R6a2llMQ0wCwYDVQQHDARMb2R6MRYw
FAYDVQQKDA1BbmFseXRpY3NGaXJlMCAXDTIxMDQyMTEzMDEyNloYDzIxMjEwMzI4
MTMwMTI2WjBiMQswCQYDVQQGEwJQTDEQMA4GA1UECAwHbG9kemtpZTENMAsGA1UE
BwwETG9kejEWMBQGA1UECgwNQW5hbHl0aWNzRmlyZTEMMAoGA1UECwwDVlROMQww
CgYDVQQDDAN2dG4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATFlCIWbOB9Urje
yQkyv+S/e3QfJ+1UhjUP9b7wr1AB2gMg5JmE7V5WMKyTjojzagdP3NOuia0iK2z8
7weBcAAvMA0GCSqGSIb3DQEBCwUAA4IBAQByAdXMdjt+F8Iowsxo/vGFOJ8WFBkQ
eyRhWQZ0ZAziQ+1k9XzIuH0q+z7pPYzxjkea0HfHjvNVkIvOtT7+S7+tXrDauZiN
qWVBWZ5GbVsaJrUkuT/3E4LxTrSaARUJQLfc7ihkgXVBqvbaPVKg1AHzVTKPIsE9
A0d0N50TGTjKF1gsW5HGBPmPccoyzbg7U3HPJVy+iWuBZGK+ffyTG7s31+h1u7Wq
ic0B129dwtaG293ETubvCBPV3ZRtg5QCavj8/c4w6uY0fbFogDzw+oc2wDfJbIim
pXU+ptYKRZy/HcCwVLG2F/36OFKLWRtC6ijV9PeVtwI7bFYo1dxy77NK
-----END CERTIFICATE-----
stan-janssen commented 3 years ago

Doesn't setting signature_algorithm to the ecdsa one make the rsa keys not work? We should probably first know what kind of certificate we're dealing with before setting it. Any ideas?

michal-kowalczyk commented 3 years ago

Correct, you can only have either ec or rsa, you cannot have both. A quick fix might be adding a new parameter to the server: key_type - 'ec'/'rsa'. If we don't like extending the interface, we could reinitialize XMLSigner with 'ecdsa-sha256' if that throws. The best would be a proper fix with checking if the key is RSA or EC although I haven't found anything suitable for python.