svn rev #25622: trunk/src/lib/krb5/asn.1/

ghudson@MIT.EDU ghudson at MIT.EDU
Sat Jan 7 21:10:47 EST 2012


http://src.mit.edu/fisheye/changelog/krb5/?cs=25622
Commit By: ghudson
Log Message:
Clean up the asn1 encoder design

Now that the PKINIT types have been converted and atype_fn has only
one use, we can more easily modify the encoder so that any object can
be encoded without its tag, which makes for a cleaner design.  The
basic building block is now krb5int_asn1_encode_type, which encodes
the contents of a function and returns its tag information to the
caller.

atype_fn now has its own structure, and the encoder function it
references follows the semantics of krb5int_asn1_encode_type.
atype_opaque is now atype_der and goes with a new corresponding field
type (field_der); stored DER encodings are parsed to separate the tag
from the content.


Changed Files:
U   trunk/src/lib/krb5/asn.1/asn1_encode.c
U   trunk/src/lib/krb5/asn.1/asn1_encode.h
U   trunk/src/lib/krb5/asn.1/asn1_k_encode.c
Modified: trunk/src/lib/krb5/asn.1/asn1_encode.c
===================================================================
--- trunk/src/lib/krb5/asn.1/asn1_encode.c	2012-01-07 20:57:36 UTC (rev 25621)
+++ trunk/src/lib/krb5/asn.1/asn1_encode.c	2012-01-08 02:10:47 UTC (rev 25622)
@@ -176,8 +176,9 @@
  *
  * Two entry points here:
  *
- * krb5int_asn1_encode_a_thing: Incrementally adds the partial
- * encoding of an object to an already-initialized asn1buf.
+ * krb5int_asn1_encode_type: Incrementally adds the contents-only encoding of
+ * an object to an already-initialized asn1buf, and returns its tag
+ * information.
  *
  * krb5int_asn1_do_full_encode: Returns a completed encoding, in the
  * correct byte order, in an allocated krb5_data.
@@ -235,142 +236,143 @@
                      const struct seq_info *seq,
                      unsigned int *retlen);
 static asn1_error_code
-encode_a_field(asn1buf *buf, const void *val,
-               const struct field_info *field,
-               unsigned int *retlen, asn1_construction *omit_tag);
+encode_a_field(asn1buf *buf, const void *val, const struct field_info *field,
+               taginfo *rettag);
 
-/* Encode a value according to a type.  If omit_tag is non-NULL, omit the
- * outer tag and return its construction bit instead. */
-static asn1_error_code
-encode_type(asn1buf *buf, const void *val, const struct atype_info *a,
-            unsigned int *retlen, asn1_construction *omit_tag)
+/* Encode a value (contents only, no outer tag) according to a type, and return
+ * its encoded tag information. */
+asn1_error_code
+krb5int_asn1_encode_type(asn1buf *buf, const void *val,
+                         const struct atype_info *a, taginfo *rettag)
 {
     asn1_error_code retval;
-    asn1_class tagclass = UNIVERSAL;
-    asn1_construction construction = PRIMITIVE;
-    asn1_tagnum tagnum = -1;
-    unsigned int length, sum = 0;
 
-    /*
-     * In the switch statement, do one of the following: (1) encode the
-     * contents of val and set tagclass, construction, and tagnum to the
-     * appropriate values for the tag; (2) encode the contents and tag, leaving
-     * tagnum alone (won't work with implicit tagging); (3) delegate the whole
-     * process to a subcall.  If not returning immediately, set length to the
-     * number of bytes encoded.
-     */
     switch (a->type) {
-    case atype_primitive:
-    case atype_fn:
-    {
+    case atype_primitive: {
         const struct primitive_info *prim = a->tinfo;
         assert(prim->enc != NULL);
-        retval = prim->enc(buf, val, &length);
+        retval = prim->enc(buf, val, &rettag->length);
         if (retval) return retval;
-        if (a->type == atype_primitive)
-            tagnum = prim->tagval;
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = PRIMITIVE;
+        rettag->tagnum = prim->tagval;
         break;
     }
+    case atype_fn: {
+        const struct fn_info *fn = a->tinfo;
+        assert(fn->enc != NULL);
+        return fn->enc(buf, val, rettag);
+    }
     case atype_sequence:
         assert(a->tinfo != NULL);
-        retval = just_encode_sequence(buf, val, a->tinfo, &length);
+        retval = just_encode_sequence(buf, val, a->tinfo, &rettag->length);
         if (retval)
             return retval;
-        construction = CONSTRUCTED;
-        tagnum = ASN1_SEQUENCE;
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = CONSTRUCTED;
+        rettag->tagnum = ASN1_SEQUENCE;
         break;
-    case atype_ptr:
-    {
+    case atype_ptr: {
         const struct ptr_info *ptr = a->tinfo;
         assert(ptr->basetype != NULL);
-        return encode_type(buf, LOADPTR(val, ptr), ptr->basetype, retlen,
-                           omit_tag);
+        return krb5int_asn1_encode_type(buf, LOADPTR(val, ptr), ptr->basetype,
+                                        rettag);
     }
     case atype_field:
         assert(a->tinfo != NULL);
-        return encode_a_field(buf, val, a->tinfo, retlen, omit_tag);
+        return encode_a_field(buf, val, a->tinfo, rettag);
     case atype_nullterm_sequence_of:
     case atype_nonempty_nullterm_sequence_of:
         assert(a->tinfo != NULL);
         retval = encode_nullterm_sequence_of(buf, val, a->tinfo,
                                              a->type ==
                                              atype_nullterm_sequence_of,
-                                             &length);
+                                             &rettag->length);
         if (retval)
             return retval;
-        construction = CONSTRUCTED;
-        tagnum = ASN1_SEQUENCE;
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = CONSTRUCTED;
+        rettag->tagnum = ASN1_SEQUENCE;
         break;
-    case atype_tagged_thing:
-    {
+    case atype_tagged_thing: {
         const struct tagged_info *tag = a->tinfo;
-        if (tag->implicit) {
-            retval = encode_type(buf, val, tag->basetype, &length,
-                                 &construction);
-        } else {
-            retval = encode_type(buf, val, tag->basetype, &length, NULL);
-            construction = tag->construction;
+        retval = krb5int_asn1_encode_type(buf, val, tag->basetype, rettag);
+        if (retval)
+            return retval;
+        if (!tag->implicit) {
+            unsigned int tlen;
+            retval = asn1_make_tag(buf, rettag->asn1class,
+                                   rettag->construction, rettag->tagnum,
+                                   rettag->length, &tlen);
+            if (retval)
+                return retval;
+            rettag->length += tlen;
+            rettag->construction = tag->construction;
         }
-        tagclass = tag->tagtype;
-        tagnum = tag->tagval;
+        rettag->asn1class = tag->tagtype;
+        rettag->tagnum = tag->tagval;
         break;
     }
-    case atype_int:
-    {
+    case atype_int: {
         const struct int_info *tinfo = a->tinfo;
         assert(tinfo->loadint != NULL);
-        retval = asn1_encode_integer(buf, tinfo->loadint(val), &length);
+        retval = asn1_encode_integer(buf, tinfo->loadint(val),
+                                     &rettag->length);
         if (retval)
             return retval;
-        tagnum = ASN1_INTEGER;
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = PRIMITIVE;
+        rettag->tagnum = ASN1_INTEGER;
         break;
     }
-    case atype_uint:
-    {
+    case atype_uint: {
         const struct uint_info *tinfo = a->tinfo;
         assert(tinfo->loaduint != NULL);
         retval = asn1_encode_unsigned_integer(buf, tinfo->loaduint(val),
-                                              &length);
+                                              &rettag->length);
         if (retval)
             return retval;
-        tagnum = ASN1_INTEGER;
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = PRIMITIVE;
+        rettag->tagnum = ASN1_INTEGER;
         break;
     }
     case atype_min:
     case atype_max:
     case atype_string:          /* only usable with field_string */
-    case atype_opaque:          /* only usable with field_string */
+    case atype_der:             /* only usable with field_der */
+    case atype_choice:          /* only usable with field_choice */
     default:
         assert(a->type > atype_min);
         assert(a->type < atype_max);
         assert(a->type != atype_string);
-        assert(a->type != atype_opaque);
+        assert(a->type != atype_der);
+        assert(a->type != atype_choice);
         abort();
     }
 
-    sum += length;
-    assert(omit_tag == NULL || tagnum != -1);
-    if (omit_tag == NULL && tagnum >= 0) {
-        /* We have not yet encoded the outer tag and should do so. */
-        retval = asn1_make_tag(buf, tagclass, construction, tagnum, sum,
-                               &length);
-        if (retval)
-            return retval;
-        sum += length;
-    } else if (omit_tag != NULL) {
-        /* Don't encode the tag; report its construction bit to the caller. */
-        *omit_tag = construction;
-    }
+    return 0;
+}
 
-    *retlen = sum;
+static asn1_error_code
+encode_type_and_tag(asn1buf *buf, const void *val, const struct atype_info *a,
+                    unsigned int *retlen)
+{
+    taginfo t;
+    asn1_error_code retval;
+    unsigned int tlen;
+
+    retval = krb5int_asn1_encode_type(buf, val, a, &t);
+    if (retval)
+        return retval;
+    retval = asn1_make_tag(buf, t.asn1class, t.construction, t.tagnum,
+                           t.length, &tlen);
+    if (retval)
+        return retval;
+    *retlen = t.length + tlen;
     return 0;
 }
 
-/*
- * Encode a value according to a field specification, adding a context tag if
- * specified.  If omit_tag is non-NULL, omit the outer tag and return its
- * construction bit instead (only valid if the field has no context tag).
- */
 static asn1_error_code
 get_field_len(const void *val, const struct field_info *field,
               unsigned int *retlen)
@@ -404,40 +406,51 @@
     return 0;
 }
 
+/* Split a DER encoding into tag and contents.  Insert the contents into buf,
+ * then return the length of the contents and the tag. */
 static asn1_error_code
+split_der(asn1buf *buf, const unsigned char *der, unsigned int len,
+          taginfo *rettag)
+{
+    asn1buf der_buf;
+    krb5_data der_data = make_data((unsigned char *)der, len);
+    asn1_error_code retval;
+
+    retval = asn1buf_wrap_data(&der_buf, &der_data);
+    if (retval)
+        return retval;
+    retval = asn1_get_tag_2(&der_buf, rettag);
+    if (retval)
+        return retval;
+    if ((unsigned int)asn1buf_remains(&der_buf, 0) != rettag->length)
+        return EINVAL;
+    return asn1buf_insert_bytestring(buf, rettag->length,
+                                     der + len - rettag->length);
+}
+
+/* Encode part of a value (contents only, no tag) according to a field
+ * descriptor and return its encoded length and tag. */
+static asn1_error_code
 encode_a_field(asn1buf *buf, const void *val, const struct field_info *field,
-               unsigned int *retlen, asn1_construction *omit_tag)
+               taginfo *rettag)
 {
     asn1_error_code retval;
-    asn1_class tagclass = UNIVERSAL;
-    asn1_construction construction = PRIMITIVE;
-    asn1_tagnum tagnum = -1;
-    unsigned int sum = 0, length;
 
     if (val == NULL) return ASN1_MISSING_FIELD;
-    assert(omit_tag == NULL || field->tag < 0);
     assert(!(field->tag_implicit && field->tag < 0));
 
-    /*
-     * In the switch statement, either (1) encode the contents of the field and
-     * set tagclass, construction, and tagnum to the appropriate values for the
-     * tag; (2) encode the contents and tag, leaving tagnum alone; (3) delegate
-     * the whole process to a subcall (only an option if the field has no
-     * context tag).  If not returning immediately, set length to the number of
-     * bytes encoded.
-     */
     switch (field->ftype) {
-    case field_immediate:
-    {
+    case field_immediate: {
         retval = asn1_encode_integer(buf, (asn1_intmax) field->dataoff,
-                                     &length);
+                                     &rettag->length);
         if (retval)
             return retval;
-        tagnum = ASN1_INTEGER;
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = PRIMITIVE;
+        rettag->tagnum = ASN1_INTEGER;
         break;
     }
-    case field_sequenceof_len:
-    {
+    case field_sequenceof_len: {
         const void *dataptr = (const char *)val + field->dataoff;
         unsigned int slen;
         const struct ptr_info *ptrinfo;
@@ -456,37 +469,29 @@
         if (slen != 0 && dataptr == NULL)
             return ASN1_MISSING_FIELD;
         retval = encode_sequence_of(buf, slen, dataptr, ptrinfo->basetype,
-                                    &length);
+                                    &rettag->length);
         if (retval)
             return retval;
-        construction = CONSTRUCTED;
-        tagnum = ASN1_SEQUENCE;
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = CONSTRUCTED;
+        rettag->tagnum = ASN1_SEQUENCE;
         break;
     }
-    case field_normal:
-    {
+    case field_normal: {
         const void *dataptr = (const char *)val + field->dataoff;
-        if (omit_tag != NULL)
-            return encode_type(buf, dataptr, field->atype, retlen, omit_tag);
-        if (field->tag_implicit) {
-            retval = encode_type(buf, dataptr, field->atype, &length,
-                                 &construction);
-        } else
-            retval = encode_type(buf, dataptr, field->atype, &length, NULL);
+        retval = krb5int_asn1_encode_type(buf, dataptr, field->atype, rettag);
         if (retval)
             return retval;
         break;
     }
-    case field_string:
-    {
+    case field_string: {
         const void *dataptr = (const char *)val + field->dataoff;
         const struct atype_info *a;
         unsigned int slen;
         const struct string_info *string;
 
         a = field->atype;
-        assert(a->type == atype_string || a->type == atype_opaque);
-        assert(!(a->type == atype_opaque && field->tag_implicit));
+        assert(a->type == atype_string);
         retval = get_field_len(val, field, &slen);
         if (retval)
             return retval;
@@ -495,22 +500,39 @@
         if (dataptr == NULL && slen != 0)
             return ASN1_MISSING_FIELD;
         assert(string->enclen != NULL);
-        retval = string->enclen(buf, slen, dataptr, &length);
+        retval = string->enclen(buf, slen, dataptr, &rettag->length);
         if (retval)
             return retval;
-        if (a->type == atype_string)
-            tagnum = string->tagval;
-        else
-            assert(omit_tag == NULL && !field->tag_implicit);
+        rettag->asn1class = UNIVERSAL;
+        rettag->construction = PRIMITIVE;
+        rettag->tagnum = string->tagval;
         break;
     }
-    case field_choice:
-    {
+    case field_der: {
         const void *dataptr = (const char *)val + field->dataoff;
+        const struct atype_info *a;
+        unsigned int slen;
+        const struct ptr_info *ptr;
+
+        a = field->atype;
+        assert(a->type == atype_der);
+        retval = get_field_len(val, field, &slen);
+        if (retval)
+            return retval;
+        ptr = a->tinfo;
+        dataptr = LOADPTR(dataptr, ptr);
+        if (dataptr == NULL && slen != 0)
+            return ASN1_MISSING_FIELD;
+        retval = split_der(buf, dataptr, slen, rettag);
+        if (retval)
+            return retval;
+        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);
@@ -518,8 +540,9 @@
             return retval;
         if (choice > seq->n_fields)
             return ASN1_MISSING_FIELD;
-        retval = encode_a_field(buf, dataptr, &seq->fields[choice], &length,
-                                NULL);
+        retval = encode_a_field(buf, dataptr, &seq->fields[choice], rettag);
+        if (retval)
+            return retval;
         break;
     }
     default:
@@ -529,31 +552,20 @@
         abort();
     }
 
-    sum += length;
-    if (tagnum >= 0 && omit_tag == NULL && !field->tag_implicit) {
-        /* We have not yet encoded the field's outer tag and should do so. */
-        retval = asn1_make_tag(buf, tagclass, construction, tagnum, sum,
-                               &length);
-        if (retval)
-            return retval;
-        sum += length;
-    } else if (omit_tag != NULL) {
-        /* Don't encode the tag; report its construction bit to the caller. */
-        *omit_tag = construction;
-    }
-
-    /* Maybe add a context tag.  Explicit tags are always constructed; implicit
-     * tags are primitive if the replaced outer tag would have been. */
     if (field->tag >= 0) {
-        if (!field->tag_implicit)
-            construction = CONSTRUCTED;
-        retval = asn1_make_tag(buf, CONTEXT_SPECIFIC, construction, field->tag,
-                               sum, &length);
-        if (retval)
-            return retval;
-        sum += length;
+        if (!field->tag_implicit) {
+            unsigned int tlen;
+            retval = asn1_make_tag(buf, rettag->asn1class,
+                                   rettag->construction, rettag->tagnum,
+                                   rettag->length, &tlen);
+            if (retval)
+                return retval;
+            rettag->length += tlen;
+            rettag->construction = CONSTRUCTED;
+        }
+        rettag->asn1class = CONTEXT_SPECIFIC;
+        rettag->tagnum = field->tag;
     }
-    *retlen = sum;
     return 0;
 }
 
@@ -567,21 +579,20 @@
     unsigned int sum = 0;
     for (i = nfields; i > 0; i--) {
         const struct field_info *f = fields+i-1;
-        unsigned int length;
+        taginfo t;
         asn1_error_code retval;
-        int present;
 
-        if (f->opt == -1)
-            present = 1;
-        else if ((1u << f->opt) & optional)
-            present = 1;
-        else
-            present = 0;
-        if (present) {
-            retval = encode_a_field(buf, val, f, &length, NULL);
-            if (retval) return retval;
-            sum += length;
-        }
+        if (f->opt != -1 && !((1u << f->opt) & optional))
+            continue;
+        retval = encode_a_field(buf, val, f, &t);
+        if (retval)
+            return retval;
+        sum += t.length;
+        retval = asn1_make_tag(buf, t.asn1class, t.construction, t.tagnum,
+                               t.length, &t.length);
+        if (retval)
+            return retval;
+        sum += t.length;
     }
     *retlen = sum;
     return 0;
@@ -615,7 +626,7 @@
 
         assert(eltinfo->size != 0);
         eltptr = (const char *)val + (i - 1) * eltinfo->size;
-        retval = encode_type(buf, eltptr, a, &length, NULL);
+        retval = encode_type_and_tag(buf, eltptr, a, &length);
         if (retval)
             return retval;
         sum += length;
@@ -624,13 +635,6 @@
     return 0;
 }
 
-asn1_error_code
-krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
-                            const struct atype_info *a, unsigned int *retlen)
-{
-    return encode_type(buf, val, a, retlen, NULL);
-}
-
 krb5_error_code
 krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
                             const struct atype_info *a)
@@ -649,7 +653,7 @@
     if (retval)
         return retval;
 
-    retval = encode_type(buf, rep, a, &length, NULL);
+    retval = encode_type_and_tag(buf, rep, a, &length);
     if (retval)
         goto cleanup;
     retval = asn12krb5_buf(buf, &d);

Modified: trunk/src/lib/krb5/asn.1/asn1_encode.h
===================================================================
--- trunk/src/lib/krb5/asn.1/asn1_encode.h	2012-01-07 20:57:36 UTC (rev 25621)
+++ trunk/src/lib/krb5/asn.1/asn1_encode.h	2012-01-08 02:10:47 UTC (rev 25622)
@@ -30,6 +30,7 @@
 #include "k5-int.h"
 #include "krbasn1.h"
 #include "asn1buf.h"
+#include "asn1_get.h"
 #include <time.h>
 
 /*
@@ -163,9 +164,11 @@
      * and wrapped with a universal primitive tag.  tinfo is a struct
      * primitive_info *. */
     atype_primitive,
-    /* Encoder function (with tag) to be called with address of <thing>.  tinfo
-     * is a struct primitive_info * with tagval ignored.  Cannot be used
-     * with an implicit tag. */
+    /*
+     * Encoder function to be called with address of <thing>.  The encoder
+     * function must generate a sequence without the sequence tag.  tinfo is a
+     * struct fn_info *.  Used only by kdc_req_body.
+     */
     atype_fn,
     /*
      * Encoder function (contents only) to be called with address of <thing>
@@ -175,10 +178,11 @@
      */
     atype_string,
     /*
-     * As above, but the encoder function produces the tag as well as the
-     * contents.  Cannot be used with an implicit context tag.
+     * Pre-made DER encoding stored at the address of <thing>.  tinfo is a
+     * struct ptr_info * with the basetype field ignored.  Only usable with the
+     * field_der field type.
      */
-    atype_opaque,
+    atype_der,
     /*
      * Pointer to actual thing to be encoded.  tinfo is a struct ptr_info *.
      *
@@ -209,8 +213,8 @@
     atype_nonempty_nullterm_sequence_of,
     /*
      * Encode this object using a single field descriptor.  tinfo is a struct
-     * field_info *.  Cannot be used with an implicit tag.  The presence of
-     * this type may mean the atype/field breakdown needs revision....
+     * field_info *.  The presence of this type may mean the atype/field
+     * breakdown needs revision....
      *
      * Main expected uses: Encode realm component of principal as a
      * GENERALSTRING.  Pluck data and length fields out of a structure
@@ -238,6 +242,10 @@
     unsigned int tagval;
 };
 
+struct fn_info {
+    asn1_error_code (*enc)(asn1buf *, const void *, taginfo *);
+};
+
 struct string_info {
     asn1_error_code (*enclen)(asn1buf *, unsigned int, const void *,
                               unsigned int *);
@@ -311,16 +319,8 @@
 /* Define a type using an explicit (with tag) encoder function. */
 #define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN)                           \
     typedef CTYPENAME aux_typedefname_##DESCNAME;                       \
-    static asn1_error_code                                              \
-    aux_encfn_##DESCNAME(asn1buf *buf, const void *val,                 \
-                         unsigned int *retlen)                          \
-    {                                                                   \
-        return ENCFN(buf,                                               \
-                     (const aux_typedefname_##DESCNAME *)val,           \
-                     retlen);                                           \
-    }                                                                   \
-    static const struct primitive_info aux_info_##DESCNAME = {          \
-        aux_encfn_##DESCNAME                                            \
+    static const struct fn_info aux_info_##DESCNAME = {                 \
+        ENCFN                                                           \
     };                                                                  \
     const struct atype_info krb5int_asn1type_##DESCNAME = {             \
         atype_fn, sizeof(CTYPENAME), &aux_info_##DESCNAME               \
