-
-
Notifications
You must be signed in to change notification settings - Fork 9
Description
I stumbled (quite badly!) across this while passing application-specific header parameters. I am trying to pass Python str values, and instead of being encoded as tstr, they come out of as bstr. A look at to_cose_header() explains why, they are being explicitly encoded that way. I want to propose a patch for this, so I started with trying a small repro:
protected = {COSEHeaders.KID: b"01", COSEHeaders.ALG: COSEAlgs.ES256, "content type": "application/cwt"}
ctx = COSE.new(alg_auto_inclusion=True)
encoded4 = ctx.encode_and_sign(b"Hello world!", cose_key, protected=protected)
phdr, _, payload = recipient.decode_with_headers(encoded4, pub_key)
assert payload == b"Hello world!"
assert phdr[COSEHeaders.ALG] == COSEAlgs.ES256
assert phdr["content type"] == "application/cwt"
But that works. How?
This does not work:
# Different order than 781, but surely equivalent?
protected = {"content type": "application/cwt", COSEHeaders.KID: b"01", COSEHeaders.ALG: COSEAlgs.ES256}
with pytest.raises(ValueError) as err:
# Raises ValueError: Unsupported or unknown COSE header parameter: 4.
# Very surprising!
encoded5 = ctx.encode_and_sign(b"Hello world!", cose_key, protected=protected)
phdr, _, payload = recipient.decode_with_headers(encoded5, pub_key)
assert payload == b"Hello world!"
assert phdr[COSEHeaders.ALG] == COSEAlgs.ES256
assert phdr["content type"] == "application/cwt"
It turns out that to_cose_header() does this:
if len(data) == 0 or not isinstance(list(data.keys())[0], str):
If the first key in the keys of the header dict is not a string, the code assumes the dict has already been encoded, and lets it through unmodified. Huh. On the one hand, this is great, now I have a way to get my tstr through. On the other hand... yikes!
Repro available on: https://github.com/achamayou/python-cwt/tree/encoding_repro
pytest -k test_cose_usage_examples_cose_signature
I can think of a few solutions, most of which involve letting the user handle header pre-processing. Another one may be to add a specific type for the built-in header parameters, instead of using string mappings. That way the logic could be: int and str keys are let through unprocessed all the way to cbor2, but only keys of COSEHeaderKey type are mapped to int. Collisions probably throw an exception?
I will think about this over the weekend, but I wanted to write this up while it is fresh. I should also say that the library is lovely, and a pleasure to use so far!