Use content-only ASN.1 primitives
authorGreg Hudson <ghudson@mit.edu>
Fri, 6 Jan 2012 20:52:12 +0000 (20:52 +0000)
committerGreg Hudson <ghudson@mit.edu>
Fri, 6 Jan 2012 20:52:12 +0000 (20:52 +0000)
As part of implicit tag support, rework ASN.1 encoding primitives so
that they encode only content, not tags.  Combine primitives which
become identical with this change.  The new atype_primitive type
invokes a primitive encoder and adds a tag.  atype_fn_len is split
into atype_string and atype_opaque, both of which are hardcoded to
use asn1_encode_bytestring.

For the encoders still using macros, create asn1_addprimitive,
asn1_addinteger, and asn1_addstring macros which call the primitive
encoder function and add a tag.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25612 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/asn.1/asn1_encode.c
src/lib/krb5/asn.1/asn1_encode.h
src/lib/krb5/asn.1/asn1_k_encode.c

index 5ecd82f5948d32f0b0ed5735519e462619ba8a1f..f222423e9c77e5c816ecc4212cea8d497f2fa576 100644 (file)
 asn1_error_code
 asn1_encode_boolean(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
 {
-    asn1_error_code retval;
-    unsigned int length = 0;
-    unsigned int partlen = 1;
-    asn1_octet bval;
-
-    bval = val ? 0xFF : 0x00;
-
-    retval = asn1buf_insert_octet(buf, bval);
-    if (retval) return retval;
-
-    length = partlen;
-    retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_BOOLEAN, length, &partlen);
-    if (retval) return retval;
-    length += partlen;
+    asn1_octet bval = val ? 0xFF : 0x00;
 
-    *retlen = length;
-    return 0;
+    *retlen = 1;
+    return asn1buf_insert_octet(buf, bval);
 }
 
-static asn1_error_code
-asn1_encode_integer_internal(asn1buf *buf, asn1_intmax val,
-                             unsigned int *retlen)
+asn1_error_code
+asn1_encode_integer(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
 {
     asn1_error_code retval;
     unsigned int length = 0;
@@ -84,52 +70,12 @@ asn1_encode_integer_internal(asn1buf *buf, asn1_intmax val,
     return 0;
 }
 
-asn1_error_code
-asn1_encode_integer(asn1buf * buf, asn1_intmax val, unsigned int *retlen)
-{
-    asn1_error_code retval;
-    unsigned int length = 0;
-    unsigned  int partlen;
-    retval = asn1_encode_integer_internal(buf, val, &partlen);
-    if (retval) return retval;
-
-    length = partlen;
-    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
-    if (retval) return retval;
-    length += partlen;
-
-    *retlen = length;
-    return 0;
-}
-
-#if 0
-asn1_error_code
-asn1_encode_enumerated(asn1buf * buf, long val,
-                       unsigned int *retlen)
-{
-    asn1_error_code retval;
-    unsigned int length = 0;
-    unsigned  int partlen;
-    retval = asn1_encode_integer_internal(buf, val, &partlen);
-    if (retval) return retval;
-
-    length = partlen;
-    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen);
-    if (retval) return retval;
-    length += partlen;
-
-    *retlen = length;
-    return 0;
-}
-#endif
-
 asn1_error_code
 asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
                              unsigned int *retlen)
 {
     asn1_error_code retval;
     unsigned int length = 0;
-    unsigned int partlen;
     unsigned long valcopy;
     int digit;
 
@@ -148,77 +94,18 @@ asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
         length++;
     }
 
-    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
-    if (retval) return retval;
-    length += partlen;
-
     *retlen = length;
     return 0;
 }
 
-static asn1_error_code
-encode_bytestring_with_tag(asn1buf *buf, unsigned int len,
-                           const void *val, int tag,
-                           unsigned int *retlen)
-{
-    asn1_error_code retval;
-    unsigned int length;
-
-    if (len > 0 && val == 0) return ASN1_MISSING_FIELD;
-    retval = asn1buf_insert_octetstring(buf, len, val);
-    if (retval) return retval;
-    retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, tag,
-                           len, &length);
-    if (retval) return retval;
-
-    *retlen = len + length;
-    return 0;
-}
-
 asn1_error_code
-asn1_encode_oid(asn1buf *buf, unsigned int len, const void *val,
-                unsigned int *retlen)
-{
-    return encode_bytestring_with_tag(buf, len, val, ASN1_OBJECTIDENTIFIER,
-                                      retlen);
-}
-
-asn1_error_code
-asn1_encode_octetstring(asn1buf *buf, unsigned int len, const void *val,
-                        unsigned int *retlen)
-{
-    return encode_bytestring_with_tag(buf, len, val, ASN1_OCTETSTRING,
-                                      retlen);
-}
-
-#if 0
-asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen)
-{
-    asn1_error_code retval;
-
-    retval = asn1buf_insert_octet(buf,0x00);
-    if (retval) return retval;
-    retval = asn1buf_insert_octet(buf,0x05);
-    if (retval) return retval;
-
-    *retlen = 2;
-    return 0;
-}
-
-asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
-                                            const char *val, int *retlen)
-{
-    return encode_bytestring_with_tag(buf, len, val, ASN1_PRINTABLESTRING,
-                                      retlen);
-}
-
-asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
-                                      const char *val, int *retlen)
+asn1_encode_bytestring(asn1buf *buf, unsigned int len, const void *val,
+                       unsigned int *retlen)
 {
-    return encode_bytestring_with_tag(buf, len, val, ASN1_IA5STRING,
-                                      retlen);
+    if (len > 0 && val == NULL) return ASN1_MISSING_FIELD;
+    *retlen = len;
+    return asn1buf_insert_octetstring(buf, len, val);
 }
-#endif
 
 asn1_error_code
 asn1_encode_generaltime(asn1buf *buf, time_t val, unsigned int *retlen)
@@ -269,16 +156,7 @@ asn1_encode_generaltime(asn1buf *buf, time_t val, unsigned int *retlen)
         sp = s;
     }
 
-    return encode_bytestring_with_tag(buf, 15, sp, ASN1_GENERALTIME,
-                                      retlen);
-}
-
-asn1_error_code
-asn1_encode_generalstring(asn1buf *buf, unsigned int len, const void *val,
-                          unsigned int *retlen)
-{
-    return encode_bytestring_with_tag(buf, len, val, ASN1_GENERALSTRING,
-                                      retlen);
+    return asn1_encode_bytestring(buf, 15, sp, retlen);
 }
 
 asn1_error_code
@@ -286,29 +164,11 @@ asn1_encode_bitstring(asn1buf *buf, unsigned int len, const void *val,
                       unsigned int *retlen)
 {
     asn1_error_code retval;
-    unsigned int length;
 
     retval = asn1buf_insert_octetstring(buf, len, val);
     if (retval) return retval;
-    retval = asn1buf_insert_octet(buf, 0);
-    if (retval) return retval;
-    retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_BITSTRING,
-                           len+1, &length);
-    if (retval) return retval;
-    *retlen = len + 1 + length;
-    return 0;
-}
-
-asn1_error_code
-asn1_encode_opaque(asn1buf *buf, unsigned int len, const void *val,
-                   unsigned int *retlen)
-{
-    asn1_error_code retval;
-
-    retval = asn1buf_insert_octetstring(buf, len, val);
-    if (retval) return retval;
-    *retlen = len;
-    return 0;
+    *retlen = len + 1;
+    return asn1buf_insert_octet(buf, '\0');
 }
 
 /*
@@ -383,12 +243,26 @@ asn1_error_code
 krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
                             const struct atype_info *a, unsigned int *retlen)
 {
+    asn1_error_code retval;
+    unsigned int length, sum = 0;
+
     switch (a->type) {
+    case atype_primitive:
     case atype_fn:
     {
-        const struct fn_info *fn = a->tinfo;
-        assert(fn->enc != NULL);
-        return fn->enc(buf, val, retlen);
+        const struct primitive_info *prim = a->tinfo;
+        assert(prim->enc != NULL);
+        retval = prim->enc(buf, val, &length);
+        if (retval) return retval;
+        sum += length;
+        if (a->type == atype_primitive) {
+            retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, prim->tagval,
+                                   sum, &length);
+            if (retval) return retval;
+            sum += length;
+        }
+        *retlen = sum;
+        return 0;
     }
     case atype_sequence:
         assert(a->tinfo != NULL);
@@ -411,8 +285,6 @@ krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
                                            retlen);
     case atype_tagged_thing:
     {
-        asn1_error_code retval;
-        unsigned int length, sum = 0;
         const struct tagged_info *tag = a->tinfo;
         retval = krb5int_asn1_encode_a_thing(buf, val, tag->basetype, &length);
         if (retval) return retval;
@@ -428,21 +300,40 @@ krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
     {
         const struct int_info *tinfo = a->tinfo;
         assert(tinfo->loadint != NULL);
-        return asn1_encode_integer(buf, tinfo->loadint(val), retlen);
+        retval = asn1_encode_integer(buf, tinfo->loadint(val), &length);
+        if (retval) return retval;
+        sum = length;
+        retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_INTEGER, sum,
+                               &length);
+        if (retval) return retval;
+        sum += length;
+        *retlen = sum;
+        return 0;
     }
     case atype_uint:
     {
         const struct uint_info *tinfo = a->tinfo;
         assert(tinfo->loaduint != NULL);
-        return asn1_encode_unsigned_integer(buf, tinfo->loaduint(val), retlen);
+        retval = asn1_encode_unsigned_integer(buf, tinfo->loaduint(val),
+                                              &length);
+        if (retval) return retval;
+        sum = length;
+        retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_INTEGER, sum,
+                               &length);
+        if (retval) return retval;
+        sum += length;
+        *retlen = sum;
+        return 0;
     }
     case atype_min:
     case atype_max:
-    case atype_fn_len:
+    case atype_string:          /* only usable with field_string */
+    case atype_opaque:          /* only usable with field_string */
     default:
         assert(a->type > atype_min);
         assert(a->type < atype_max);
-        assert(a->type != atype_fn_len);
+        assert(a->type != atype_string);
+        assert(a->type != atype_opaque);
         abort();
     }
 }
@@ -466,6 +357,10 @@ encode_a_field(asn1buf *buf, const void *val,
                                      &length);
         if (retval) return retval;
         sum += length;
+        retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_INTEGER, sum,
+                               &length);
+        if (retval) return retval;
+        sum += length;
         break;
     }
     case field_sequenceof_len:
@@ -536,13 +431,13 @@ encode_a_field(asn1buf *buf, const void *val,
         const struct atype_info *a;
         size_t slen;
         unsigned int length;
-        const struct fn_len_info *fnlen;
+        const struct string_info *string;
 
         dataptr = (const char *)val + field->dataoff;
         lenptr = (const char *)val + field->lenoff;
 
         a = field->atype;
-        assert(a->type == atype_fn_len);
+        assert(a->type == atype_string || a->type == atype_opaque);
         assert(field->lentype != 0);
         assert(field->lentype->type == atype_int || field->lentype->type == atype_uint);
         assert(sizeof(int) <= sizeof(asn1_intmax));
@@ -563,25 +458,28 @@ encode_a_field(asn1buf *buf, const void *val,
             slen = (size_t) xlen;
         }
 
-        fnlen = a->tinfo;
-        dataptr = LOADPTR(dataptr, fnlen);
+        string = a->tinfo;
+        dataptr = LOADPTR(dataptr, string);
         if (slen == SIZE_MAX)
             /* Error - negative or out of size_t range.  */
             return EINVAL;
         if (dataptr == NULL && slen != 0)
             return ASN1_MISSING_FIELD;
-        /*
-         * Currently our string encoders want "unsigned int" for
-         * lengths.
-         */
-        if (slen != (unsigned int) slen)
+        /* Currently string encoders want "unsigned int" for length. */
+        if (slen != (unsigned int)slen)
             return EINVAL;
-        assert(fnlen->enclen != NULL);
-        retval = fnlen->enclen(buf, (unsigned int) slen, dataptr, &length);
-        if (retval) {
+        assert(string->enclen != NULL);
+        retval = string->enclen(buf, (unsigned int) slen, dataptr, &length);
+        if (retval)
             return retval;
-        }
         sum += length;
+        if (a->type == atype_string) {
+            retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, string->tagval,
+                                   sum, &length);
+            if (retval)
+                return retval;
+            sum += length;
+        }
         break;
     }
     default:
index 8a7c9f073c4f9c05c5b36d73bdfe9df91ef69b32..ed2eb18e9d5a86231fd82f138938ca09c014399d 100644 (file)
  *   asn1_encode_boolean
  *   asn1_encode_integer
  *   asn1_encode_unsigned_integer
- *   asn1_encode_octetstring
+ *   asn1_encode_bytestring
  *   asn1_encode_generaltime
- *   asn1_encode_generalstring
  *   asn1_encode_bitstring
- *   asn1_encode_oid
  */
 
 asn1_error_code asn1_encode_boolean(asn1buf *buf, asn1_intmax val,
@@ -63,9 +61,6 @@ asn1_error_code asn1_encode_integer(asn1buf *buf, asn1_intmax val,
  *            to expand the buffer.
  */
 
-asn1_error_code asn1_encode_enumerated(asn1buf *buf, long val,
-                                       unsigned int *retlen);
-
 asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
                                              unsigned int *retlen);
 /*
@@ -77,24 +72,8 @@ asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
  *            to expand the buffer.
  */
 
-asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len,
-                                        const void *val, unsigned int *retlen);
-/*
- * requires  *buf is allocated
- * modifies  *buf, *retlen
- * effects   Inserts the encoding of val into *buf and returns
- *            the length of the encoding in *retlen.
- *           Returns ENOMEM to signal an unsuccesful attempt
- *            to expand the buffer.
- */
-#define asn1_encode_charstring asn1_encode_octetstring
-
-/**
- * Encode @a val, an object identifier in compressed DER form without a tag or
- * length. This function adds the OID tag and length.
- */
-asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len,
-                                const void *val, unsigned int *retlen);
+asn1_error_code asn1_encode_bytestring(asn1buf *buf, unsigned int len,
+                                       const void *val, unsigned int *retlen);
 /*
  * requires  *buf is allocated
  * modifies  *buf, *retlen
@@ -114,28 +93,6 @@ asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen);
  *            to expand the buffer.
  */
 
-asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
-                                            const char *val, int *retlen);
-/*
- * requires  *buf is allocated
- * modifies  *buf, *retlen
- * effects   Inserts the encoding of val into *buf and returns
- *            the length of the encoding in *retlen.
- *           Returns ENOMEM to signal an unsuccesful attempt
- *            to expand the buffer.
- */
-
-asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
-                                      const char *val, int *retlen);
-/*
- * requires  *buf is allocated
- * modifies  *buf, *retlen
- * effects   Inserts the encoding of val into *buf and returns
- *            the length of the encoding in *retlen.
- *           Returns ENOMEM to signal an unsuccesful attempt
- *            to expand the buffer.
- */
-
 asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
                                         unsigned int *retlen);
 /*
@@ -148,18 +105,6 @@ asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
  * Note: The encoding of GeneralizedTime is YYYYMMDDhhmmZ
  */
 
-asn1_error_code asn1_encode_generalstring(asn1buf *buf,
-                                          unsigned int len, const void *val,
-                                          unsigned int *retlen);
-/*
- * requires  *buf is allocated,  val has a length of len characters
- * modifies  *buf, *retlen
- * effects   Inserts the encoding of val into *buf and returns
- *            the length of the encoding in *retlen.
- *           Returns ENOMEM to signal an unsuccesful attempt
- *            to expand the buffer.
- */
-
 asn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len,
                                       const void *val,
                                       unsigned int *retlen);
@@ -172,18 +117,6 @@ asn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len,
  *            to expand the buffer.
  */
 
-asn1_error_code asn1_encode_opaque(asn1buf *buf, unsigned int len,
-                                   const void *val,
-                                   unsigned int *retlen);
-/*
- * requires  *buf is allocated,  val has a length of len characters
- * modifies  *buf, *retlen
- * effects   Inserts the encoding of val into *buf and returns
- *            the length of the encoding in *retlen.
- *           Returns ENOMEM to signal an unsuccesful attempt
- *            to expand the buffer.
- */
-
 /*
  * Type descriptor info.
  *
@@ -226,14 +159,25 @@ enum atype_type {
      * invalid.
      */
     atype_min = 1,
-    /* Encoder function to be called with address of <thing>.  tinfo is a
-     * struct fn_info *. */
+    /* Encoder function (contents-only) to be called with address of <thing>
+     * 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. */
     atype_fn,
     /*
-     * Encoder function to be called with address of <thing> and a
-     * length (unsigned int).  tinfo is a struct fn_len_info *.
+     * Encoder function (contents only) to be called with address of <thing>
+     * and a length (unsigned int), and wrapped with a universal primitive tag.
+     * tinfo is a struct string_info *.  Only usable with the field_string
+     * field type.
      */
-    atype_fn_len,
+    atype_string,
+    /*
+     * As above, but the encoder function produces the tag as well as the
+     * contents.
+     */
+    atype_opaque,
     /*
      * Pointer to actual thing to be encoded.  tinfo is a struct ptr_info *.
      *
@@ -282,14 +226,16 @@ struct atype_info {
     const void *tinfo;          /* Points to type-specific structure */
 };
 
-struct fn_info {
+struct primitive_info {
     asn1_error_code (*enc)(asn1buf *, const void *, unsigned int *);
+    unsigned int tagval;
 };
 
-struct fn_len_info {
+struct string_info {
     asn1_error_code (*enclen)(asn1buf *, unsigned int, const void *,
                               unsigned int *);
     const void *(*loadptr)(const void *);
+    unsigned int tagval;
 };
 
 struct ptr_info {
@@ -331,26 +277,32 @@ struct uint_info {
  */
 
 /*
- * Define a type for which we must use an explicit encoder function.
- * The DEFFNTYPE variant uses a function taking a void*, the
- * DEFFNXTYPE form wants a function taking a pointer to the actual C
- * type to be encoded; you should use the latter unless you've already
- * got the void* function supplied elsewhere.
+ * Define a type using a primitive (content-only) encoder function.
  *
- * Of course, we need a single, consistent type for the descriptor
- * structure field, so we use the function pointer type that uses
- * void*, and create a wrapper function in DEFFNXTYPE.  However, in
- * all our cases so far, the supplied function is static and not used
- * otherwise, so the compiler can merge it with the wrapper function
- * if the optimizer is good enough.
+ * Because we need a single, consistent type for the descriptor structure
+ * field, we use the function pointer type that uses void*, and create a
+ * wrapper function in DEFFNXTYPE.  The supplied function is static and not
+ * used otherwise, so the compiler can merge it with the wrapper function if
+ * the optimizer is good enough.
  */
-#define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN)                           \
+#define DEFPRIMITIVETYPE(DESCNAME, CTYPENAME, ENCFN, TAG)               \
     typedef CTYPENAME aux_typedefname_##DESCNAME;                       \
-    static const struct fn_info aux_info_##DESCNAME = { ENCFN };        \
+    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, TAG                                       \
+    };                                                                  \
     const struct atype_info krb5int_asn1type_##DESCNAME = {             \
-        atype_fn, sizeof(CTYPENAME), &aux_info_##DESCNAME               \
+        atype_primitive, sizeof(CTYPENAME), &aux_info_##DESCNAME        \
     }
-#define DEFFNXTYPE(DESCNAME, CTYPENAME, ENCFN)                          \
+/* 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,                 \
@@ -360,7 +312,7 @@ struct uint_info {
                      (const aux_typedefname_##DESCNAME *)val,           \
                      retlen);                                           \
     }                                                                   \
-    static const struct fn_info aux_info_##DESCNAME = {                 \
+    static const struct primitive_info aux_info_##DESCNAME = {          \
         aux_encfn_##DESCNAME                                            \
     };                                                                  \
     const struct atype_info krb5int_asn1type_##DESCNAME = {             \
@@ -381,29 +333,43 @@ struct uint_info {
  * string-encoding primitives work.  So be it.
  */
 #ifdef POINTERS_ARE_ALL_THE_SAME
-#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN)                \
+#define DEFSTRINGTYPE(DESCNAME, CTYPENAME, ENCFN, TAGVAL)       \
     typedef CTYPENAME aux_typedefname_##DESCNAME;               \
-    static const struct fn_len_info aux_info_##DESCNAME = {     \
-        ENCFN, NULL                                             \
+    static const struct string_info aux_info_##DESCNAME = {     \
+        ENCFN, NULL, TAGVAL                                     \
     }                                                           \
     const struct atype_info krb5int_asn1type_##DESCNAME = {     \
-        atype_fn_len, 0, &aux_info_##DESCNAME                   \
+        atype_string, 0, &aux_info_##DESCNAME                   \
     }
 #else
-#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN)                \
+#define DEFSTRINGTYPE(DESCNAME, CTYPENAME, ENCFN, TAGVAL)       \
     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 fn_len_info aux_info_##DESCNAME = {     \
-        ENCFN, loadptr_for_##DESCNAME                           \
+    static const struct string_info aux_info_##DESCNAME = {     \
+        ENCFN, loadptr_for_##DESCNAME, TAGVAL                   \
     };                                                          \
     const struct atype_info krb5int_asn1type_##DESCNAME = {     \
-        atype_fn_len, 0, &aux_info_##DESCNAME                   \
+        atype_string, 0, &aux_info_##DESCNAME                   \
     }
 #endif
