From: Greg Hudson Date: Fri, 6 Jan 2012 20:52:12 +0000 (+0000) Subject: Use content-only ASN.1 primitives X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=3688edd67398b6d8f6a80c400889c1a361dffcda;p=krb5.git Use content-only ASN.1 primitives 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 --- diff --git a/src/lib/krb5/asn.1/asn1_encode.c b/src/lib/krb5/asn.1/asn1_encode.c index 5ecd82f59..f222423e9 100644 --- a/src/lib/krb5/asn.1/asn1_encode.c +++ b/src/lib/krb5/asn.1/asn1_encode.c @@ -32,28 +32,14 @@ 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: diff --git a/src/lib/krb5/asn.1/asn1_encode.h b/src/lib/krb5/asn.1/asn1_encode.h index 8a7c9f073..ed2eb18e9 100644 --- a/src/lib/krb5/asn.1/asn1_encode.h +++ b/src/lib/krb5/asn.1/asn1_encode.h @@ -43,11 +43,9 @@ * 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 . tinfo is a - * struct fn_info *. */ + /* Encoder function (contents-only) to be called with address of + * 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 . tinfo + * is a struct primitive_info * with tagval ignored. */ atype_fn, /* - * Encoder function to be called with address of and a - * length (unsigned int). tinfo is a struct fn_len_info *. + * Encoder function (contents only) to be called with address of + * 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. diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index 8aecfdf56..56b98022b 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -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(); }