@@ -364,18 +364,18 @@
     }
 #endif
 /* Not used enough to justify a POINTERS_ARE_ALL_THE_SAME version. */
-#define DEFOPAQUETYPE(DESCNAME, CTYPENAME, ENCFN)               \
+#define DEFDERTYPE(DESCNAME, CTYPENAME)                         \
     typedef CTYPENAME aux_typedefname_##DESCNAME;               \
     static const void *loadptr_for_##DESCNAME(const void *pv)   \
     {                                                           \
         const aux_typedefname_##DESCNAME *p = pv;               \
         return *p;                                              \
     }                                                           \
-    static const struct string_info aux_info_##DESCNAME = {     \
-        ENCFN, loadptr_for_##DESCNAME                           \
+    static const struct ptr_info aux_info_##DESCNAME = {        \
+        loadptr_for_##DESCNAME                                  \
     };                                                          \
     const struct atype_info krb5int_asn1type_##DESCNAME = {     \
-        atype_opaque, 0, &aux_info_##DESCNAME                   \
+        atype_der, 0, &aux_info_##DESCNAME                      \
     }
 /*
  * A sequence, defined by the indicated series of fields, and an
@@ -431,7 +431,7 @@
     typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \
     static const struct ptr_info aux_info_##DESCNAME = {                \
         NULL, &krb5int_asn1type_##BASEDESCNAME                          \
-    };
+    };                                                                  \
     const struct atype_info krb5int_asn1type_##DESCNAME = {             \
         atype_ptr, sizeof(aux_typedefname_##DESCNAME),                  \
         &aux_info_##DESCNAME                                            \
@@ -535,24 +535,11 @@
     typedef CTYPENAME aux_typedefname_##DESCNAME;               \
     extern const struct atype_info krb5int_asn1type_##DESCNAME
 
-/*
- * Create a partial-encoding function by the indicated name, for the
- * indicated type.  Should only be needed until we've converted all of
- * the encoders, then everything should use descriptor tables.
- */
-extern asn1_error_code
-krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
-                            const struct atype_info *a, unsigned int *retlen);
-#define MAKE_ENCFN(FNAME,DESC)                                          \
-    static asn1_error_code FNAME(asn1buf *buf,                          \
-                                 const aux_typedefname_##DESC *val,     \
-                                 unsigned int *retlen)                  \
-    {                                                                   \
-        return krb5int_asn1_encode_a_thing(buf, val,                    \
-                                           &krb5int_asn1type_##DESC,    \
-                                           retlen);                     \
-    }                                                                   \
-    extern int dummy /* gobble semicolon */
+/* Partially encode the contents of a type and return its tag information.
+ * Used only by asn1_encode_kdc_req_body. */
+asn1_error_code
+krb5int_asn1_encode_type(asn1buf *buf, const void *val,
+                         const struct atype_info *a, taginfo *rettag);
 
 /*
  * Sequence field descriptor.
@@ -583,6 +570,8 @@
      * string would be handled as field_normal.)
      */
     field_string,
+    /* Insert a DER encoding given by the pointer and length. */
+    field_der,
     /*
      * LENOFF indicates a value describing the length of the array at
      * DATAOFF, encoded as a sequence-of with the element type
@@ -616,7 +605,8 @@
      * compactly as an unsigned bitfield value tagnum+1, with 0=no
      * tag.)  The tag is omitted for optional fields that are not
      * present.  If tag_implicit is set, then the context tag replaces
-     * the outer tag of the field.
+     * the outer tag of the field, and uses the same construction bit
+     * as the outer tag would have used.
      *
      * It's a bit illogical to combine the tag and other field info,
      * since really a sequence field could have zero or several
@@ -721,6 +711,16 @@
 #define FIELD_INT_IMM(VALUE,TAG,IMPLICIT)                       \
     { field_immediate, VALUE, 0, TAG, IMPLICIT, -1, 0, }
 
+#define FIELDOF_OPTDER(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG,IMPLICIT,OPT) \
+    { field_der,                                                        \
+            OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC),             \
+            OFFOF(STYPE, LENFIELD, aux_typedefname_##LENTYPE),          \
+            TAG, IMPLICIT, OPT,                                         \
+            &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE       \
+    }
+#define FIELDOF_DER(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG,IMPLICIT)  \
+    FIELDOF_OPTDER(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG,IMPLICIT,-1)
+
 #define FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG,IMPLICIT) \
     {                                                                   \
         field_sequenceof_len,                                           \

Modified: trunk/src/lib/krb5/asn.1/asn1_k_encode.c
===================================================================
--- trunk/src/lib/krb5/asn.1/asn1_k_encode.c	2012-01-07 20:57:36 UTC (rev 25621)
+++ trunk/src/lib/krb5/asn.1/asn1_k_encode.c	2012-01-08 02:10:47 UTC (rev 25622)
@@ -42,7 +42,7 @@
               ASN1_GENERALSTRING);
 DEFSTRINGTYPE(u_generalstring, unsigned char *, asn1_encode_bytestring,
               ASN1_GENERALSTRING);
-DEFOPAQUETYPE(opaque, char *, asn1_encode_bytestring);
+DEFDERTYPE(der, char *);
 
 DEFFIELDTYPE(gstring_data, krb5_data,
              FIELDOF_STRING(krb5_data, generalstring, data, length, -1, 0));
@@ -52,8 +52,8 @@
              FIELDOF_STRING(krb5_data, s_octetstring, data, length, -1, 0));
 DEFPTRTYPE(ostring_data_ptr,ostring_data);
 
-DEFFIELDTYPE(opaque_data, krb5_data,
-             FIELDOF_STRING(krb5_data, opaque, data, length, -1, 0));
+DEFFIELDTYPE(der_data, krb5_data,
+             FIELDOF_DER(krb5_data, der, data, length, uint, -1, 0));
 
 DEFFIELDTYPE(realm_of_principal_data, krb5_principal_data,
              FIELDOF_NORM(krb5_principal_data, gstring_data, realm, -1, 0));
@@ -298,13 +298,9 @@
 DEFSEQTYPE(kdc_req_body_hack, struct kdc_req_hack, kdc_req_hack_fields,
            optional_kdc_req_hack);
 static asn1_error_code
-asn1_encode_kdc_req_hack(asn1buf *, const struct kdc_req_hack *,
-                         unsigned int *);
-MAKE_ENCFN(asn1_encode_kdc_req_hack, kdc_req_body_hack);
-static asn1_error_code
-asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *val,
-                         unsigned int *retlen)
+asn1_encode_kdc_req_body(asn1buf *buf, const void *ptr, taginfo *rettag)
 {
+    const krb5_kdc_req *val = ptr;
     struct kdc_req_hack val2;
     val2.v = *val;
     if (val->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
@@ -314,7 +310,9 @@
     } else if (val->server != NULL) {
         val2.server_realm = &val->server->realm;
     } else return ASN1_MISSING_FIELD;
-    return asn1_encode_kdc_req_hack(buf, &val2, retlen);
+    return krb5int_asn1_encode_type(buf, &val2,
+                                    &krb5int_asn1type_kdc_req_body_hack,
+                                    rettag);
 }
 DEFFNTYPE(kdc_req_body, krb5_kdc_req, asn1_encode_kdc_req_body);
 /* end ugly hack */
@@ -455,8 +453,7 @@
 DEFNULLTERMSEQOFTYPE(etype_info2, etype_info2_entry_ptr);
 
 static const struct field_info sam_challenge_2_fields[] = {
-    FIELDOF_NORM(krb5_sam_challenge_2, opaque_data, sam_challenge_2_body,
-                 0, 0),
+    FIELDOF_NORM(krb5_sam_challenge_2, der_data, sam_challenge_2_body, 0, 0),
     FIELDOF_NORM(krb5_sam_challenge_2, ptr_seqof_checksum, sam_cksum, 1, 0),
 };
 DEFSEQTYPE(sam_challenge_2, krb5_sam_challenge_2, sam_challenge_2_fields, 0);
@@ -790,7 +787,7 @@
 DEFSEQTYPE(untagged_krb5_safe, krb5_safe, krb5_safe_fields, 0);
 DEFAPPTAGGEDTYPE(krb5_safe, 20, untagged_krb5_safe);
 
-DEFPTRTYPE(krb_saved_safe_body_ptr, opaque_data);
+DEFPTRTYPE(krb_saved_safe_body_ptr, der_data);
 DEFFIELDTYPE(krb5_safe_checksum_only, krb5_safe,
              FIELDOF_NORM(krb5_safe, checksum_ptr, checksum, -1, 0));
 DEFPTRTYPE(krb5_safe_checksum_only_ptr, krb5_safe_checksum_only);
@@ -1307,7 +1304,7 @@
 
 static const struct field_info algorithm_identifier_fields[] = {
     FIELDOF_NORM(krb5_algorithm_identifier, oid_data, algorithm, -1, 0),
-    FIELDOF_OPT(krb5_algorithm_identifier, opaque_data, parameters, -1, 0, 1),
+    FIELDOF_OPT(krb5_algorithm_identifier, der_data, parameters, -1, 0, 1),
 };
 DEFSEQTYPE(algorithm_identifier, krb5_algorithm_identifier,
            algorithm_identifier_fields, algorithm_identifier_optional);



More information about the cvs-krb5 mailing list