+/* Not used enough to justify a POINTERS_ARE_ALL_THE_SAME version. */
+#define DEFOPAQUETYPE(DESCNAME, CTYPENAME, ENCFN)               \
+    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                           \
+    };                                                          \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {     \
+        atype_opaque, 0, &aux_info_##DESCNAME                   \
+    }
 /*
  * A sequence, defined by the indicated series of fields, and an
  * optional function indicating which fields are present.
index 8aecfdf564aa051edc8be3c613727913ae20b783..56b98022b2bd105c74df07a0f5a61f54192680ca 100644 (file)
@@ -78,12 +78,14 @@ DEFUINTTYPE(uint, unsigned int);
 DEFUINTTYPE(octet, krb5_octet);
 DEFUINTTYPE(ui_4, krb5_ui_4);
 
-DEFFNLENTYPE(octetstring, unsigned char *, asn1_encode_octetstring);
-DEFFNLENTYPE(s_octetstring, char *, asn1_encode_octetstring);
-DEFFNLENTYPE(charstring, char *, asn1_encode_charstring);
-DEFFNLENTYPE(generalstring, char *, asn1_encode_generalstring);
-DEFFNLENTYPE(u_generalstring, unsigned char *, asn1_encode_generalstring);
-DEFFNLENTYPE(opaque, char *, asn1_encode_opaque);
+DEFSTRINGTYPE(octetstring, unsigned char *, asn1_encode_bytestring,
+              ASN1_OCTETSTRING);
+DEFSTRINGTYPE(s_octetstring, char *, asn1_encode_bytestring, ASN1_OCTETSTRING);
+DEFSTRINGTYPE(generalstring, char *, asn1_encode_bytestring,
+              ASN1_GENERALSTRING);
+DEFSTRINGTYPE(u_generalstring, unsigned char *, asn1_encode_bytestring,
+              ASN1_GENERALSTRING);
+DEFOPAQUETYPE(opaque, char *, asn1_encode_bytestring);
 
 DEFFIELDTYPE(gstring_data, krb5_data,
              FIELDOF_STRING(krb5_data, generalstring, data, length, -1));
@@ -119,7 +121,8 @@ asn1_encode_kerberos_time_at(asn1buf *buf, const krb5_timestamp *val,
     time_t tval = *val;
     return asn1_encode_generaltime(buf, tval, retlen);
 }
-DEFFNXTYPE(kerberos_time, krb5_timestamp, asn1_encode_kerberos_time_at);
+DEFPRIMITIVETYPE(kerberos_time, krb5_timestamp, asn1_encode_kerberos_time_at,
+                 ASN1_GENERALTIME);
 
 const static struct field_info address_fields[] = {
     FIELDOF_NORM(krb5_address, int32, addrtype, 0),
@@ -164,7 +167,8 @@ asn1_encode_krb5_flags_at(asn1buf *buf, const krb5_flags *val,
     store_32_be((krb5_ui_4) *val, cbuf);
     return asn1_encode_bitstring(buf, 4, cbuf, retlen);
 }
-DEFFNXTYPE(krb5_flags, krb5_flags, asn1_encode_krb5_flags_at);
+DEFPRIMITIVETYPE(krb5_flags, krb5_flags, asn1_encode_krb5_flags_at,
+                 ASN1_BITSTRING);
 
 const static struct field_info authdata_elt_fields[] = {
     /* ad-type[0]               INTEGER */
@@ -347,7 +351,7 @@ asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *val,
     } else return ASN1_MISSING_FIELD;
     return asn1_encode_kdc_req_hack(buf, &val2, retlen);
 }
-DEFFNXTYPE(kdc_req_body, krb5_kdc_req, asn1_encode_kdc_req_body);
+DEFFNTYPE(kdc_req_body, krb5_kdc_req, asn1_encode_kdc_req_body);
 /* end ugly hack */
 
 DEFPTRTYPE(ptr_kdc_req_body,kdc_req_body);
@@ -562,7 +566,7 @@ asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val,
     asn1_makeseq();
     asn1_cleanup();
 }
