TimothyClaeys / pycose

A Python implementation of the COSE specification (CBOR Object Signing and Encryption) described in RFC 8152.
https://tools.ietf.org/html/rfc8152
Other
39 stars 24 forks source link

Make decoding stricter when called on specific subclass. #102

Closed plietar closed 2 years ago

plietar commented 2 years ago

The vast majority of the time, a given call site will expect a particular message type. Previously, calling decode(data) would behave the same, regardless on which class it was called on, and inferred the message type from the CBOR tag.

This change uses the cls argument to enforce the correct message type. For example, Sign1Message.decode(data) will either return a Sign1Message or raise an exception if the message type is incorrect.

It is still possible to use CoseMessage.decode(data) if the message type is not known ahead of time, and then dynamically inspect the type of the return value.

This also fixes the type annotation of decode, which previously had an unconstrained CM type variable. This led to either errors where type checkers could not infer the return type, or it would allow the caller to annotate the call with any type it wanted.

Before:

# mypy error: Need type annotation for "msg"
msg = CoseMessage.decode(data)

# This type checks, regardless of the contents of data.
# At runtime, msg may have a different type if data contains a different
# message type.
msg: Sign1Message = CoseMessage.decode(data)

After:

# This type checks, and msg has type CoseMessage
msg = CoseMessage.decode(data)

# This type checks, and msg has type Sign1Message
# An exception is raised if data is not a valid Sign1Message
msg = Sign1Message.decode(data)

Note that even when using an explicit message type, this still requires the data to include a CBOR tag. As a next step, we could loosen this requirement, and make the tag optional is the message type is known.

Finally, as a minor change, the type of the key in CoseMessage is switched from the CK type variable to CoseKey. The former had odd semantics, and led to type checker errors:

msg = Sign1Message()
# error: Incompatible types in assignment (expression has type "EC2Key", variable has type "CK")
msg.key = EC2Key.generate_key(crv=P256)
letmaik commented 2 years ago

CI is still failing here.

sonarcloud[bot] commented 2 years ago

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication