* asn1buf.c (asn1buf_sync): Add new arguments to include the full
authorTom Yu <tlyu@mit.edu>
Thu, 26 Oct 2000 22:58:13 +0000 (22:58 +0000)
committerTom Yu <tlyu@mit.edu>
Thu, 26 Oct 2000 22:58:13 +0000 (22:58 +0000)
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

src/lib/krb5/asn.1/ChangeLog
src/lib/krb5/asn.1/asn1_get.c
src/lib/krb5/asn.1/asn1_k_decode.c
src/lib/krb5/asn.1/asn1buf.c
src/lib/krb5/asn.1/asn1buf.h
src/lib/krb5/asn.1/krb5_decode.c

index f5aa4d7cc69d8d194efb28ef9c4b880ee5ad17a4..87decd05bb87b23c619e53c781eaee64fd771982 100644 (file)
@@ -1,3 +1,72 @@
+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
index b233a1aef8a7df3f49ca7804543d5f8a4b0d2342..fc945f115e651d5ad0a8a031138b14f31f127b62 100644 (file)
@@ -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;
 }
 
index b01506304daa53ea1bf7017156911dc8c0c6dae2..845f92b51e597177977b6659121a23b06c759373 100644 (file)
@@ -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));
index 61db90d485ce240921283c86e42e255de57f91f4..dcb0f6093b6c2d27fc0b8986ca432770099a008f 100644 (file)
@@ -54,6 +54,9 @@
 #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;
 {
@@ -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;
 }
 
index 4fbe03003719f4d060c540b652fa0ddaa9054507..9d4d245078ff8bdc9d799dee1a23d5767ec1d3ab 100644 (file)
@@ -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. */
index 0429a1a4b0c1172d0e5c790e980f46cd236f9ccb..42b09a783432650f7600ac32bf8f3b5b5624478b 100644 (file)
@@ -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]> <length> <contents>)
@@ -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);\
 }