-DEFFNXTYPE(sam_challenge_2, krb5_sam_challenge_2, asn1_encode_sam_challenge_2);
+DEFFNTYPE(sam_challenge_2, krb5_sam_challenge_2, asn1_encode_sam_challenge_2);
 
 static const struct field_info sam_challenge_2_body_fields[] = {
     FIELDOF_NORM(krb5_sam_challenge_2_body, int32, sam_type, 0),
@@ -1553,19 +1557,46 @@ asn1_error_code asn1_encode_krb5_substructure(asn1buf *buf,
 }
 #endif
 
-/* asn1_addlenfield -- add a field whose length must be separately specified */
-#define asn1_addlenfield(len, value, tag, encoder)      \
-    {                                                   \
-        unsigned int length;                            \
-        retval = encoder(buf, len, value, &length);     \
-        if (retval) {                                   \
-            return retval; }                            \
-        sum += length;                                  \
-        retval = asn1_make_etag(buf, CONTEXT_SPECIFIC,  \
-                                tag, length, &length);  \
-        if (retval) {                                   \
-            return retval; }                            \
-        sum += length;                                  \
+/*
+ * asn1_addprimitive -- add a primitive field and universal primitive tag to
+ * the encoding, wrapped in a context tag.  encoder must encode only the
+ * contents, not the tag.
+ */
+#define asn1_addprimitive(value,tag,encoder,ptag)                       \
+    { unsigned int enclen, tlen;                                        \
+        retval = encoder(buf, value, &enclen);                          \
+        if (retval) {                                                   \
+            return retval; }                                            \
+        retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ptag,         \
+                               enclen, &tlen);                          \
+        sum += enclen + tlen;                                           \
+        retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, tag,             \
+                                enclen + tlen, &tlen);                  \
+        if (retval) {                                                   \
+            return retval; }                                            \
+        sum += tlen; }
+
+#define asn1_addinteger(value, tag) \
+    asn1_addprimitive(value, tag, asn1_encode_integer, ASN1_INTEGER)
+
+/* asn1_addstring -- add a string field whose length must be separately
+ * specified, wrapped in a universal primitive tag. */
+#define asn1_addstring(len, value, tag, ptag)                           \
+    {                                                                   \
+        unsigned int enclen, tlen;                                      \
+        retval = asn1_encode_bytestring(buf, len, value, &enclen);      \
+        if (retval) {                                                   \
+            return retval; }                                            \
+        retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ptag,         \
+                               enclen, &tlen);                          \
+        if (retval) {                                                   \
+            return retval; }                                            \
+        sum += enclen + tlen;                                           \
+        retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, tag,             \
+                                enclen + tlen, &tlen);                  \
+        if (retval) {                                                   \
+            return retval; }                                            \
+        sum += tlen;                                                    \
     }
 
 /*
@@ -1621,8 +1652,9 @@ asn1_error_code asn1_encode_krb5_substructure(asn1buf *buf,
 
 #ifndef DISABLE_PKINIT
 
-DEFFNXTYPE(algorithm_identifier, krb5_algorithm_identifier, asn1_encode_algorithm_identifier);
-DEFFNLENTYPE(object_identifier, char *, asn1_encode_oid);
+DEFFNTYPE(algorithm_identifier, krb5_algorithm_identifier, asn1_encode_algorithm_identifier);
+DEFSTRINGTYPE(object_identifier, char *, asn1_encode_bytestring,
+              ASN1_OBJECTIDENTIFIER);
 DEFFIELDTYPE(oid_data, krb5_data,
              FIELDOF_STRING(krb5_data, object_identifier, data, length, -1));
 DEFPTRTYPE(oid_data_ptr, oid_data);
@@ -1664,8 +1696,10 @@ DEFSEQTYPE(sp80056a_other_info, krb5_sp80056a_other_info, sp80056a_other_info_fi
 /* For PkinitSuppPubInfo, for pkinit agility */
 static const struct field_info pkinit_supp_pub_info_fields[] = {
     FIELDOF_NORM(krb5_pkinit_supp_pub_info, int32, enctype, 0),
-    FIELDOF_STRING(krb5_pkinit_supp_pub_info, charstring, as_req.data, as_req.length, 1),
-    FIELDOF_STRING(krb5_pkinit_supp_pub_info, charstring, pk_as_rep.data, pk_as_rep.length, 2),
+    FIELDOF_STRING(krb5_pkinit_supp_pub_info, s_octetstring, as_req.data,
+                   as_req.length, 1),
+    FIELDOF_STRING(krb5_pkinit_supp_pub_info, s_octetstring, pk_as_rep.data,
+                   pk_as_rep.length, 2),
 };
 
 DEFSEQTYPE(pkinit_supp_pub_info, krb5_pkinit_supp_pub_info, pkinit_supp_pub_info_fields, NULL);
@@ -1693,10 +1727,12 @@ asn1_encode_pk_authenticator(asn1buf *buf, const krb5_pk_authenticator *val,
                              unsigned int *retlen)
 {
     asn1_setup();
-    asn1_addlenfield(val->paChecksum.length, val->paChecksum.contents, 3, asn1_encode_octetstring);
-    asn1_addfield(val->nonce, 2, asn1_encode_integer);
-    asn1_addfield(val->ctime, 1, asn1_encode_kerberos_time);
-    asn1_addfield(val->cusec, 0, asn1_encode_integer);
+    asn1_addstring(val->paChecksum.length, val->paChecksum.contents, 3,
+                   ASN1_OCTETSTRING);
+    asn1_addinteger(val->nonce, 2);
+    asn1_addprimitive(val->ctime, 1, asn1_encode_kerberos_time,
+                      ASN1_GENERALTIME);
+    asn1_addinteger(val->cusec, 0);
 
     asn1_makeseq();
     asn1_cleanup();
@@ -1709,9 +1745,10 @@ asn1_encode_pk_authenticator_draft9(asn1buf *buf,
 {
     asn1_setup();
 
-    asn1_addfield(val->nonce, 4, asn1_encode_integer);
-    asn1_addfield(val->ctime, 3, asn1_encode_kerberos_time);
-    asn1_addfield(val->cusec, 2, asn1_encode_integer);
+    asn1_addinteger(val->nonce, 4);
+    asn1_addprimitive(val->ctime, 3, asn1_encode_kerberos_time,
+                      ASN1_GENERALTIME);
+    asn1_addinteger(val->cusec, 2);
     asn1_addfield(val->kdcName, 1, asn1_encode_realm);
     asn1_addfield(val->kdcName, 0, asn1_encode_principal_name);
 
@@ -1737,13 +1774,17 @@ asn1_encode_algorithm_identifier(asn1buf *buf,
 
     {
         unsigned int length;
-        retval = asn1_encode_oid(buf, val->algorithm.length,
-                                 val->algorithm.data,
-                                 &length);
+        retval = asn1_encode_bytestring(buf, val->algorithm.length,
+                                        val->algorithm.data, &length);
 
         if (retval)
             return retval;
         sum += length;
+        retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE,
+                               ASN1_OBJECTIDENTIFIER, length, &length);
+        if (retval)
+            return retval;
+        sum += length;
     }
 
     asn1_makeseq();
@@ -1755,9 +1796,11 @@ asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_info *val,
                             unsigned int *retlen)
 {
     asn1_setup();
+    unsigned int len, alen = 0;
 
     {
         unsigned int length;
+
         asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,ASN1_BITSTRING);
     }
 
@@ -1766,29 +1809,25 @@ asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_info *val,
                                             val->algorithm.parameters.data);
         if (retval)
             return retval;
-        sum += val->algorithm.parameters.length;
+        alen += val->algorithm.parameters.length;
     }
 
