From b5143ff810a937e12491ba678575c09948d78300 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Fri, 6 Jan 2012 21:13:59 +0000 Subject: [PATCH] Add support for CHOICE in ASN.1 encoder Add a new field type where the length offset indicates a distinguisher and the data offset indicates a union address. The field's type is an atype_choice containing a seq_info indexed by the distinguisher. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25616 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/asn.1/asn1_encode.c | 18 ++++++++++++++++++ src/lib/krb5/asn.1/asn1_encode.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/lib/krb5/asn.1/asn1_encode.c b/src/lib/krb5/asn.1/asn1_encode.c index 5fc1efdfd..e654b7286 100644 --- a/src/lib/krb5/asn.1/asn1_encode.c +++ b/src/lib/krb5/asn.1/asn1_encode.c @@ -504,6 +504,24 @@ encode_a_field(asn1buf *buf, const void *val, const struct field_info *field, assert(omit_tag == NULL && !field->tag_implicit); break; } + case field_choice: + { + const void *dataptr = (const char *)val + field->dataoff; + unsigned int choice; + const struct seq_info *seq; + + assert(omit_tag == NULL); + assert(field->atype->type == atype_choice); + seq = field->atype->tinfo; + retval = get_field_len(val, field, &choice); + if (retval) + return retval; + if (choice > seq->n_fields) + return ASN1_MISSING_FIELD; + retval = encode_a_field(buf, dataptr, &seq->fields[choice], &length, + NULL); + break; + } default: assert(field->ftype > field_min); assert(field->ftype < field_max); diff --git a/src/lib/krb5/asn.1/asn1_encode.h b/src/lib/krb5/asn.1/asn1_encode.h index 85e4861a5..c1486d2be 100644 --- a/src/lib/krb5/asn.1/asn1_encode.h +++ b/src/lib/krb5/asn.1/asn1_encode.h @@ -193,6 +193,12 @@ enum atype_type { atype_ptr, /* Sequence. tinfo is a struct seq_info *. */ atype_sequence, + /* + * Choice. tinfo is a struct seq_info *, with the optional field ignored. + * Only usable with the field_choice field type. Cannot be used with an + * implicit context tag. + */ + atype_choice, /* * Sequence-of, with pointer to base type descriptor, represented * as a null-terminated array of pointers (and thus the "base" @@ -383,6 +389,15 @@ struct uint_info { const struct atype_info krb5int_asn1type_##DESCNAME = { \ atype_sequence, sizeof(CTYPENAME), &aux_seqinfo_##DESCNAME \ } +/* A choice, selected from the indicated series of fields. */ +#define DEFCHOICETYPE(DESCNAME, CTYPENAME, FIELDS) \ + typedef CTYPENAME aux_typedefname_##DESCNAME; \ + static const struct seq_info aux_seqinfo_##DESCNAME = { \ + NULL, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0]) \ + }; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_choice, sizeof(CTYPENAME), &aux_seqinfo_##DESCNAME \ + } /* Integer types. */ #define DEFINTTYPE(DESCNAME, CTYPENAME) \ typedef CTYPENAME aux_typedefname_##DESCNAME; \ @@ -574,6 +589,12 @@ enum field_type { * described by ATYPE. */ field_sequenceof_len, + /* + * LENOFF indicates a distinguisher and DATAOFF indicates a union base + * address. ATYPE is an atype_choice type pointing to a seq_info + * containing a field type for each choice element. + */ + field_choice, /* Unused except for range checking. */ field_max }; @@ -711,6 +732,17 @@ struct field_info { #define FIELDOF_SEQOF_INT32(STYPE,DESC,PTRFIELD,LENFIELD,TAG,IMPLICIT) \ FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,int32,TAG,IMPLICIT) +#define FIELDOF_OPTCHOICE(STYPE,DESC,PTRFIELD,CHOICEFIELD,LENTYPE,TAG,OPT) \ + { \ + field_choice, \ + OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \ + OFFOF(STYPE, CHOICEFIELD, aux_typedefname_##LENTYPE), \ + TAG, 0, OPT, \ + &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE \ + } +#define FIELDOF_CHOICE(STYPE,DESC,PTRFIELD,CHOICEFIELD,LENTYPE,TAG) \ + FIELDOF_OPTCHOICE(STYPE,DESC,PTRFIELD,CHOICEFIELD,LENTYPE,TAG,-1) + struct seq_info { /* * If present, returns a bitmask indicating which fields are -- 2.26.2