From: Tom Yu Date: Thu, 26 Oct 2000 22:58:13 +0000 (+0000) Subject: * asn1buf.c (asn1buf_sync): Add new arguments to include the full X-Git-Tag: krb5-1.3-alpha1~1792 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=b5e198d5a487d71d92acf3cd2475071fd559554e;p=krb5.git * 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(). git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12816 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/asn.1/ChangeLog b/src/lib/krb5/asn.1/ChangeLog index f5aa4d7cc..87decd05b 100644 --- a/src/lib/krb5/asn.1/ChangeLog +++ b/src/lib/krb5/asn.1/ChangeLog @@ -1,3 +1,72 @@ +2000-10-26 Tom Yu + + * 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 * asn1buf.h: Lengths are now unsigned int for diff --git a/src/lib/krb5/asn.1/asn1_get.c b/src/lib/krb5/asn.1/asn1_get.c index b233a1aef..fc945f115 100644 --- a/src/lib/krb5/asn.1/asn1_get.c +++ b/src/lib/krb5/asn.1/asn1_get.c @@ -42,17 +42,13 @@ asn1_get_tag_indef(buf, class, construction, tagnum, retlen, indef) *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; } diff --git a/src/lib/krb5/asn.1/asn1_k_decode.c b/src/lib/krb5/asn.1/asn1_k_decode.c index b01506304..845f92b51 100644 --- a/src/lib/krb5/asn.1/asn1_k_decode.c +++ b/src/lib/krb5/asn.1/asn1_k_decode.c @@ -39,10 +39,16 @@ unsigned int length,taglen #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));\ @@ -59,15 +65,21 @@ if(class != APPLICATION || construction != CONSTRUCTED ||\ #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 @@ -76,12 +88,15 @@ 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)\ @@ -92,30 +107,58 @@ else { len = 0; var = 0; } #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 @@ -206,8 +249,8 @@ asn1_error_code asn1_decode_principal_name(buf, val) { 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)); @@ -221,8 +264,12 @@ asn1_error_code asn1_decode_principal_name(buf, val) 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; } @@ -528,7 +575,7 @@ if(*(array) == NULL) return ENOMEM;\ 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);\ @@ -665,7 +712,7 @@ asn1_error_code asn1_decode_sequence_of_enctype(buf, num, val) { 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)); diff --git a/src/lib/krb5/asn.1/asn1buf.c b/src/lib/krb5/asn.1/asn1buf.c index 61db90d48..dcb0f6093 100644 --- a/src/lib/krb5/asn.1/asn1buf.c +++ b/src/lib/krb5/asn.1/asn1buf.c @@ -54,6 +54,9 @@ #include #include "asn1_get.h" +#define asn1_is_eoc(class, num, indef) \ +((class) == UNIVERSAL && !(num) && !(indef)) + asn1_error_code asn1buf_create(buf) asn1buf ** buf; { @@ -91,34 +94,35 @@ asn1_error_code asn1buf_imbed(subbuf, buf, length, indef) 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; @@ -126,16 +130,29 @@ asn1_error_code asn1buf_skiptail(buf) 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; } @@ -248,8 +265,9 @@ asn1_error_code asn1buf_remove_charstring(buf, len, s) 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; @@ -257,15 +275,9 @@ int asn1buf_remains(buf) 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; } diff --git a/src/lib/krb5/asn.1/asn1buf.h b/src/lib/krb5/asn.1/asn1buf.h index 4fbe03003..9d4d24507 100644 --- a/src/lib/krb5/asn.1/asn1buf.h +++ b/src/lib/krb5/asn.1/asn1buf.h @@ -122,14 +122,17 @@ asn1_error_code asn1buf_imbed 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. */ @@ -222,7 +225,7 @@ asn1_error_code asn12krb5_buf 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. */ diff --git a/src/lib/krb5/asn.1/krb5_decode.c b/src/lib/krb5/asn.1/krb5_decode.c index 0429a1a4b..42b09a783 100644 --- a/src/lib/krb5/asn.1/krb5_decode.c +++ b/src/lib/krb5/asn.1/krb5_decode.c @@ -77,23 +77,29 @@ if(tagnum != (tagexpect)) clean_return(KRB5_BADMSGTYPE) /* 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 *******************************************/ @@ -101,6 +107,7 @@ if (retval) clean_return(retval) #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]> ) @@ -110,26 +117,35 @@ next_tag() #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);\ }