The reason why it fails is that you use the wrong key type for the given key.
For the key provided as a JWK ("kty": "EC"
) you need to use EC2, but in your code, you're trying to map it to OKP parameters.
Therefore you first need to change two lines in the import section of your code:
#from cose.keys.keyparam import KpKty, OKPKpCurve, OKPKpD, OKPKpX
from cose.keys.keyparam import KpKty, EC2KpCurve, EC2KpX, EC2KpY
#from cose.keys.okp import OKPKey
from cose.keys.ec2 import EC2Key
Then extract the key parameters x and y from the JWK. The parameters are stored in Base64Url encoding and need to be decoded. The Python Base64 decoder insists on padding, even though Base64Url should not need it. Hence the cryptic looking code to add padding "=" on the Base64Url encoded string before decoding:
x = jwk_key['x']
if len(x) % 4:
x = x + "=" * (4 - len(x)%4)
ec_x = base64.urlsafe_b64decode(x)
y = jwk_key['y']
if len(y) % 4:
y = y + "=" * (4 - len(y)%4)
ec_y = base64.urlsafe_b64decode(y)
And finally, change the mapping code as follows:
key_as_dict = {
KpKty: cose.keys.keytype.KtyEC2,
EC2KpCurve: P256,
EC2Key: kid,
KpKeyOps: [VerifyOp],
EC2KpX: ec_x,
EC2KpY: ec_y,
}
As you can see, I changed the parameters from OKP...
to the EC2...
counterparts
The output of the program (I skipped Part 1..5 as you already know the result) is:
*** Part 6: Verifying certificate
key ready
header True
Below is a minimal runnable example, that just shows the key mapping based on a hardcoded JWK key in the code:
import base64
import cose
from cose.keys.curves import P256, CoseCurve
from cose.keys.keyparam import KpKty, EC2KpCurve, EC2KpX, EC2KpY
from cose.keys.keyparam import KpKeyOps
from cose.keys.keyops import SignOp, VerifyOp
from cose.keys import CoseKey
from cose.keys.ec2 import EC2Key
import json
# this is in reality loaded from the web
jwk_string = '''{"kty": "EC", "crv": "P-256",
"x": "zRR-XGsCp12Vvbgui4DD6O6cqmhfPuXMhi1OxPl8760",
"y": "Iv5SU6FuW-TRYh5_GOrJlcV_gpF_GpFQhCOD8LSk3T0"}'''
jwk_key = json.loads(jwk_string)
kid = "123" # just an example
# mapping the incoming JWK to a COSE key
x = jwk_key['x']
if len(x) % 4:
x = x + "=" * (4 - len(x)%4)
ec_x = base64.urlsafe_b64decode(x)
y = jwk_key['y']
if len(y) % 4:
y = y + "=" * (4 - len(y)%4)
ec_y = base64.urlsafe_b64decode(y)
key_as_dict = {
KpKty: cose.keys.keytype.KtyEC2,
EC2KpCurve: P256,
EC2Key: kid,
KpKeyOps: [VerifyOp],
EC2KpX: ec_x,
EC2KpY: ec_y,
}
govt_key = CoseKey.from_dict(key_as_dict)
print("key ready")
As a side note: make sure the ECDSA package is up to date. I had an older version already on my PC and got a strange Error during verification:
TypeError: from_public_point() got an unexpected keyword argument 'validate_point'
which disappeared after upgrading:
pip install ecdsa --upgrade