-    {
-        unsigned int length;
-
-        retval = asn1_encode_oid(buf, val->algorithm.algorithm.length,
-                                 val->algorithm.algorithm.data,
-                                 &length);
-
-        if (retval)
-            return retval;
-        sum += length;
-
+    retval = asn1_encode_bytestring(buf, val->algorithm.algorithm.length,
+                                    val->algorithm.algorithm.data, &len);
+    if (retval)
+        return retval;
+    alen += len;
 
-        retval = asn1_make_etag(buf, UNIVERSAL, ASN1_SEQUENCE,
-                                val->algorithm.parameters.length + length,
-                                &length);
+    retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE,
+                           ASN1_OBJECTIDENTIFIER, len, &len);
+    if (retval)
+        return retval;
+    alen += len;
 
-        if (retval)
-            return retval;
-        sum += length;
-    }
+    retval = asn1_make_etag(buf, UNIVERSAL, ASN1_SEQUENCE, alen, &len);
+    if (retval)
+        return retval;
+    sum += alen + len;
 
     asn1_makeseq();
     asn1_cleanup();
@@ -1825,7 +1864,8 @@ asn1_encode_auth_pack(asn1buf *buf, const krb5_auth_pack *val,
     if (val->supportedKDFs != NULL)
         asn1_addfield(val->supportedKDFs, 4, asn1_encode_supported_kdfs);
     if (val->clientDHNonce.length != 0)
-        asn1_addlenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_encode_octetstring);
+        asn1_addstring(val->clientDHNonce.length, val->clientDHNonce.data, 3,
+                       ASN1_OCTETSTRING);
     if (val->supportedCMSTypes != NULL)
         asn1_addfield((const krb5_algorithm_identifier **)val->supportedCMSTypes,2,asn1_encode_sequence_of_algorithm_identifier);
     if (val->clientPublicValue != NULL)
@@ -2003,9 +2043,11 @@ asn1_encode_kdc_dh_key_info(asn1buf *buf, const krb5_kdc_dh_key_info *val,
 {
     asn1_setup();
 
-    if (val->dhKeyExpiration != 0)
-        asn1_addfield(val->dhKeyExpiration, 2, asn1_encode_kerberos_time);
-    asn1_addfield(val->nonce, 1, asn1_encode_integer);
+    if (val->dhKeyExpiration != 0) {
+        asn1_addprimitive(val->dhKeyExpiration, 2, asn1_encode_kerberos_time,
+                          ASN1_GENERALTIME);
+    }
+    asn1_addinteger(val->nonce, 1);
 
     {
         unsigned int length;
@@ -2043,7 +2085,7 @@ asn1_encode_reply_key_pack_draft9(asn1buf *buf,
 {
     asn1_setup();
 
-    asn1_addfield(val->nonce, 1, asn1_encode_integer);
+    asn1_addinteger(val->nonce, 1);
     asn1_addfield(&(val->replyKey), 0, asn1_encode_encryption_key);
 
     asn1_makeseq();
@@ -2157,8 +2199,8 @@ asn1_encode_typed_data(asn1buf *buf, const krb5_pa_data *val,
                        unsigned int *retlen)
 {
     asn1_setup();
-    asn1_addlenfield(val->length, val->contents, 1, asn1_encode_octetstring);
-    asn1_addfield(val->pa_type, 0, asn1_encode_integer);
+    asn1_addstring(val->length, val->contents, 1, ASN1_OCTETSTRING);
+    asn1_addinteger(val->pa_type, 0);
     asn1_makeseq();
     asn1_cleanup();
 }