Closed panzi closed 3 years ago
Thank you! Are you sure this is the right one, though? Because I'm getting this:
>>> import requests
>>> from cryptography.hazmat.primitives.asymmetric.ec import ECDSA
>>> from cryptography.hazmat.primitives.serialization import load_pem_public_key
>>> from cryptography.hazmat.primitives import hashes
>>> from base64 import b64decode
>>> certs_signed_json = requests.get('https://de.dscg.ubirch.com/trustList/DSC/').content
>>> pubkey_pem = requests.get('https://github.com/Digitaler-Impfnachweis/covpass-ios/raw/main/Certificates/DEMO/CA/pubkey.pem').content
>>> pubkey = load_pem_public_key(pubkey_pem)
>>> sign_b64, body_json = certs_signed_json.split(b'\n', 1)
>>> sign = b64decode(sign_b64)
>>> pubkey.verify(sign, body_json, ECDSA(hashes.SHA256()))
Traceback (most recent call last):
File "<pyshell#167>", line 1, in <module>
pubkey.verify(sign, body_json, ECDSA(hashes.SHA256()))
File "/home/panzi/.local/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ec.py", line 378, in verify
_ecdsa_sig_verify(self._backend, self, signature, data)
File "/home/panzi/.local/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ec.py", line 106, in _ecdsa_sig_verify
raise InvalidSignature
cryptography.exceptions.InvalidSignature
(Using PROD
or PROD_RKI
instead of the DEMO
in the URL doesn't change anything.)
Keep in mind that the verify
method of hazmat.primitives.asymmetric.ec
takes signatures in the DER encoded DSS format only. To achieve this format, add to the code:
from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature
r = int.from_bytes(sign[:len(sign)//2], byteorder="big", signed=False)
s = int.from_bytes(sign[len(sign)//2:], byteorder="big", signed=False)
sign = encode_dss_signature(r, s)
Thank you! 😄
@panzi maybe you are also interested in my Python port of the relevant kotlin code in the SDK to be able to verify and dump contents of CovPass QR-Codes. After all it is just a quick'n'dirty script which while writing helped me to understand the architecture of the system better. Another good read might be https://harrisonsand.com/posts/covid-certificates/
@e7p Thank you but I already did that part myself, see: https://github.com/panzi/verify-ehc Note that I've also seen RSA keys being used, not just EC. My script handles that. What my script currently doesn't do is validating the signature of the trust list itself, but I know how to do that now (for Germany).
I stumbled across this. Here's my solution, with some help from python-ecdsa:
import hashlib
from ecdsa import VerifyingKey
import requests
with open('pubkey.pem') as f:
vk = VerifyingKey.from_pem(f.read())
result = requests.get(...)
signature, message = result.content.split(b'\n')
vk.verify(base64.b64decode(signature), message, hashfunc=hashlib.sha256)
Looks like a good solution. I thought I should eventually share the python snippet which is basically just the kotlin code ported to python: https://gist.github.com/e7p/66dde9002fcc0cb197f3bcab7c3ce975
As this is somehow just quick'n'dirty, it doesn't parse the signature so good as @loelkes solution though. It simply splits the signature in half to get the two parameters r
and s
.
The first line of the Trust List is a signature, but in order to verify that I'd need the public key (to the private key with which the signature was created). Where can I find that?