You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a meta-issue/design issue for tracking a declarative ASN.1 API for Cryptography!
The goal: an importable Python API that users of Cryptography can define ASN.1 structures with, which can then be ser/de'd to and from DER (and only DER).
A rough sketch, demonstrating the basic idioms of the API:
fromcryptography.hazmatimportasn1# Corresponding to:## Signature ::= Sequence {# r INTEGER,# s INTEGER# }@asn1.sequenceclassSignature:
r: ints: intsig=Signature.from_der(b"...")
raw: bytes=sig.to_der()
This declarative API should have fully generality/expressivity with respect to ASN.1's own feature set, including qualifiers like EXPLICIT and IMPLICIT:
This API should be 100% declarative: there should be no imperative effects on ASN.1 ser/de
Open design questions:
What's the best way to handle ANY? asn1.Any as a generic TLV type, similar to rust-asn1?
What's the best way to handle ANY DEFINED BY?
Maybe something like this:
@asn1.sequenceclassVaryMe:
content_type: asn1.ObjectIdentifiercontent: Annotated[Varied, asn1.defined_by("content_type")]
# or maybe we can do this with the standard enum.Enum?# or maybe @asn1.varied?classVaried(asn1.Enum):
foo: Annotated[VariantA, asn1.defined_by(SOME_OID)]
bar: Annotated[VariantB, asn1.defined_by(ANOTHER_OID)]
To what extent/how can we best support trivial "native" Python types (int, str, etc.) versus "synthetic" types?
Moreover, what's the appropriate isomorph for str? Probably UTF8String, with all other string-ish types being bytes?
What about non-trivial native types like list[T], set[T], etc? Should we support these with fixed mappings (e.g. list[T] -> SEQUENCE OF), or should we have our own types that don't require as much object conversion (e.g. asn.List[T])?
To what extent should we support datetime as a time type/map between datetime and UTCTime/GeneralizedTime?
One pitfall that we want to avoid is surprising serializations, e.g. a user really wants UTCTime OR GeneralizedTime but instead gets only GeneralizedTime
What's the best way to handle ASN.1 type constraints, e.g. ranged integers and min/max sequence/set lengths?
Probably additional fields on Annotated, e.g. Annotated[list[T], asn1.size(1...10)]
Not all of these make sense for an MVP, since plenty are obscure/not widely used (e.g. contained subtypes)
Open integration questions:
Where should this live within cryptography? Does cryptography.hazmat.asn1 make sense, or should it be cryptography.asn1, or something else?
There are probably many other questions too, and I'm sure I've missed some in my notes 🙂
As an implementation/integration consideration: we'll (@facutuesca and I) begin prototyping this as its own independent codebase, which should then be relatively straightforward to fold into Cryptography (since the only deps should be pyO3 and rust-asn1).
We need to extract each class definition's annotations with cls.__annotations__, inspect.get_annotations(), or typing.get_type_hints(). Which one of these to use will depend on the version of Python we're on, since Cryptography supports 3.7 (but we're targeting 3.8).
Once the annotations are extracted, we need to put them into a form that's sufficiently convenient for the Rust side to walk and generate a set of parsing actions from.
A successful parse should end with an instantiated T (for whatever T began the parse), which should also have some methods added to it (from_der(), to_der(), __init__(), etc.). This last bit can be done by the decorator itself.
The decorator itself will probably be purely on the Python side.
This is a meta-issue/design issue for tracking a declarative ASN.1 API for Cryptography!
The goal: an importable Python API that users of Cryptography can define ASN.1 structures with, which can then be ser/de'd to and from DER (and only DER).
A rough sketch, demonstrating the basic idioms of the API:
This declarative API should have fully generality/expressivity with respect to ASN.1's own feature set, including qualifiers like
EXPLICIT
andIMPLICIT
:This would also (naturally) include generality over user-defined types:
Key design constraints:
Open design questions:
What's the best way to handle
ANY
?asn1.Any
as a generic TLV type, similar to rust-asn1?What's the best way to handle
ANY DEFINED BY
?Maybe something like this:
To what extent/how can we best support trivial "native" Python types (
int
,str
, etc.) versus "synthetic" types?str
? ProbablyUTF8String
, with all other string-ish types beingbytes
?What about non-trivial native types like
list[T]
,set[T]
, etc? Should we support these with fixed mappings (e.g.list[T] -> SEQUENCE OF
), or should we have our own types that don't require as much object conversion (e.g.asn.List[T]
)?To what extent should we support
datetime
as a time type/map betweendatetime
andUTCTime
/GeneralizedTime
?UTCTime OR GeneralizedTime
but instead gets onlyGeneralizedTime
What's the best way to handle ASN.1 type constraints, e.g. ranged integers and min/max sequence/set lengths?
Annotated
, e.g.Annotated[list[T], asn1.size(1...10)]
Open integration questions:
cryptography
? Doescryptography.hazmat.asn1
make sense, or should it becryptography.asn1
, or something else?There are probably many other questions too, and I'm sure I've missed some in my notes 🙂
CC @facutuesca
The text was updated successfully, but these errors were encountered: