Make a more ASN1-friendly CHOICE field (Enhancement)
This issue is a proposal to make a different ASN1 choice field type, say ASN1F_NAMEDCHOICE, that looks like a sequence. With this, choices from ASN1 definitions can be more easily translated to scapy, and a choice definition can be reused more easily in several packets/sequences.
Like a sequence, each alternative of the choice will be named. But only one value will be built when the field is expressed, and only one field will be created when the choice is dissected. Also, the value of the choice can be the last alternative that was assigned to any member.
Example borrowed from CMIP:
ObjectClass ::= CHOICE {
ocglobalForm [0] IMPLICIT OBJECT IDENTIFIER,
oclocalForm [1] IMPLICIT INTEGER
}
GetArgument ::= SEQUENCE {
baseManagedObjectClass ObjectClass,
baseManagedObjectInstance ObjectInstance,
...
}
GetResult ::= SEQUENCE {
managedObjectClass ObjectClass OPTIONAL,
managedObjectInstance ObjectInstance OPTIONAL,
currentTime [5] IMPLICIT GeneralizedTime OPTIONAL,
...
}
This is used in several sequences in this standard. The current syntax is clunky because each ASN1F_CHOICE instance must be named when it is defined rather than used, which results in extra names and encapsulations. Also the current ASN1F_CHOICE alternatives are class types which make it an additional burden when implicit or explicit tags are specified: one must create extra classes when the standard ASN1 field constructors have kwargs for them. Additionally, (I think) it's better to specify the name of the alternative which is being used in a standard.
With the syntax in this ticket proposal:
class ObjectClass(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_NAMEDCHOICE(
ASN1F_OID("ocglobalForm", None, implicit_tag=0x80),
ASN1F_INTEGER("oclocalForm", None, implicit_tag=0x81))
class GetArgument(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SEQUENCE(
ASN1F_PACKET("baseManagedObjectClass", ObjectClass(), ObjectClass),
ASN1F_PACKET("baseManagedObjectInstance", ObjectInstance(), ObjectInstance),
....
class GetResult(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SEQUENCE(
ASN1F_optional(ASN1F_PACKET("managedObjectClass", None, ObjectClass)),
ASN1F_optional(ASN1F_PACKET("managedObjectInstance", None, ObjectInstance)),
ASN1F_optional(ASN1F_GENERALIZED_TIME("currentTime", None, implicit_tag=0x85)),
....
Some hybrid of the sequence and choice does almost everything this new field type should; adapting them to become a "named choice" requires a bit more work/constraint to make it express only one alternative in encoding/decoding (basically iterate through the list alternatives and stop after one works) and not have a tag of its own.