complement of data about a prefetched tag, as well as to indicate
whether the prefetched tag or the surrounding sequence is of an
indefinite length.
(asn1buf_skiptail): Add new arguments to indicate whether the
prefetched tag is indefinite, as well as its length. This
facilitates proper skipping of trailing garbage.
(asn1buf_remains): Add new argument to indicate whether the
surrounding encoding is indefinite. Don't advance buf->next if an
EOC encoding is detected; the caller will do that.
* asn1buf.h: Update prototypes.
* asn1_get.c (asn1_get_tag_indef): Don't treat EOC encoding as
special anymore, since previous behavior was overloading the
tag number in a bad way. Also, report a MISMATCH_INDEF error if
the tag encoding is for the forbidden primitive constructed
encoding.
* asn1_k_decode.c (next_tag): Call get_tag_indef() in order to get
information about whether the length is indefinite. Don't check
the tag class and construction explicitly.
(get_eoc): New macro to get a tag and check if it is an EOC
encoding.
(get_field, opt_field): Move the check for the tag class and
construction to here.
(get_field_body, get_lenfield_body): Call get_eoc() instead of
next_tag() if we are decoding a constructed indefinite encoding.
(begin_structure): Use a different variable to indicate whether
the sequence is indefinite as opposed to whether an individual
field is indefinite.
(end_structure): Update to new calling convention of
asn1buf_sync().
(sequence_of): Rewrite significantly.
(sequence_of_common): Move the bulk of previous sequence_of()
macro to here. Does not declare some variables that sequence_of()
declares.
(sequence_of_no_tagvars): Similar to sequence_of() macro but
declares different variables for the purpose of prefetching the
final tag.
(end_sequence_of_no_tagvars): Similar to end_sequence_of() macro
but uses variables declared by the sequence_of_no_tagvars() macro
to prefetch the final tag.
(asn1_decode_principal_name): Update for new asn1buf_remains()
calling convention. Call sequence_of_no_tagvars(), etc. instead
of sequence_of(), etc. in order to not declare shadowing
block-local variables.
(decode_array_body): Update for new asn1buf_remains() calling
convention.
(asn1_decode_sequence_of_enctype): Update for new
asn1buf_remains() calling convention.
* krb5_decode.c (next_tag): Call get_tag_indef() in order to get
information about whether the length is indefinite. Don't check
the tag class and construction explicitly.
(get_eoc): New macro to get a tag and check if it is an EOC
encoding.
(get_field, opt_field): Move the check for the tag class and
construction to here.
(get_field_body, get_lenfield_body): Call get_eoc() instead of
next_tag() if we are decoding a constructed indefinite encoding.
(begin_structure): Use a different variable to indicate whether
the sequence is indefinite as opposed to whether an individual
field is indefinite.
(end_structure): Update to new calling convention of
asn1buf_sync().
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12816
dc483132-0cff-0310-8789-
dd5450dbe970
+2000-10-26 Tom Yu <tlyu@mit.edu>
+
+ * asn1buf.c (asn1buf_sync): Add new arguments to include the full
+ complement of data about a prefetched tag, as well as to indicate
+ whether the prefetched tag or the surrounding sequence is of an
+ indefinite length.
+ (asn1buf_skiptail): Add new arguments to indicate whether the
+ prefetched tag is indefinite, as well as its length. This
+ facilitates proper skipping of trailing garbage.
+ (asn1buf_remains): Add new argument to indicate whether the
+ surrounding encoding is indefinite. Don't advance buf->next if an
+ EOC encoding is detected; the caller will do that.
+
+ * asn1buf.h: Update prototypes.
+
+ * asn1_get.c (asn1_get_tag_indef): Don't treat EOC encoding as
+ special anymore, since previous behavior was overloading the
+ tag number in a bad way. Also, report a MISMATCH_INDEF error if
+ the tag encoding is for the forbidden primitive constructed
+ encoding.
+
+ * asn1_k_decode.c (next_tag): Call get_tag_indef() in order to get
+ information about whether the length is indefinite. Don't check
+ the tag class and construction explicitly.
+ (get_eoc): New macro to get a tag and check if it is an EOC
+ encoding.
+ (get_field, opt_field): Move the check for the tag class and
+ construction to here.
+ (get_field_body, get_lenfield_body): Call get_eoc() instead of
+ next_tag() if we are decoding a constructed indefinite encoding.
+ (begin_structure): Use a different variable to indicate whether
+ the sequence is indefinite as opposed to whether an individual
+ field is indefinite.
+ (end_structure): Update to new calling convention of
+ asn1buf_sync().
+ (sequence_of): Rewrite significantly.
+ (sequence_of_common): Move the bulk of previous sequence_of()
+ macro to here. Does not declare some variables that sequence_of()
+ declares.
+ (sequence_of_no_tagvars): Similar to sequence_of() macro but
+ declares different variables for the purpose of prefetching the
+ final tag.
+ (end_sequence_of_no_tagvars): Similar to end_sequence_of() macro
+ but uses variables declared by the sequence_of_no_tagvars() macro
+ to prefetch the final tag.
+ (asn1_decode_principal_name): Update for new asn1buf_remains()
+ calling convention. Call sequence_of_no_tagvars(), etc. instead
+ of sequence_of(), etc. in order to not declare shadowing
+ block-local variables.
+ (decode_array_body): Update for new asn1buf_remains() calling
+ convention.
+ (asn1_decode_sequence_of_enctype): Update for new
+ asn1buf_remains() calling convention.
+
+ * krb5_decode.c (next_tag): Call get_tag_indef() in order to get
+ information about whether the length is indefinite. Don't check
+ the tag class and construction explicitly.
+ (get_eoc): New macro to get a tag and check if it is an EOC
+ encoding.
+ (get_field, opt_field): Move the check for the tag class and
+ construction to here.
+ (get_field_body, get_lenfield_body): Call get_eoc() instead of
+ next_tag() if we are decoding a constructed indefinite encoding.
+ (begin_structure): Use a different variable to indicate whether
+ the sequence is indefinite as opposed to whether an individual
+ field is indefinite.
+ (end_structure): Update to new calling convention of
+ asn1buf_sync().
+
2000-10-17 Ezra Peisach <epeisach@mit.edu>
* asn1buf.h: Lengths are now unsigned int for
*tagnum = ASN1_TAGNUM_CEILING;
return 0;
}
- /* Allow for the indefinite encoding */
- if ((buf->bound - buf->next + 1 >= 2)
- && !*(buf->next) && !*(buf->next + 1)) {
- buf->next += 2;
- *tagnum = ASN1_TAGNUM_CEILING;
- return 0;
- }
retval = asn1_get_id(buf,class,construction,tagnum);
if(retval) return retval;
retval = asn1_get_length(buf,retlen,indef);
if(retval) return retval;
+ if (indef != NULL && *indef &&
+ construction != NULL && *construction != CONSTRUCTED)
+ return ASN1_MISMATCH_INDEF;
return 0;
}
#define unused_var(x) if(0) x=0
#define next_tag()\
-retval = asn1_get_tag(&subbuf,&class,&construction,&tagnum,&taglen);\
-if(retval) return retval;\
-if(class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
- return ASN1_BAD_ID
+retval = asn1_get_tag_indef(&subbuf,&class,&construction,\
+ &tagnum,&taglen,&indef);\
+if(retval) return retval;
+
+#define get_eoc() \
+retval = asn1_get_tag_indef(&subbuf,&class,&construction, \
+ &tagnum,&taglen,&indef); \
+if(retval) return retval; \
+if(class != UNIVERSAL || tagnum || indef) \
+ return ASN1_MISSING_EOC
#define alloc_field(var,type)\
var = (type*)calloc(1,sizeof(type));\
#define get_field_body(var,decoder)\
retval = decoder(&subbuf,&(var));\
if(retval) return retval;\
-if(!taglen) { next_tag(); }\
+if(!taglen && indef) { get_eoc(); }\
next_tag()
#define get_field(var,tagexpect,decoder)\
if(tagnum > (tagexpect)) return ASN1_MISSING_FIELD;\
if(tagnum < (tagexpect)) return ASN1_MISPLACED_FIELD;\
+if((class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ && (tagnum || taglen || class != UNIVERSAL)) \
+ return ASN1_BAD_ID;\
get_field_body(var,decoder)
#define opt_field(var,tagexpect,decoder,optvalue)\
+if((class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ && (tagnum || taglen || class != UNIVERSAL)) \
+ return ASN1_BAD_ID;\
if(tagnum == (tagexpect)){\
get_field_body(var,decoder); }\
else var = optvalue
#define get_lenfield_body(len,var,decoder)\
retval = decoder(&subbuf,&(len),&(var));\
if(retval) return retval;\
-if(!taglen) { next_tag(); }\
+if(!taglen && indef) { get_eoc(); }\
next_tag()
#define get_lenfield(len,var,tagexpect,decoder)\
if(tagnum > (tagexpect)) return ASN1_MISSING_FIELD;\
if(tagnum < (tagexpect)) return ASN1_MISPLACED_FIELD;\
+if((class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ && (tagnum || taglen || class != UNIVERSAL)) \
+ return ASN1_BAD_ID;\
get_lenfield_body(len,var,decoder)
#define opt_lenfield(len,var,tagexpect,decoder)\
#define begin_structure()\
asn1buf subbuf;\
+int seqindef;\
int indef;\
-retval = asn1_get_sequence(buf,&length,&indef);\
+retval = asn1_get_sequence(buf,&length,&seqindef);\
if(retval) return retval;\
-retval = asn1buf_imbed(&subbuf,buf,length,indef);\
+retval = asn1buf_imbed(&subbuf,buf,length,seqindef);\
if(retval) return retval;\
next_tag()
#define end_structure()\
-retval = asn1buf_sync(buf,&subbuf,tagnum,length);\
+retval = asn1buf_sync(buf,&subbuf,class,tagnum,length,indef,seqindef);\
if(retval) return retval
-#define sequence_of(buf)\
-int size=0;\
-asn1buf seqbuf;\
-unsigned int length;\
-int indef;\
-retval = asn1_get_sequence(buf,&length,&indef);\
-if(retval) return retval;\
-retval = asn1buf_imbed(&seqbuf,buf,length,indef);\
+#define sequence_of(buf) \
+unsigned int length, taglen; \
+asn1_class class; \
+asn1_construction construction; \
+asn1_tagnum tagnum; \
+int indef; \
+sequence_of_common(buf)
+
+#define sequence_of_common(buf) \
+int size=0; \
+asn1buf seqbuf; \
+int seqofindef; \
+retval = asn1_get_sequence(buf,&length,&seqofindef); \
+if(retval) return retval; \
+retval = asn1buf_imbed(&seqbuf,buf,length,seqofindef); \
if(retval) return retval
-#define end_sequence_of(buf)\
-retval = asn1buf_sync(buf,&seqbuf,ASN1_TAGNUM_CEILING,length);\
-if(retval) return retval
+#define sequence_of_no_tagvars(buf) \
+asn1_class eseqclass; \
+asn1_construction eseqconstr; \
+asn1_tagnum eseqnum; \
+unsigned int eseqlen; \
+int eseqindef; \
+sequence_of_common(buf)
+
+#define end_sequence_of_no_tagvars(buf) \
+retval = asn1_get_tag_indef(&seqbuf,&eseqclass,&eseqconstr, \
+ &eseqnum,&eseqlen,&eseqindef); \
+if(retval) return retval; \
+retval = asn1buf_sync(buf,&seqbuf,eseqclass,eseqnum, \
+ eseqlen,eseqindef,seqofindef); \
+if(retval) return retval;
+
+#define end_sequence_of(buf) \
+retval = asn1_get_tag_indef(&seqbuf,&class,&construction, \
+ &tagnum,&taglen,&indef); \
+if(retval) return retval; \
+retval = asn1buf_sync(buf,&seqbuf,class,tagnum, \
+ length,indef,seqofindef); \
+if(retval) return retval;
#define cleanup()\
return 0
{ begin_structure();
get_field((*val)->type,0,asn1_decode_int32);
- { sequence_of(&subbuf);
- while(asn1buf_remains(&seqbuf)){
+ { sequence_of_no_tagvars(&subbuf);
+ while(asn1buf_remains(&seqbuf,seqofindef) > 0){
size++;
if ((*val)->data == NULL)
(*val)->data = (krb5_data*)malloc(size*sizeof(krb5_data));
if(retval) return retval;
}
(*val)->length = size;
- end_sequence_of(&subbuf);
+ end_sequence_of_no_tagvars(&subbuf);
+ }
+ if (indef) {
+ get_eoc();
}
+ next_tag();
end_structure();
(*val)->magic = KV5M_PRINCIPAL;
}
type *elt;\
\
{ sequence_of(buf);\
- while(asn1buf_remains(&seqbuf) > 0){\
+ while(asn1buf_remains(&seqbuf,seqofindef) > 0){\
alloc_field(elt,type);\
get_element(elt,decoder);\
array_append(val,size,elt,type);\
{
asn1_error_code retval;
{ sequence_of(buf);
- while(asn1buf_remains(&seqbuf) > 0){
+ while(asn1buf_remains(&seqbuf,seqofindef) > 0){
size++;
if (*val == NULL)
*val = (krb5_enctype*)malloc(size*sizeof(krb5_enctype));
#include <stdio.h>
#include "asn1_get.h"
+#define asn1_is_eoc(class, num, indef) \
+((class) == UNIVERSAL && !(num) && !(indef))
+
asn1_error_code asn1buf_create(buf)
asn1buf ** buf;
{
return 0;
}
-asn1_error_code asn1buf_sync(buf, subbuf, lasttag, length)
+asn1_error_code asn1buf_sync(buf, subbuf, class, lasttag, length, indef, seqindef)
asn1buf * buf;
asn1buf * subbuf;
+ const asn1_class class;
const asn1_tagnum lasttag;
const unsigned int length;
+ const int indef;
+ const int seqindef;
{
asn1_error_code retval;
- if (length) {
+ if (!seqindef) {
+ /* sequence was encoded as definite length */
buf->next = subbuf->bound + 1;
+ } else if (!asn1_is_eoc(class, lasttag, indef)) {
+ retval = asn1buf_skiptail(subbuf, length, indef);
+ if (retval)
+ return retval;
} else {
- /*
- * indefinite length:
- *
- * Note that asn1_get_tag() returns ASN1_TAGNUM_CEILING
- * for an EOC encoding.
- */
- if (lasttag != ASN1_TAGNUM_CEILING) {
- retval = asn1buf_skiptail(subbuf);
- if (retval) return retval;
- }
+ /* We have just read the EOC octets. */
buf->next = subbuf->next;
}
return 0;
}
-asn1_error_code asn1buf_skiptail(buf)
+asn1_error_code asn1buf_skiptail(buf, length, indef)
asn1buf *buf;
+ const unsigned int length;
+ const int indef;
{
asn1_error_code retval;
asn1_class class;
asn1_tagnum tagnum;
unsigned int taglen;
int nestlevel;
+ int tagindef;
- nestlevel = 1;
+ nestlevel = 1 + indef;
+ if (!indef) {
+ if (length <= buf->bound - buf->next + 1)
+ buf->next += length;
+ else
+ return ASN1_OVERRUN;
+ }
while (nestlevel > 0) {
- retval = asn1_get_tag(buf, &class, &construction, &tagnum, &taglen);
+ retval = asn1_get_tag_indef(buf, &class, &construction, &tagnum,
+ &taglen, &tagindef);
if (retval) return retval;
- buf->next += taglen;
- if (construction == CONSTRUCTED && taglen == 0)
+ if (!tagindef) {
+ if (taglen <= buf->bound - buf->next + 1)
+ buf->next += taglen;
+ else
+ return ASN1_OVERRUN;
+ }
+ if (tagindef)
nestlevel++;
- if (tagnum == ASN1_TAGNUM_CEILING)
- nestlevel--;
+ if (asn1_is_eoc(class, tagnum, tagindef))
+ nestlevel--; /* got an EOC encoding */
}
return 0;
}
return 0;
}
-int asn1buf_remains(buf)
+int asn1buf_remains(buf, indef)
asn1buf *buf;
+ int indef;
{
int remain;
if(buf == NULL || buf->base == NULL) return 0;
if (remain <= 0) return remain;
/*
* Two 0 octets means the end of an indefinite encoding.
- *
- * XXX Do we need to test to make sure we'er actually doing an
- * indefinite encoding here?
*/
- if ( !*(buf->next) && !*(buf->next + 1)) {
- /* buf->bound = buf->next + 1; */
- buf->next += 2;
+ if (indef && remain >= 2 && !*(buf->next) && !*(buf->next + 1))
return 0;
- }
else return remain;
}
position starts at the beginning of *subbuf. */
asn1_error_code asn1buf_sync
- PROTOTYPE((asn1buf *buf, asn1buf *subbuf, const asn1_tagnum lasttag,
- const unsigned int length));
+ PROTOTYPE((asn1buf *buf, asn1buf *subbuf, const asn1_class class,
+ const asn1_tagnum lasttag,
+ const unsigned int length, const int indef,
+ const int seqindef));
/* requires *subbuf is a sub-buffer of *buf, as created by asn1buf_imbed.
- lasttag is a pointer to the last tagnumber read.
+ lasttag is the last tagnumber read.
effects Synchronizes *buf's current position to match that of *subbuf. */
asn1_error_code asn1buf_skiptail
- PROTOTYPE((asn1buf *buf));
+ PROTOTYPE((asn1buf *buf, const unsigned int length,
+ const int indef));
/* requires *buf is a subbuffer used in a decoding of a
constructed indefinite sequence.
effects skips trailing fields. */
int asn1buf_remains
- PROTOTYPE((asn1buf *buf));
+ PROTOTYPE((asn1buf *buf, int indef));
/* requires *buf is a buffer containing an asn.1 structure or array
modifies *buf
effects Returns the number of unprocessed octets remaining in *buf. */
/* decode an explicit tag and place the number in tagnum */
#define next_tag()\
-retval = asn1_get_tag(&subbuf,&class,&construction,&tagnum,NULL);\
-if(retval) clean_return(retval);\
-if(class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
- clean_return(ASN1_BAD_ID)
+retval = asn1_get_tag_indef(&subbuf,&class,&construction,&tagnum,NULL,&indef);\
+if(retval) clean_return(retval)
+
+#define get_eoc() \
+retval = asn1_get_tag_indef(&subbuf,&class,&construction, \
+ &tagnum,NULL,&indef); \
+if(retval) return retval; \
+if(class != UNIVERSAL || tagnum || indef) \
+ return ASN1_MISSING_EOC
/* decode sequence header and initialize tagnum with the first field */
#define begin_structure()\
asn1buf subbuf;\
+int seqindef;\
int indef;\
-retval = asn1_get_sequence(&buf,&length,&indef);\
+retval = asn1_get_sequence(&buf,&length,&seqindef);\
if(retval) clean_return(retval);\
-retval = asn1buf_imbed(&subbuf,&buf,length,indef);\
+retval = asn1buf_imbed(&subbuf,&buf,length,seqindef);\
if(retval) clean_return(retval);\
next_tag()
#define end_structure()\
-retval = asn1buf_sync(&buf,&subbuf,tagnum,length);\
+retval = asn1buf_sync(&buf,&subbuf,class,tagnum,length,indef,seqindef);\
if (retval) clean_return(retval)
/* process fields *******************************************/
#define get_field_body(var,decoder)\
retval = decoder(&subbuf,&(var));\
if(retval) clean_return(retval);\
+if (indef) { get_eoc(); }\
next_tag()
/* decode a field (<[UNIVERSAL id]> <length> <contents>)
#define get_field(var,tagexpect,decoder)\
if(tagnum > (tagexpect)) clean_return(ASN1_MISSING_FIELD);\
if(tagnum < (tagexpect)) clean_return(ASN1_MISPLACED_FIELD);\
+if(class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
+ clean_return(ASN1_BAD_ID);\
get_field_body(var,decoder)
/* decode (or skip, if not present) an optional field */
#define opt_field(var,tagexpect,decoder)\
+if(class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
+ clean_return(ASN1_BAD_ID);\
if(tagnum == (tagexpect)){ get_field_body(var,decoder); }
/* field w/ accompanying length *********/
#define get_lenfield_body(len,var,decoder)\
retval = decoder(&subbuf,&(len),&(var));\
if(retval) clean_return(retval);\
+if (indef) { get_eoc(); }\
next_tag()
/* decode a field w/ its length (for string types) */
#define get_lenfield(len,var,tagexpect,decoder)\
if(tagnum > (tagexpect)) clean_return(ASN1_MISSING_FIELD);\
if(tagnum < (tagexpect)) clean_return(ASN1_MISPLACED_FIELD);\
+if(class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
+ clean_return(ASN1_BAD_ID);\
get_lenfield_body(len,var,decoder)
/* decode an optional field w/ length */
#define opt_lenfield(len,var,tagexpect,decoder)\
+if(class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
+ clean_return(ASN1_BAD_ID);\
if(tagnum == (tagexpect)){\
get_lenfield_body(len,var,decoder);\
}