diff options
Diffstat (limited to 'src/lib/krb5/asn.1')
-rw-r--r-- | src/lib/krb5/asn.1/TODO.asn1 | 90 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/asn1_encode.c | 518 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/asn1_encode.h | 539 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/asn1_k_decode.c | 7 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/asn1_k_encode.c | 2003 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/asn1_k_encode.h | 208 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/asn1buf.c | 27 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/asn1buf.h | 15 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/krb5_encode.c | 849 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/krbasn1.h | 13 | ||||
-rw-r--r-- | src/lib/krb5/asn.1/ldap_key_seq.c | 239 |
11 files changed, 2317 insertions, 2191 deletions
diff --git a/src/lib/krb5/asn.1/TODO.asn1 b/src/lib/krb5/asn.1/TODO.asn1 new file mode 100644 index 0000000..73f5fed --- /dev/null +++ b/src/lib/krb5/asn.1/TODO.asn1 @@ -0,0 +1,90 @@ +-*- text -*- + +Stuff that should still be done on the ASN.1 encoder conversion: + +* Add support for opaque objects (pre-encoded fields, or ANY), and fix + up those remaining encoders (e.g., asn1_encode_sam_challenge_2) that + need them. + +* Convert PKINIT encoders, after we have test cases. + +* Make offsetof uses conforming. Currently we may use foo.bar or + foo[0] as fields. + +* Script to generate the tables. Then each type or field entry can + generate multiple bits of code, instead of forcing us to bury the + type consistency checking into the structure initializer + expression. For example, we might generate these bits of code from + one field descriptor: + + * Field table entry. + + * Type-checking code: Create a pointer of the expected type and a + pointer of the actual type (address of field of automatic struct), + and verify consistency with comparison, assignment, or conditional + expr. Plenty of comments to indicate what's being compared and + what a compiler complain means. + + * Range-checking code for bitfields: Create an automatic field info + struct, fill in the computed offset or whatever, read it back, + make sure it matches. Also with comments. + + * Possibly header declarations describing the types that could be + imported, with correct handles *and* C types. + + * Static declarations for non-exported types to keep symbol table + sizes down. + + Then similar bits of code (e.g., all the field table entries) can be + pulled together into the appropriate places. + +* Some kind of "module" system for exporting and importing encoders, + better than relying on the "type_*" variable names. Probably use + meaningful strings that indicate both the ASN.1 type and the + associated C type. Find a way to fit "imported type" into this + scheme so that we can cleanly move the PKINIT types into the PKINIT + plugin, the LDAP types into the LDAP plugin, etc., and still let + them use the encoders in the code. Only a subset of types would be + exported probably. + +* More compact encoding: For tags and optional-field bit positions, + encode N+1, and use 0 for "none", then make the field unsigned. + Currently the fields are signed, non-negative values hold useful + data, -1 means "none", and MIN..-2 are unused. Changing this will + either let us reduce the field size one bit, or extend the maximum + tag/bitpos value from 2**(N-1)-1 to 2**N-2. + +* More compact encoding: Use a union with designated initializers, or + some ugly casting, to make the structures smaller by not having all + fields present when we never use all of them at once. The union + approach is certainly more appealing, aside from the little detail + that it won't work on Windows unless we do all the initialization at + run time. + +* Pie in the sky: A verbose mode that can tell you "missing field + KDC-REP.cname.name-string[1].data" or some such. This would require + tracking the stack of pending encodes and adding strings with type + and field names. + +* For ALL_POINTERS_ARE_THE_SAME mode (which is not strictly conforming + with the C standard, and thus not default currently, but makes + things a little smaller and faster), eliminate the loadptr structure + entry. + +* Maybe: Reorganize the data of a "module" so everything needing + relocation is put in some tables, referenced by index from other + structures without relocations. E.g., for krb5_data, here's the + offset for the data pointer, here's the offset for the length value, + here's the index into the pointer reader function table, here's the + index into the length reader function table, here's an index into + the string-type encoder table. + + Using an index into a set of pointer types, with a single function + taking an integer parameter used to switch between various + ptr-to-ptr-to-type code paths, will be a lot smaller -- with a good + compiler the function will probably collapse to a simple + fetch-a-pointer function ignoring the integer argument, while at the + C level it's strictly conforming by using the correct types for + access. + +* Table-driven decoders? diff --git a/src/lib/krb5/asn.1/asn1_encode.c b/src/lib/krb5/asn.1/asn1_encode.c index d55e183..d2caefd 100644 --- a/src/lib/krb5/asn.1/asn1_encode.c +++ b/src/lib/krb5/asn.1/asn1_encode.c @@ -2,7 +2,7 @@ /* * src/lib/krb5/asn.1/asn1_encode.c * - * Copyright 1994 by the Massachusetts Institute of Technology. + * Copyright 1994, 2008 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -30,7 +30,8 @@ #include "asn1_encode.h" #include "asn1_make.h" -static asn1_error_code asn1_encode_integer_internal(asn1buf *buf, long val, +static asn1_error_code asn1_encode_integer_internal(asn1buf *buf, + asn1_intmax val, unsigned int *retlen) { asn1_error_code retval; @@ -62,7 +63,7 @@ static asn1_error_code asn1_encode_integer_internal(asn1buf *buf, long val, return 0; } -asn1_error_code asn1_encode_integer(asn1buf * buf, long val, +asn1_error_code asn1_encode_integer(asn1buf * buf, asn1_intmax val, unsigned int *retlen) { asn1_error_code retval; @@ -80,6 +81,7 @@ asn1_error_code asn1_encode_integer(asn1buf * buf, long val, return 0; } +#if 0 asn1_error_code asn1_encode_enumerated(asn1buf * buf, long val, unsigned int *retlen) @@ -98,8 +100,9 @@ asn1_encode_enumerated(asn1buf * buf, long val, *retlen = length; return 0; } +#endif -asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, unsigned long val, +asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val, unsigned int *retlen) { asn1_error_code retval; @@ -115,7 +118,7 @@ asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, unsigned long val, if (retval) return retval; length++; valcopy = valcopy >> 8; - } while (valcopy != 0 && valcopy != ~0); + } while (valcopy != 0); if (digit&0x80) { /* make sure the high bit is */ retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */ @@ -131,16 +134,18 @@ asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, unsigned long val, return 0; } -asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len, - const asn1_octet *val, - unsigned int *retlen) +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, ASN1_OBJECTIDENTIFIER, + retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, tag, len, &length); if (retval) return retval; @@ -148,37 +153,23 @@ asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len, return 0; } -asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len, - const asn1_octet *val, - unsigned int *retlen) +asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len, + const asn1_octet *val, + unsigned int *retlen) { - asn1_error_code retval; - unsigned int length; - - retval = asn1buf_insert_octetstring(buf,len,val); - if (retval) return retval; - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length); - if (retval) return retval; - - *retlen = len + length; - return 0; + return encode_bytestring_with_tag(buf, len, val, ASN1_OBJECTIDENTIFIER, + retlen); } -asn1_error_code asn1_encode_charstring(asn1buf *buf, unsigned int len, - const char *val, unsigned int *retlen) +asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len, + const void *val, + unsigned int *retlen) { - asn1_error_code retval; - unsigned int length; - - retval = asn1buf_insert_charstring(buf,len,val); - if (retval) return retval; - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length); - if (retval) return retval; - - *retlen = len + length; - return 0; + 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; @@ -195,40 +186,23 @@ asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen) asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len, const char *val, int *retlen) { - asn1_error_code retval; - unsigned int length; - - retval = asn1buf_insert_charstring(buf,len,val); - if (retval) return retval; - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_PRINTABLESTRING,len, &length); - if (retval) return retval; - - *retlen = len + length; - return 0; + 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_error_code retval; - unsigned int length; - - retval = asn1buf_insert_charstring(buf,len,val); - if (retval) return retval; - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_IA5STRING,len, &length); - if (retval) return retval; - - *retlen = len + length; - return 0; + return encode_bytestring_with_tag(buf, len, val, ASN1_IA5STRING, + retlen); } +#endif asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val, unsigned int *retlen) { - asn1_error_code retval; struct tm *gtime, gtimebuf; char s[16], *sp; - unsigned int length, sum=0; time_t gmt_time = val; /* @@ -237,6 +211,7 @@ asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val, if (gmt_time == 0) { sp = "19700101000000Z"; } else { + int len; /* * Sanity check this just to be paranoid, as gmtime can return NULL, @@ -262,40 +237,435 @@ asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val, gtime->tm_mday > 31 || gtime->tm_hour > 23 || gtime->tm_min > 59 || gtime->tm_sec > 59) return ASN1_BAD_GMTIME; - if (snprintf(s, sizeof(s), "%04d%02d%02d%02d%02d%02dZ", - 1900+gtime->tm_year, gtime->tm_mon+1, gtime->tm_mday, - gtime->tm_hour, gtime->tm_min, gtime->tm_sec) - >= sizeof(s)) + len = snprintf(s, sizeof(s), "%04d%02d%02d%02d%02d%02dZ", + 1900+gtime->tm_year, gtime->tm_mon+1, + gtime->tm_mday, gtime->tm_hour, + gtime->tm_min, gtime->tm_sec); + if (SNPRINTF_OVERFLOW(len, sizeof(s))) /* Shouldn't be possible given above tests. */ return ASN1_BAD_GMTIME; sp = s; } - retval = asn1buf_insert_charstring(buf,15,sp); + 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); +} + +asn1_error_code 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; - sum = 15; + 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; +} - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALTIME,sum,&length); +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; - sum += length; + *retlen = len; + return 0; +} + +/* ASN.1 constructed type encoder engine + Two entry points here: + + krb5int_asn1_encode_a_thing: Incrementally adds the partial + encoding of an object to an already-initialized asn1buf. + + krb5int_asn1_do_full_encode: Returns a completed encoding, in the + correct byte order, in an allocated krb5_data. */ + +#ifdef POINTERS_ARE_ALL_THE_SAME +#define LOADPTR(PTR,TYPE) \ + (assert((TYPE)->loadptr != NULL), (TYPE)->loadptr(PTR)) +#else +#define LOADPTR(PTR,TYPE) \ + (*(const void *const *)(PTR)) +#endif + +static int +get_nullterm_sequence_len(const void *valp, const struct atype_info *seq) +{ + int i; + const struct atype_info *a; + const void *elt, *eltptr; + + a = seq; + i = 0; + assert(a->type == atype_ptr); + assert(seq->size != 0); + + while (1) { + eltptr = (const char *) valp + i * seq->size; + elt = LOADPTR(eltptr, a); + if (elt == NULL) + break; + i++; + } + return i; +} +static asn1_error_code +encode_sequence_of(asn1buf *buf, int seqlen, const void *val, + const struct atype_info *eltinfo, + unsigned int *retlen); + +static asn1_error_code +encode_nullterm_sequence_of(asn1buf *buf, const void *val, + const struct atype_info *type, + int can_be_empty, + unsigned int *retlen) +{ + int length = get_nullterm_sequence_len(val, type); + if (!can_be_empty && length == 0) return ASN1_MISSING_FIELD; + return encode_sequence_of(buf, length, val, type, retlen); +} + +static asn1_error_code +just_encode_sequence(asn1buf *buf, const void *val, + 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_error_code +krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val, + const struct atype_info *a, unsigned int *retlen) +{ + switch (a->type) { + case atype_fn: + assert(a->enc != NULL); + return a->enc(buf, val, retlen); + case atype_sequence: + assert(a->seq != NULL); + return just_encode_sequence(buf, val, a->seq, retlen); + case atype_ptr: + assert(a->basetype != NULL); + return krb5int_asn1_encode_a_thing(buf, LOADPTR(val, a), + a->basetype, retlen); + case atype_field: + assert(a->field != NULL); + return encode_a_field(buf, val, a->field, retlen); + case atype_nullterm_sequence_of: + case atype_nonempty_nullterm_sequence_of: + assert(a->basetype != NULL); + return encode_nullterm_sequence_of(buf, val, a->basetype, + a->type == atype_nullterm_sequence_of, + retlen); + case atype_tagged_thing: + { + asn1_error_code retval; + unsigned int length, sum = 0; + retval = krb5int_asn1_encode_a_thing(buf, val, a->basetype, &length); + if (retval) return retval; + sum = length; + retval = asn1_make_etag(buf, a->tagtype, a->tagval, sum, &length); + if (retval) return retval; + sum += length; + *retlen = sum; + return 0; + } + case atype_int: + assert(a->loadint != NULL); + return asn1_encode_integer(buf, a->loadint(val), retlen); + case atype_uint: + assert(a->loaduint != NULL); + return asn1_encode_unsigned_integer(buf, a->loaduint(val), retlen); + case atype_min: + case atype_max: + case atype_fn_len: + default: + assert(a->type > atype_min); + assert(a->type < atype_max); + assert(a->type != atype_fn_len); + abort(); + } +} + +static asn1_error_code +encode_a_field(asn1buf *buf, const void *val, + const struct field_info *field, + unsigned int *retlen) +{ + asn1_error_code retval; + unsigned int sum = 0; + + if (val == NULL) return ASN1_MISSING_FIELD; + + switch (field->ftype) { + case field_immediate: + { + unsigned int length; + + retval = asn1_encode_integer(buf, field->dataoff, &length); + if (retval) return retval; + sum += length; + break; + } + case field_sequenceof_len: + { + const void *dataptr, *lenptr; + int slen; + unsigned int length; + const struct atype_info *a; + + /* The field holds a pointer to the array of objects. So the + address we compute is a pointer-to-pointer, and that's what + field->atype must help us dereference. */ + dataptr = (const char *)val + field->dataoff; + lenptr = (const char *)val + field->lenoff; + assert(field->atype->type == atype_ptr); + dataptr = LOADPTR(dataptr, field->atype); + a = field->atype->basetype; + assert(field->lentype != 0); + assert(field->lentype->type == atype_int || field->lentype->type == atype_uint); + assert(sizeof(int) <= sizeof(asn1_intmax)); + assert(sizeof(unsigned int) <= sizeof(asn1_uintmax)); + if (field->lentype->type == atype_int) { + asn1_intmax xlen = field->lentype->loadint(lenptr); + if (xlen < 0) + return EINVAL; + if ((unsigned int) xlen != (asn1_uintmax) xlen) + return EINVAL; + if ((unsigned int) xlen > INT_MAX) + return EINVAL; + slen = (int) xlen; + } else { + asn1_uintmax xlen = field->lentype->loaduint(lenptr); + if ((unsigned int) xlen != xlen) + return EINVAL; + if (xlen > INT_MAX) + return EINVAL; + slen = (int) xlen; + } + if (slen != 0 && dataptr == NULL) + return ASN1_MISSING_FIELD; + retval = encode_sequence_of(buf, slen, dataptr, a, &length); + if (retval) return retval; + sum += length; + break; + } + case field_normal: + { + const void *dataptr; + const struct atype_info *a; + unsigned int length; + + dataptr = (const char *)val + field->dataoff; + + a = field->atype; + assert(a->type != atype_fn_len); + retval = krb5int_asn1_encode_a_thing(buf, dataptr, a, &length); + if (retval) { + return retval; + } + sum += length; + break; + } + case field_string: + { + const void *dataptr, *lenptr; + const struct atype_info *a; + size_t slen; + unsigned int length; + + dataptr = (const char *)val + field->dataoff; + lenptr = (const char *)val + field->lenoff; + + a = field->atype; + assert(a->type == atype_fn_len); + assert(field->lentype != 0); + assert(field->lentype->type == atype_int || field->lentype->type == atype_uint); + assert(sizeof(int) <= sizeof(asn1_intmax)); + assert(sizeof(unsigned int) <= sizeof(asn1_uintmax)); + if (field->lentype->type == atype_int) { + asn1_intmax xlen = field->lentype->loadint(lenptr); + if (xlen < 0) + return EINVAL; + if ((size_t) xlen != (asn1_uintmax) xlen) + return EINVAL; + slen = (size_t) xlen; + } else { + asn1_uintmax xlen = field->lentype->loaduint(lenptr); + if ((size_t) xlen != xlen) + return EINVAL; + slen = (size_t) xlen; + } + + dataptr = LOADPTR(dataptr, a); + 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) + return EINVAL; + assert(a->enclen != NULL); + retval = a->enclen(buf, (unsigned int) slen, dataptr, &length); + if (retval) { + return retval; + } + sum += length; + break; + } + default: + assert(field->ftype > field_min); + assert(field->ftype < field_max); + assert(__LINE__ == 0); + abort(); + } + if (field->tag >= 0) { + unsigned int length; + retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, field->tag, sum, + &length); + if (retval) { + return retval; + } + sum += length; + } *retlen = sum; return 0; } -asn1_error_code asn1_encode_generalstring(asn1buf *buf, unsigned int len, - const char *val, - unsigned int *retlen) +static asn1_error_code +encode_fields(asn1buf *buf, const void *val, + const struct field_info *fields, size_t nfields, + unsigned int optional, + unsigned int *retlen) { + size_t i; + unsigned int sum = 0; + for (i = nfields; i > 0; i--) { + const struct field_info *f = fields+i-1; + unsigned int length; + 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); + if (retval) return retval; + sum += length; + } + } + *retlen = sum; + return 0; +} + +static asn1_error_code +just_encode_sequence(asn1buf *buf, const void *val, + const struct seq_info *seq, + unsigned int *retlen) +{ + const struct field_info *fields = seq->fields; + size_t nfields = seq->n_fields; + unsigned int optional; asn1_error_code retval; - unsigned int length; + unsigned int sum = 0; + + if (seq->optional) + optional = seq->optional(val); + else + /* In this case, none of the field descriptors should indicate + that we examine any bits of this value. */ + optional = 0; + { + unsigned int length; + retval = encode_fields(buf, val, fields, nfields, optional, &length); + if (retval) return retval; + sum += length; + } + { + unsigned int length; + retval = asn1_make_sequence(buf, sum, &length); + if (retval) return retval; + sum += length; + } + *retlen = sum; + return 0; +} - retval = asn1buf_insert_charstring(buf,len,val); - if (retval) return retval; - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALSTRING,len, - &length); - if (retval) return retval; +static asn1_error_code +encode_sequence_of(asn1buf *buf, int seqlen, const void *val, + const struct atype_info *eltinfo, + unsigned int *retlen) +{ + asn1_error_code retval; + unsigned int sum = 0; + int i; - *retlen = len + length; + for (i = seqlen-1; i >= 0; i--) { + const void *eltptr; + unsigned int length; + const struct atype_info *a = eltinfo; + + assert(eltinfo->size != 0); + eltptr = (const char *)val + i * eltinfo->size; + retval = krb5int_asn1_encode_a_thing(buf, eltptr, a, &length); + if (retval) return retval; + sum += length; + } + { + unsigned int length; + retval = asn1_make_sequence(buf, sum, &length); + if (retval) return retval; + sum += length; + } + *retlen = sum; return 0; } + +krb5_error_code +krb5int_asn1_do_full_encode(const void *rep, krb5_data **code, + const struct atype_info *a) +{ + unsigned int length; + asn1_error_code retval; + unsigned int sum = 0; + asn1buf *buf = NULL; + + if (rep == NULL) return ASN1_MISSING_FIELD; + + retval = asn1buf_create(&buf); + if (retval) + return retval; + + retval = krb5int_asn1_encode_a_thing(buf, rep, a, &length); + if (retval) + return retval; + sum += length; + retval = asn12krb5_buf(buf, code); + asn1buf_destroy(&buf); + return retval; +} diff --git a/src/lib/krb5/asn.1/asn1_encode.h b/src/lib/krb5/asn.1/asn1_encode.h index c75f4e8..1486333 100644 --- a/src/lib/krb5/asn.1/asn1_encode.h +++ b/src/lib/krb5/asn.1/asn1_encode.h @@ -2,7 +2,7 @@ /* * src/lib/krb5/asn.1/asn1_encode.h * - * Copyright 1994 by the Massachusetts Institute of Technology. + * Copyright 1994, 2008 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -42,16 +42,16 @@ Operations asn1_encode_integer + asn1_encode_unsigned_integer asn1_encode_octetstring - asn1_encode_null - asn1_encode_printablestring - asn1_encode_ia5string asn1_encode_generaltime asn1_encode_generalstring + asn1_encode_bitstring + asn1_encode_oid */ asn1_error_code asn1_encode_integer - (asn1buf *buf, long val, unsigned int *retlen); + (asn1buf *buf, asn1_intmax val, unsigned int *retlen); /* requires *buf is allocated modifies *buf, *retlen effects Inserts the encoding of val into *buf and returns @@ -63,7 +63,7 @@ asn1_error_code asn1_encode_enumerated (asn1buf *buf, long val, unsigned int *retlen); asn1_error_code asn1_encode_unsigned_integer - (asn1buf *buf, unsigned long val, + (asn1buf *buf, asn1_uintmax val, unsigned int *retlen); /* requires *buf is allocated modifies *buf, *retlen @@ -74,7 +74,7 @@ asn1_error_code asn1_encode_unsigned_integer asn1_error_code asn1_encode_octetstring (asn1buf *buf, - unsigned int len, const asn1_octet *val, + unsigned int len, const void *val, unsigned int *retlen); /* requires *buf is allocated modifies *buf, *retlen @@ -82,6 +82,7 @@ asn1_error_code asn1_encode_octetstring 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 asn1_error_code asn1_encode_oid (asn1buf *buf, @@ -94,17 +95,6 @@ asn1_error_code asn1_encode_oid Returns ENOMEM to signal an unsuccesful attempt to expand the buffer. */ -asn1_error_code asn1_encode_charstring - (asn1buf *buf, - unsigned int len, const char *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. */ - asn1_error_code asn1_encode_null (asn1buf *buf, int *retlen); /* requires *buf is allocated @@ -148,7 +138,7 @@ asn1_error_code asn1_encode_generaltime asn1_error_code asn1_encode_generalstring (asn1buf *buf, - unsigned int len, const char *val, + unsigned int len, const void *val, unsigned int *retlen); /* requires *buf is allocated, val has a length of len characters modifies *buf, *retlen @@ -157,4 +147,515 @@ asn1_error_code asn1_encode_generalstring 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); +/* 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_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. + + In this context, a "type" is a combination of a C data type + and an ASN.1 encoding scheme for it. So we would have to define + different "types" for: + + * unsigned char* encoded as octet string + * char* encoded as octet string + * char* encoded as generalstring + * krb5_data encoded as octet string + * krb5_data encoded as generalstring + * int32_t encoded as integer + * unsigned char encoded as integer + + Perhaps someday some kind of flags could be defined so that minor + variations on the C types could be handled via common routines. + + The handling of strings is pretty messy. Currently, we have a + separate kind of encoder function that takes an extra length + parameter. Perhaps we should just give up on that, always deal + with just a single location, and handle strings by via encoder + functions for krb5_data, keyblock, etc. + + We wind up with a lot of load-time relocations being done, which is + a bit annoying. Be careful about "fixing" that at the cost of too + much run-time performance. It might work to have a master "module" + descriptor with pointers to various arrays (type descriptors, + strings, field descriptors, functions) most of which don't need + relocation themselves, and replace most of the pointers with table + indices. + + It's a work in progress. */ + +enum atype_type { + /* For bounds checking only. By starting with values above 1, we + guarantee that zero-initialized storage will be recognized as + invalid. */ + atype_min = 1, + /* Encoder function to be called with address of <thing>. */ + atype_fn, + /* Encoder function to be called with address of <thing> and a + length (unsigned int). */ + atype_fn_len, + /* Pointer to actual thing to be encoded. + + Most of the fields are related only to the C type -- size, how + to fetch a pointer in a type-safe fashion -- but since the base + type descriptor encapsulates the encoding as well, different + encodings for the same C type may require different pointer-to + types as well. + + Must not refer to atype_fn_len. */ + atype_ptr, + /* Sequence, with pointer to sequence descriptor header. */ + atype_sequence, + /* Sequence-of, with pointer to base type descriptor, represented + as a null-terminated array of pointers (and thus the "base" + type descriptor is actually an atype_ptr node). */ + atype_nullterm_sequence_of, + atype_nonempty_nullterm_sequence_of, + /* Encode this object using a single field descriptor. This 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 + and encode a counted SEQUENCE OF. */ + atype_field, + /* Tagged version of another type. */ + atype_tagged_thing, + /* Integer types. */ + atype_int, + atype_uint, + /* Unused except for bounds checking. */ + atype_max +}; + +/* Initialized structures could be a lot smaller if we could use C99 + designated initializers, and a union for all the type-specific + stuff. Maybe use the hack we use for krb5int_access, where we use + a run-time initialize if the compiler doesn't support designated + initializers? That's a lot of work here, though, with so many + little structures. Maybe if/when these get auto-generated. */ +struct atype_info { + enum atype_type type; + /* used for sequence-of processing */ + unsigned int size; + /* atype_fn */ + asn1_error_code (*enc)(asn1buf *, const void *, unsigned int *); + /* atype_fn_len */ + asn1_error_code (*enclen)(asn1buf *, unsigned int, const void *, + unsigned int *); + /* atype_ptr, atype_fn_len */ + const void *(*loadptr)(const void *); + /* atype_ptr, atype_nullterm_sequence_of */ + const struct atype_info *basetype; + /* atype_sequence */ + const struct seq_info *seq; + /* atype_field */ + const struct field_info *field; + /* atype_tagged_thing */ + unsigned int tagval : 8, tagtype : 8; + /* atype_[u]int */ + asn1_intmax (*loadint)(const void *); + asn1_uintmax (*loaduint)(const void *); +}; + +/* The various DEF*TYPE macros must: + + + Define a type named aux_typedefname_##DESCNAME, for use in any + types derived from the type being defined. + + + Define an atype_info struct named krb5int_asn1type_##DESCNAME. + + + Define any extra stuff needed in the type descriptor, like + pointer-load functions. + + + Accept a following semicolon syntactically, to keep Emacs parsing + (and indentation calculating) code happy. + + Nothing else should directly define the atype_info structures. */ + +/* 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. + + 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. */ +#define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN) \ + typedef CTYPENAME aux_typedefname_##DESCNAME; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_fn, sizeof(CTYPENAME), ENCFN, \ + } +#define DEFFNXTYPE(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); \ + } \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_fn, sizeof(CTYPENAME), aux_encfn_##DESCNAME, \ + } +/* XXX The handling of data+length fields really needs reworking. + A type descriptor probably isn't the right way. + + Also, the C type is likely to be one of char*, unsigned char*, + or (maybe) void*. An enumerator or reference to an external + function would be more compact. + + The supplied encoder function takes as an argument the data pointer + loaded from the indicated location, not the address of the field. + This isn't consistent with DEFFN[X]TYPE above, but all of the uses + of DEFFNLENTYPE are for string encodings, and that's how our + string-encoding primitives work. So be it. */ +#ifdef POINTERS_ARE_ALL_THE_SAME +#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN) \ + typedef CTYPENAME aux_typedefname_##DESCNAME; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_fn_len, 0, 0, ENCFN, \ + } +#else +#define DEFFNLENTYPE(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; \ + } \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_fn_len, 0, 0, ENCFN, \ + loadptr_for_##DESCNAME \ + } +#endif +/* A sequence, defined by the indicated series of fields, and an + optional function indicating which fields are present. */ +#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS, OPT) \ + typedef CTYPENAME aux_typedefname_##DESCNAME; \ + static const struct seq_info aux_seqinfo_##DESCNAME = { \ + OPT, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0]) \ + }; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_sequence, sizeof(CTYPENAME), 0,0,0,0, \ + &aux_seqinfo_##DESCNAME, \ + } +/* Integer types. */ +#define DEFINTTYPE(DESCNAME, CTYPENAME) \ + typedef CTYPENAME aux_typedefname_##DESCNAME; \ + static asn1_intmax loadint_##DESCNAME(const void *p) \ + { \ + assert(sizeof(CTYPENAME) <= sizeof(asn1_intmax)); \ + return *(const aux_typedefname_##DESCNAME *)p; \ + } \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_int, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \ + loadint_##DESCNAME, 0, \ + } +#define DEFUINTTYPE(DESCNAME, CTYPENAME) \ + typedef CTYPENAME aux_typedefname_##DESCNAME; \ + static asn1_uintmax loaduint_##DESCNAME(const void *p) \ + { \ + assert(sizeof(CTYPENAME) <= sizeof(asn1_uintmax)); \ + return *(const aux_typedefname_##DESCNAME *)p; \ + } \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_uint, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, loaduint_##DESCNAME, \ + } +/* Pointers to other types, to be encoded as those other types. */ +#ifdef POINTERS_ARE_ALL_THE_SAME +#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \ + typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, 0, \ + &krb5int_asn1type_##BASEDESCNAME, 0 \ + } +#else +#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \ + typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \ + static const void * \ + loadptr_for_##BASEDESCNAME##_from_##DESCNAME(const void *p) \ + { \ + const aux_typedefname_##DESCNAME *inptr = p; \ + const aux_typedefname_##BASEDESCNAME *retptr; \ + retptr = *inptr; \ + return retptr; \ + } \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, \ + loadptr_for_##BASEDESCNAME##_from_##DESCNAME, \ + &krb5int_asn1type_##BASEDESCNAME, 0 \ + } +#endif +/* This encodes a pointer-to-pointer-to-thing where the passed-in + value points to a null-terminated list of pointers to objects to be + encoded, and encodes a (possibly empty) SEQUENCE OF these objects. + + BASEDESCNAME is a descriptor name for the pointer-to-thing + type. + + When dealing with a structure containing a + pointer-to-pointer-to-thing field, make a DEFPTRTYPE of this type, + and use that type for the structure field. */ +#define DEFNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \ + typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_nullterm_sequence_of, sizeof(aux_typedefname_##DESCNAME), \ + 0, 0, \ + 0 /* loadptr */, \ + &krb5int_asn1type_##BASEDESCNAME, 0 \ + } +#define DEFNONEMPTYNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \ + typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_nonempty_nullterm_sequence_of, \ + sizeof(aux_typedefname_##DESCNAME), \ + 0, 0, \ + 0 /* loadptr */, \ + &krb5int_asn1type_##BASEDESCNAME, 0 \ + } +/* Encode a thing (probably sub-fields within the structure) as a + single object. */ +#define DEFFIELDTYPE(DESCNAME, CTYPENAME, FIELDINFO) \ + typedef CTYPENAME aux_typedefname_##DESCNAME; \ + static const struct field_info aux_fieldinfo_##DESCNAME = FIELDINFO; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_field, sizeof(CTYPENAME), 0, 0, 0, 0, 0, \ + &aux_fieldinfo_##DESCNAME \ + } +/* Objects with an APPLICATION tag added. */ +#define DEFAPPTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \ + typedef aux_typedefname_##BASEDESC aux_typedefname_##DESCNAME; \ + const struct atype_info krb5int_asn1type_##DESCNAME = { \ + atype_tagged_thing, sizeof(aux_typedefname_##DESCNAME), \ + 0, 0, 0, &krb5int_asn1type_##BASEDESC, 0, 0, TAG, APPLICATION \ + } + +/* Declare an externally-defined type. This is a hack we should do + away with once we move to generating code from a script. For now, + this macro is unfortunately not compatible with the defining macros + above, since you can't do the typedefs twice and we need the + declarations to produce typedefs. (We could eliminate the typedefs + from the DEF* macros, but then every DEF* macro use, even the ones + for internal type nodes we only use to build other types, would + need an accompanying declaration which explicitly lists the + type.) */ +#define IMPORT_TYPE(DESCNAME, CTYPENAME) \ + 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 */ + +/* Sequence field descriptor. + + Currently we assume everything is a single object with a type + descriptor, and then we bolt on some ugliness on the side for + handling strings with length fields. + + Anything with "interesting" encoding handling, like a sequence-of + or a pointer to the actual value to encode, is handled via opaque + types with their own encoder functions. Most of that should + eventually change. */ + +enum field_type { + /* Unused except for range checking. */ + field_min = 1, + /* Field ATYPE describes processing of field at DATAOFF. */ + field_normal, + /* Encode an "immediate" integer value stored in DATAOFF, with no + reference to the data structure. */ + field_immediate, + /* Encode some kind of string field encoded with pointer and + length. (A GENERALSTRING represented as a null-terminated C + string would be handled as field_normal.) */ + field_string, + /* LENOFF indicates a value describing the length of the array at + DATAOFF, encoded as a sequence-of with the element type + described by ATYPE. */ + field_sequenceof_len, + /* Unused except for range checking. */ + field_max +}; +/* To do: Consider using bitfields. */ +struct field_info { + /* Type of the field. */ + unsigned int /* enum field_type */ ftype : 3; + + /* Use of DATAOFF and LENOFF are described by the value in FTYPE. + Generally DATAOFF will be the offset from the supplied pointer + at which we find the object to be encoded. */ + unsigned int dataoff : 9, lenoff : 9; + + /* If TAG is non-negative, a context tag with that value is added + to the encoding of the thing. (XXX This would encode more + compactly as an unsigned bitfield value tagnum+1, with 0=no + tag.) The tag is omitted for optional fields that are not + present. + + It's a bit illogical to combine the tag and other field info, + since really a sequence field could have zero or several + context tags, and of course a tag could be used elsewhere. But + the normal mode in the Kerberos ASN.1 description is to use one + context tag on each sequence field, so for now let's address + that case primarily and work around the other cases (thus tag<0 + means skip tagging). */ + signed int tag : 5; + + /* If OPT is non-negative and the sequence header structure has a + function pointer describing which fields are present, OPT is + the bit position indicating whether the currently-described + element is present. (XXX Similar encoding issue.) + + Note: Most of the time, I'm using the same number here as for + the context tag. This is just because it's easier for me to + keep track while working on the code by hand. The *only* + meaningful correlation is of this value and the bits set by the + "optional" function when examining the data structure. */ + signed int opt : 5; + + /* For some values of FTYPE, this describes the type of the + object(s) to be encoded. */ + const struct atype_info *atype; + + /* We use different types for "length" fields in different places. + So we need a good way to retrieve the various kinds of lengths + in a compatible way. This may be a string length, or the + length of an array of objects to encode in a SEQUENCE OF. + + In case the field is signed and negative, or larger than + size_t, return SIZE_MAX as an error indication. We'll assume + for now that we'll never have 4G-1 (or 2**64-1, or on tiny + systems, 65535) sized values. On most if not all systems we + care about, SIZE_MAX is equivalent to "all of addressable + memory" minus one byte. That wouldn't leave enough extra room + for the structure we're encoding, so it's pretty safe to assume + SIZE_MAX won't legitimately come up on those systems. + + If this code gets ported to a segmented architecture or other + system where it might be possible... figure it out then. */ + const struct atype_info *lentype; +}; + +/* Normal or optional sequence fields at a particular offset, encoded + as indicated by the listed DESCRiptor. */ +#define FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,OPT) \ + { \ + field_normal, OFFOF(TYPE, FIELDNAME, aux_typedefname_##DESCR), \ + 0, TAG, OPT, &krb5int_asn1type_##DESCR \ + } +#define FIELDOF_NORM(TYPE,DESCR,FIELDNAME,TAG) \ + FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,-1) +/* If encoding a subset of the fields of the current structure (for + example, a flat structure describing data that gets encoded as a + sequence containing one or more sequences), use ENCODEAS, no struct + field name(s), and the indicated type descriptor must support the + current struct type. */ +#define FIELDOF_ENCODEAS(TYPE,DESCR,TAG) \ + FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,-1) +#define FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,OPT) \ + { \ + field_normal, \ + 0 * sizeof(0 ? (TYPE *)0 : (aux_typedefname_##DESCR *) 0), \ + 0, TAG, OPT, &krb5int_asn1type_##DESCR \ + } + +/* Reinterpret some subset of the structure itself as something + else. */ +#define FIELD_SELF(DESCR, TAG) \ + { field_normal, 0, 0, TAG, -1, &krb5int_asn1type_##DESCR } + +#define FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,OPT) \ + { \ + field_string, \ + OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \ + OFFOF(STYPE, LENFIELD, aux_typedefname_##LENDESC), \ + TAG, OPT, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENDESC \ + } +#define FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,OPT) \ + FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,uint,LENFIELD,TAG,OPT) +#define FIELDOF_STRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG) \ + FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,-1) +#define FIELDOF_STRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \ + FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,-1) +#define FIELD_INT_IMM(VALUE,TAG) \ + { field_immediate, VALUE, 0, TAG, -1, 0, } + +#define FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG) \ + { \ + field_sequenceof_len, \ + OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \ + OFFOF(STYPE, LENFIELD, aux_typedefname_##LENTYPE), \ + TAG, -1, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE \ + } +#define FIELDOF_SEQOF_INT32(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \ + FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,int32,TAG) + +struct seq_info { + /* If present, returns a bitmask indicating which fields are + present. See the "opt" field in struct field_info. */ + unsigned int (*optional)(const void *); + /* Indicates an array of sequence field descriptors. */ + const struct field_info *fields; + size_t n_fields; + /* Missing: Extensibility handling. (New field type?) */ +}; + +extern krb5_error_code +krb5int_asn1_do_full_encode(const void *rep, krb5_data **code, + const struct atype_info *a); + +#define MAKE_FULL_ENCODER(FNAME, DESC) \ + krb5_error_code FNAME(const aux_typedefname_##DESC *rep, \ + krb5_data **code) \ + { \ + return krb5int_asn1_do_full_encode(rep, code, \ + &krb5int_asn1type_##DESC); \ + } \ + extern int dummy /* gobble semicolon */ + +#include <stddef.h> +/* Ugly hack! + Like "offsetof", but with type checking. */ +#define WARN_IF_TYPE_MISMATCH(LVALUE, TYPE) \ + (sizeof(0 ? (TYPE *) 0 : &(LVALUE))) +#define OFFOF(TYPE,FIELD,FTYPE) \ + (offsetof(TYPE, FIELD) \ + + 0 * WARN_IF_TYPE_MISMATCH(((TYPE*)0)->FIELD, FTYPE)) + #endif diff --git a/src/lib/krb5/asn.1/asn1_k_decode.c b/src/lib/krb5/asn.1/asn1_k_decode.c index e47ca6f..2af3a00 100644 --- a/src/lib/krb5/asn.1/asn1_k_decode.c +++ b/src/lib/krb5/asn.1/asn1_k_decode.c @@ -741,12 +741,12 @@ array_expand (void *array, int n_elts, size_t elt_size) if (n_elts <= 0) return NULL; - if (n_elts > SIZE_MAX / elt_size) + if ((unsigned int) n_elts > SIZE_MAX / elt_size) return NULL; new_size = n_elts * elt_size; if (new_size == 0) return NULL; - if (new_size / elt_size != n_elts) + if (new_size / elt_size != (unsigned int) n_elts) return NULL; new_array = realloc(array, new_size); return new_array; @@ -1374,7 +1374,8 @@ asn1_error_code asn1_decode_algorithm_identifier(asn1buf *buf, krb5_algorithm_i val->parameters.length = 0; val->parameters.data = NULL; - if (length > subbuf.next - subbuf.base) { + assert(subbuf.next >= subbuf.base); + if (length > (size_t)(subbuf.next - subbuf.base)) { unsigned int size = length - (subbuf.next - subbuf.base); retval = asn1buf_remove_octetstring(&subbuf, size, &val->parameters.data); diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index e2577d8..a94ac3c 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -30,45 +30,10 @@ #include "asn1_encode.h" #include <assert.h> -/**** asn1 macros ****/ -#if 0 - How to write an asn1 encoder function using these macros: +/* helper macros - asn1_error_code asn1_encode_krb5_substructure(asn1buf *buf, - const krb5_type *val, - int *retlen) - { - asn1_setup(); - - asn1_addfield(val->last_field, n, asn1_type); - asn1_addfield(rep->next_to_last_field, n-1, asn1_type); - ... - - /* for OPTIONAL fields */ - if (rep->field_i == should_not_be_omitted) - asn1_addfield(rep->field_i, i, asn1_type); - - /* for string fields (these encoders take an additional argument, - the length of the string) */ - addlenfield(rep->field_length, rep->field, i-1, asn1_type); - - /* if you really have to do things yourself... */ - retval = asn1_encode_asn1_type(buf,rep->field,&length); - if (retval) return retval; - sum += length; - retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, tag_number, length, - &length); - if (retval) return retval; - sum += length; - - ... - asn1_addfield(rep->second_field, 1, asn1_type); - asn1_addfield(rep->first_field, 0, asn1_type); - asn1_makeseq(); - - asn1_cleanup(); - } -#endif + These are mostly only needed for PKINIT, but there are three + basic-krb5 encoders not converted yet. */ /* setup() -- create and initialize bookkeeping variables retval: stores error codes returned from subroutines @@ -76,942 +41,1290 @@ sum: cumulative length of the entire encoding */ #define asn1_setup()\ asn1_error_code retval;\ - unsigned int length, sum=0 - -/* asn1_addfield -- add a field, or component, to the encoding */ -#define asn1_addfield(value,tag,encoder)\ -{ retval = encoder(buf,value,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length;\ - retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length; } - -/* asn1_addlenfield -- add a field whose length must be separately specified */ -#define asn1_addlenfield(len,value,tag,encoder)\ -{ retval = encoder(buf,len,value,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length;\ - retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length; } - -/* asn1_addfield_implicit -- add an implicitly tagged field, or component, to the encoding */ -#define asn1_addfield_implicit(value,tag,encoder)\ -{ retval = encoder(buf,value,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length;\ - retval = asn1_make_tag(buf,CONTEXT_SPECIFIC,PRIMITIVE,tag,length,&length); \ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length; } - -/* asn1_insert_implicit_octetstring -- add an octet string with implicit tagging */ -#define asn1_insert_implicit_octetstring(len,value,tag)\ -{ retval = asn1buf_insert_octetstring(buf,len,value);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += len;\ - retval = asn1_make_tag(buf,CONTEXT_SPECIFIC,PRIMITIVE,tag,len,&length); \ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length; } - -/* asn1_insert_implicit_bitstring -- add a bitstring with implicit tagging */ -#define asn1_insert_implicit_bitstring(len,value,tag)\ -{ retval = asn1buf_insert_octetstring(buf,len,value);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += len;\ - retval = asn1buf_insert_octet(buf, 0);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum++;\ - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,tag,len+1,&length); \ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length; } + unsigned int sum=0 /* form a sequence (by adding a sequence header to the current encoding) */ #define asn1_makeseq()\ +{ unsigned int length;\ retval = asn1_make_sequence(buf,sum,&length);\ if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length - -/* add an APPLICATION class tag to the current encoding */ -#define asn1_apptag(num)\ - retval = asn1_make_etag(buf,APPLICATION,num,sum,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ return retval; }\ - sum += length + sum += length; } /* produce the final output and clean up the workspace */ #define asn1_cleanup()\ *retlen = sum;\ return 0 -asn1_error_code asn1_encode_ui_4(asn1buf *buf, const krb5_ui_4 val, unsigned int *retlen) -{ - return asn1_encode_unsigned_integer(buf,val,retlen); -} - - -asn1_error_code asn1_encode_realm(asn1buf *buf, const krb5_principal val, unsigned int *retlen) -{ - if (val == NULL || - (val->realm.length && val->realm.data == NULL)) - return ASN1_MISSING_FIELD; - return asn1_encode_generalstring(buf,val->realm.length,val->realm.data, - retlen); -} +/* asn1_addfield -- add a field, or component, to the encoding */ +#define asn1_addfield(value,tag,encoder)\ +{ unsigned int length; \ + retval = encoder(buf,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_error_code asn1_encode_principal_name(asn1buf *buf, const krb5_principal val, unsigned int *retlen) -{ - asn1_setup(); - int n; - - if (val == NULL || val->data == NULL) return ASN1_MISSING_FIELD; - - for (n = (int) ((val->length)-1); n >= 0; n--) { - if (val->data[n].length && - val->data[n].data == NULL) - return ASN1_MISSING_FIELD; - retval = asn1_encode_generalstring(buf, - (val->data)[n].length, - (val->data)[n].data, - &length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,1,sum,&length); - if (retval) return retval; - sum += length; +DEFINTTYPE(int32, krb5_int32); +DEFPTRTYPE(int32_ptr, int32); - asn1_addfield(val->type,0,asn1_encode_integer); +DEFUINTTYPE(uint, unsigned int); +DEFUINTTYPE(octet, krb5_octet); +DEFUINTTYPE(ui_4, krb5_ui_4); - asn1_makeseq(); +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); - asn1_cleanup(); -} +DEFFIELDTYPE(gstring_data, krb5_data, + FIELDOF_STRING(krb5_data, generalstring, data, length, -1)); +DEFPTRTYPE(gstring_data_ptr,gstring_data); -asn1_error_code asn1_encode_kerberos_time(asn1buf *buf, const krb5_timestamp val, unsigned int *retlen) -{ - return asn1_encode_generaltime(buf,val,retlen); -} +DEFFIELDTYPE(ostring_data, krb5_data, + FIELDOF_STRING(krb5_data, s_octetstring, data, length, -1)); +DEFPTRTYPE(ostring_data_ptr,ostring_data); -asn1_error_code asn1_encode_host_address(asn1buf *buf, const krb5_address *val, unsigned int *retlen) -{ - asn1_setup(); +DEFFIELDTYPE(opaque_data, krb5_data, + FIELDOF_STRING(krb5_data, opaque, data, length, -1)); - if (val == NULL || val->contents == NULL) return ASN1_MISSING_FIELD; +DEFFIELDTYPE(realm_of_principal_data, krb5_principal_data, + FIELDOF_NORM(krb5_principal_data, gstring_data, realm, -1)); +DEFPTRTYPE(realm_of_principal, realm_of_principal_data); - asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring); - asn1_addfield(val->addrtype,0,asn1_encode_integer); - asn1_makeseq(); - asn1_cleanup(); -} +static const struct field_info princname_fields[] = { + FIELDOF_NORM(krb5_principal_data, int32, type, 0), + FIELDOF_SEQOF_INT32(krb5_principal_data, gstring_data_ptr, data, length, 1), +}; +/* krb5_principal is a typedef for krb5_principal_data*, so this is + effectively "encode_principal_data_at" with an address arg. */ +DEFSEQTYPE(principal_data, krb5_principal_data, princname_fields, 0); +DEFPTRTYPE(principal, principal_data); -asn1_error_code asn1_encode_host_addresses(asn1buf *buf, const krb5_address **val, unsigned int *retlen) +static asn1_error_code +asn1_encode_kerberos_time_at(asn1buf *buf, const krb5_timestamp *val, + unsigned int *retlen) { - asn1_setup(); - int i; - - if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD; - - for (i=0; val[i] != NULL; i++); /* go to end of array */ - for (i--; i>=0; i--) { - retval = asn1_encode_host_address(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - - asn1_cleanup(); + /* Range checking for time_t vs krb5_timestamp? */ + time_t tval = *val; + return asn1_encode_generaltime(buf, tval, retlen); } +DEFFNXTYPE(kerberos_time, krb5_timestamp, asn1_encode_kerberos_time_at); -asn1_error_code asn1_encode_encrypted_data(asn1buf *buf, const krb5_enc_data *val, unsigned int *retlen) -{ - asn1_setup(); - - if (val == NULL || - (val->ciphertext.length && val->ciphertext.data == NULL)) - return ASN1_MISSING_FIELD; - - asn1_addlenfield(val->ciphertext.length,val->ciphertext.data,2,asn1_encode_charstring); - /* krb5_kvno should be int */ - if (val->kvno) - asn1_addfield((int) val->kvno,1,asn1_encode_integer); - asn1_addfield(val->enctype,0,asn1_encode_integer); +const static struct field_info address_fields[] = { + FIELDOF_NORM(krb5_address, int32, addrtype, 0), + FIELDOF_STRING(krb5_address, octetstring, contents, length, 1), +}; +DEFSEQTYPE(address, krb5_address, address_fields, 0); +DEFPTRTYPE(address_ptr, address); - asn1_makeseq(); - - asn1_cleanup(); -} +DEFNULLTERMSEQOFTYPE(seq_of_host_addresses, address_ptr); +DEFPTRTYPE(ptr_seqof_host_addresses, seq_of_host_addresses); -asn1_error_code asn1_encode_krb5_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen) +static unsigned int +optional_encrypted_data (const void *vptr) { - asn1_setup(); - krb5_flags valcopy = val; - int i; - - for (i=0; i<4; i++) { - retval = asn1buf_insert_octet(buf,(asn1_octet) (valcopy&0xFF)); - if (retval) return retval; - valcopy >>= 8; - } - retval = asn1buf_insert_octet(buf,0); /* 0 padding bits */ - if (retval) return retval; - sum = 5; + const krb5_enc_data *val = vptr; + unsigned int optional = 0; - retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_BITSTRING,sum, - &length); - if (retval) return retval; - sum += length; + if (val->kvno != 0) + optional |= (1u << 1); - *retlen = sum; - return 0; + return optional; } -asn1_error_code asn1_encode_ap_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen) -{ - return asn1_encode_krb5_flags(buf,val,retlen); -} - -asn1_error_code asn1_encode_ticket_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen) -{ - return asn1_encode_krb5_flags(buf,val,retlen); -} +static const struct field_info encrypted_data_fields[] = { + FIELDOF_NORM(krb5_enc_data, int32, enctype, 0), + FIELDOF_OPT(krb5_enc_data, uint, kvno, 1, 1), + FIELDOF_NORM(krb5_enc_data, ostring_data, ciphertext, 2), +}; +DEFSEQTYPE(encrypted_data, krb5_enc_data, encrypted_data_fields, + optional_encrypted_data); -asn1_error_code asn1_encode_kdc_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen) +/* The encode_bitstring function wants an array of bytes (since PKINIT + may provide something that isn't 32 bits), but krb5_flags is stored + as a 32-bit integer in host order. */ +static asn1_error_code +asn1_encode_krb5_flags_at(asn1buf *buf, const krb5_flags *val, + unsigned int *retlen) { - return asn1_encode_krb5_flags(buf,val,retlen); + unsigned char cbuf[4]; + store_32_be(*val, cbuf); + return asn1_encode_bitstring(buf, 4, cbuf, retlen); } +DEFFNXTYPE(krb5_flags, krb5_flags, asn1_encode_krb5_flags_at); -asn1_error_code asn1_encode_authorization_data(asn1buf *buf, const krb5_authdata **val, unsigned int *retlen) -{ - asn1_setup(); - int i; - - if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD; - - for (i=0; val[i] != NULL; i++); /* get to the end of the array */ - for (i--; i>=0; i--) { - retval = asn1_encode_krb5_authdata_elt(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - - asn1_cleanup(); -} - -asn1_error_code asn1_encode_krb5_authdata_elt(asn1buf *buf, const krb5_authdata *val, unsigned int *retlen) -{ - asn1_setup(); - - if (val == NULL || - (val->length && val->contents == NULL)) - return ASN1_MISSING_FIELD; - - /* ad-data[1] OCTET STRING */ - asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring); +const static struct field_info authdata_elt_fields[] = { /* ad-type[0] INTEGER */ - asn1_addfield(val->ad_type,0,asn1_encode_integer); - /* SEQUENCE */ - asn1_makeseq(); + FIELDOF_NORM(krb5_authdata, int32, ad_type, 0), + /* ad-data[1] OCTET STRING */ + FIELDOF_STRING(krb5_authdata, octetstring, contents, length, 1), +}; +DEFSEQTYPE(authdata_elt, krb5_authdata, authdata_elt_fields, 0); +DEFPTRTYPE(authdata_elt_ptr, authdata_elt); +DEFNONEMPTYNULLTERMSEQOFTYPE(auth_data, authdata_elt_ptr); +DEFPTRTYPE(auth_data_ptr, auth_data); + +static const struct field_info encryption_key_fields[] = { + FIELDOF_NORM(krb5_keyblock, int32, enctype, 0), + FIELDOF_STRING(krb5_keyblock, octetstring, contents, length, 1), +}; +DEFSEQTYPE(encryption_key, krb5_keyblock, encryption_key_fields, 0); +DEFPTRTYPE(ptr_encryption_key, encryption_key); + +static const struct field_info checksum_fields[] = { + FIELDOF_NORM(krb5_checksum, int32, checksum_type, 0), + FIELDOF_STRING(krb5_checksum, octetstring, contents, length, 1), +}; +DEFSEQTYPE(checksum, krb5_checksum, checksum_fields, 0); +DEFPTRTYPE(checksum_ptr, checksum); +DEFNULLTERMSEQOFTYPE(seq_of_checksum, checksum_ptr); +DEFPTRTYPE(ptr_seqof_checksum, seq_of_checksum); + +static const struct field_info lr_fields[] = { + FIELDOF_NORM(krb5_last_req_entry, int32, lr_type, 0), + FIELDOF_NORM(krb5_last_req_entry, kerberos_time, value, 1), +}; +DEFSEQTYPE(last_req_ent, krb5_last_req_entry, lr_fields, 0); + +DEFPTRTYPE(last_req_ent_ptr, last_req_ent); +DEFNONEMPTYNULLTERMSEQOFTYPE(last_req, last_req_ent_ptr); +DEFPTRTYPE(last_req_ptr, last_req); + +static const struct field_info ticket_fields[] = { + FIELD_INT_IMM(KVNO, 0), + FIELDOF_NORM(krb5_ticket, realm_of_principal, server, 1), + FIELDOF_NORM(krb5_ticket, principal, server, 2), + FIELDOF_NORM(krb5_ticket, encrypted_data, enc_part, 3), +}; +DEFSEQTYPE(untagged_ticket, krb5_ticket, ticket_fields, 0); +DEFAPPTAGGEDTYPE(ticket, 1, untagged_ticket); + +DEFPTRTYPE(ticket_ptr, ticket); +DEFNONEMPTYNULLTERMSEQOFTYPE(seq_of_ticket,ticket_ptr); +DEFPTRTYPE(ptr_seqof_ticket, seq_of_ticket); + +/* EncKDCRepPart ::= SEQUENCE */ +static const struct field_info enc_kdc_rep_part_fields[] = { + /* key[0] EncryptionKey */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, ptr_encryption_key, session, 0), + /* last-req[1] LastReq */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, last_req_ptr, last_req, 1), + /* nonce[2] INTEGER */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, int32, nonce, 2), + /* key-expiration[3] KerberosTime OPTIONAL */ + FIELDOF_OPT(krb5_enc_kdc_rep_part, kerberos_time, key_exp, 3, 3), + /* flags[4] TicketFlags */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, krb5_flags, flags, 4), + /* authtime[5] KerberosTime */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, kerberos_time, times.authtime, 5), + /* starttime[6] KerberosTime OPTIONAL */ + FIELDOF_OPT(krb5_enc_kdc_rep_part, kerberos_time, times.starttime, 6, 6), + /* endtime[7] KerberosTime */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, kerberos_time, times.endtime, 7), + /* renew-till[8] KerberosTime OPTIONAL */ + FIELDOF_OPT(krb5_enc_kdc_rep_part, kerberos_time, times.renew_till, 8, 8), + /* srealm[9] Realm */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, realm_of_principal, server, 9), + /* sname[10] PrincipalName */ + FIELDOF_NORM(krb5_enc_kdc_rep_part, principal, server, 10), + /* caddr[11] HostAddresses OPTIONAL */ + FIELDOF_OPT(krb5_enc_kdc_rep_part, ptr_seqof_host_addresses, caddrs, + 11, 11), +}; +static unsigned int optional_enc_kdc_rep_part(const void *p) +{ + const krb5_enc_kdc_rep_part *val = p; + unsigned int optional = 0; - asn1_cleanup(); + if (val->key_exp) + optional |= (1u << 3); + if (val->times.starttime) + optional |= (1u << 6); + if (val->flags & TKT_FLG_RENEWABLE) + optional |= (1u << 8); + if (val->caddrs != NULL && val->caddrs[0] != NULL) + optional |= (1u << 11); + + return optional; +} +DEFSEQTYPE(enc_kdc_rep_part, krb5_enc_kdc_rep_part, enc_kdc_rep_part_fields, + optional_enc_kdc_rep_part); + +/* Yuck! Eventually push this *up* above the encoder API and make the + rest of the library put the realm name in one consistent place. At + the same time, might as well add the msg-type field and encode both + AS-REQ and TGS-REQ through the same descriptor. */ +struct kdc_req_hack { + krb5_kdc_req v; + krb5_data *server_realm; +}; +static const struct field_info kdc_req_hack_fields[] = { + FIELDOF_NORM(struct kdc_req_hack, krb5_flags, v.kdc_options, 0), + FIELDOF_OPT(struct kdc_req_hack, principal, v.client, 1, 1), + FIELDOF_NORM(struct kdc_req_hack, gstring_data_ptr, server_realm, 2), + FIELDOF_OPT(struct kdc_req_hack, principal, v.server, 3, 3), + FIELDOF_OPT(struct kdc_req_hack, kerberos_time, v.from, 4, 4), + FIELDOF_NORM(struct kdc_req_hack, kerberos_time, v.till, 5), + FIELDOF_OPT(struct kdc_req_hack, kerberos_time, v.rtime, 6, 6), + FIELDOF_NORM(struct kdc_req_hack, int32, v.nonce, 7), + FIELDOF_SEQOF_INT32(struct kdc_req_hack, int32_ptr, v.ktype, v.nktypes, 8), + FIELDOF_OPT(struct kdc_req_hack, ptr_seqof_host_addresses, v.addresses, 9, 9), + FIELDOF_OPT(struct kdc_req_hack, encrypted_data, v.authorization_data, 10, 10), + FIELDOF_OPT(struct kdc_req_hack, ptr_seqof_ticket, v.second_ticket, 11, 11), +}; +static unsigned int optional_kdc_req_hack(const void *p) +{ + const struct kdc_req_hack *val2 = p; + const krb5_kdc_req *val = &val2->v; + unsigned int optional = 0; + + if (val->second_ticket != NULL && val->second_ticket[0] != NULL) + optional |= (1u << 11); + if (val->authorization_data.ciphertext.data != NULL) + optional |= (1u << 10); + if (val->addresses != NULL && val->addresses[0] != NULL) + optional |= (1u << 9); + if (val->rtime) + optional |= (1u << 6); + if (val->from) + optional |= (1u << 4); + if (val->server != NULL) + optional |= (1u << 3); + if (val->client != NULL) + optional |= (1u << 1); + + return optional; +} +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) +{ + struct kdc_req_hack val2; + val2.v = *val; + if (val->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) { + if (val->second_ticket != NULL && val->second_ticket[0] != NULL) { + val2.server_realm = &val->second_ticket[0]->server->realm; + } else return ASN1_MISSING_FIELD; + } 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); } +DEFFNXTYPE(kdc_req_body, krb5_kdc_req, asn1_encode_kdc_req_body); +/* end ugly hack */ -asn1_error_code asn1_encode_kdc_rep(int msg_type, asn1buf *buf, const krb5_kdc_rep *val, unsigned int *retlen) -{ - asn1_setup(); +static const struct field_info transited_fields[] = { + FIELDOF_NORM(krb5_transited, octet, tr_type, 0), + FIELDOF_NORM(krb5_transited, ostring_data, tr_contents, 1), +}; +DEFSEQTYPE(transited, krb5_transited, transited_fields, 0); - if (val == NULL) return ASN1_MISSING_FIELD; +static const struct field_info pa_data_fields[] = { + FIELDOF_NORM(krb5_pa_data, int32, pa_type, 1), + FIELDOF_STRING(krb5_pa_data, octetstring, contents, length, 2), +}; +DEFSEQTYPE(pa_data, krb5_pa_data, pa_data_fields, 0); +DEFPTRTYPE(pa_data_ptr, pa_data); - asn1_addfield(&(val->enc_part),6,asn1_encode_encrypted_data); - asn1_addfield(val->ticket,5,asn1_encode_ticket); - asn1_addfield(val->client,4,asn1_encode_principal_name); - asn1_addfield(val->client,3,asn1_encode_realm); - if (val->padata != NULL && val->padata[0] != NULL) - asn1_addfield((const krb5_pa_data**)val->padata,2,asn1_encode_sequence_of_pa_data); - if (msg_type != KRB5_AS_REP && msg_type != KRB5_TGS_REP) - return KRB5_BADMSGTYPE; - asn1_addfield(msg_type,1,asn1_encode_integer); - asn1_addfield(KVNO,0,asn1_encode_integer); - asn1_makeseq(); +DEFNULLTERMSEQOFTYPE(seq_of_pa_data, pa_data_ptr); +DEFPTRTYPE(ptr_seqof_pa_data, seq_of_pa_data); - asn1_cleanup(); -} -asn1_error_code asn1_encode_enc_kdc_rep_part(asn1buf *buf, const krb5_enc_kdc_rep_part *val, unsigned int *retlen) +static const struct field_info krb_safe_body_fields[] = { + FIELDOF_NORM(krb5_safe, ostring_data, user_data, 0), + FIELDOF_OPT(krb5_safe, kerberos_time, timestamp, 1, 1), + FIELDOF_OPT(krb5_safe, int32, usec, 2, 2), + FIELDOF_OPT(krb5_safe, uint, seq_number, 3, 3), + FIELDOF_NORM(krb5_safe, address_ptr, s_address, 4), + FIELDOF_OPT(krb5_safe, address_ptr, r_address, 5, 5), +}; +static unsigned int optional_krb_safe_body(const void *p) { - asn1_setup(); + const krb5_safe *val = p; + unsigned int optional = 0; - if (val == NULL) return ASN1_MISSING_FIELD; + if (val->timestamp) { + optional |= (1u << 1); + optional |= (1u << 2); + } + if (val->seq_number) + optional |= (1u << 3); + if (val->r_address != NULL) + optional |= (1u << 5); + + return optional; +} +DEFSEQTYPE(krb_safe_body, krb5_safe, krb_safe_body_fields, + optional_krb_safe_body); + +static const struct field_info krb_cred_info_fields[] = { + FIELDOF_NORM(krb5_cred_info, ptr_encryption_key, session, 0), + FIELDOF_OPT(krb5_cred_info, realm_of_principal, client, 1, 1), + FIELDOF_OPT(krb5_cred_info, principal, client, 2, 2), + FIELDOF_OPT(krb5_cred_info, krb5_flags, flags, 3, 3), + FIELDOF_OPT(krb5_cred_info, kerberos_time, times.authtime, 4, 4), + FIELDOF_OPT(krb5_cred_info, kerberos_time, times.starttime, 5, 5), + FIELDOF_OPT(krb5_cred_info, kerberos_time, times.endtime, 6, 6), + FIELDOF_OPT(krb5_cred_info, kerberos_time, times.renew_till, 7, 7), + FIELDOF_OPT(krb5_cred_info, realm_of_principal, server, 8, 8), + FIELDOF_OPT(krb5_cred_info, principal, server, 9, 9), + FIELDOF_OPT(krb5_cred_info, ptr_seqof_host_addresses, caddrs, 10, 10), +}; +static unsigned int optional_krb_cred_info(const void *p) +{ + const krb5_cred_info *val = p; + unsigned int optional = 0; - /* caddr[11] HostAddresses OPTIONAL */ if (val->caddrs != NULL && val->caddrs[0] != NULL) - asn1_addfield((const krb5_address**)(val->caddrs),11,asn1_encode_host_addresses); - - /* sname[10] PrincipalName */ - asn1_addfield(val->server,10,asn1_encode_principal_name); - - /* srealm[9] Realm */ - asn1_addfield(val->server,9,asn1_encode_realm); - - /* renew-till[8] KerberosTime OPTIONAL */ - if (val->flags & TKT_FLG_RENEWABLE) - asn1_addfield(val->times.renew_till,8,asn1_encode_kerberos_time); - - /* endtime[7] KerberosTime */ - asn1_addfield(val->times.endtime,7,asn1_encode_kerberos_time); - - /* starttime[6] KerberosTime OPTIONAL */ + optional |= (1u << 10); + if (val->server != NULL) { + optional |= (1u << 9); + optional |= (1u << 8); + } + if (val->times.renew_till) + optional |= (1u << 7); + if (val->times.endtime) + optional |= (1u << 6); if (val->times.starttime) - asn1_addfield(val->times.starttime,6,asn1_encode_kerberos_time); - - /* authtime[5] KerberosTime */ - asn1_addfield(val->times.authtime,5,asn1_encode_kerberos_time); - - /* flags[4] TicketFlags */ - asn1_addfield(val->flags,4,asn1_encode_ticket_flags); - - /* key-expiration[3] KerberosTime OPTIONAL */ - if (val->key_exp) - asn1_addfield(val->key_exp,3,asn1_encode_kerberos_time); - - /* nonce[2] INTEGER */ - asn1_addfield(val->nonce,2,asn1_encode_integer); + optional |= (1u << 5); + if (val->times.authtime) + optional |= (1u << 4); + if (val->flags) + optional |= (1u << 3); + if (val->client != NULL) { + optional |= (1u << 2); + optional |= (1u << 1); + } - /* last-req[1] LastReq */ - asn1_addfield((const krb5_last_req_entry**)val->last_req,1,asn1_encode_last_req); + return optional; +} +DEFSEQTYPE(cred_info, krb5_cred_info, krb_cred_info_fields, + optional_krb_cred_info); +DEFPTRTYPE(cred_info_ptr, cred_info); +DEFNULLTERMSEQOFTYPE(seq_of_cred_info, cred_info_ptr); - /* key[0] EncryptionKey */ - asn1_addfield(val->session,0,asn1_encode_encryption_key); +DEFPTRTYPE(ptrseqof_cred_info, seq_of_cred_info); - /* EncKDCRepPart ::= SEQUENCE */ - asn1_makeseq(); - asn1_cleanup(); -} -asn1_error_code asn1_encode_sequence_of_checksum(asn1buf *buf, const krb5_checksum ** val, unsigned int *retlen) +static unsigned int +optional_etype_info_entry(const void *vptr) { - asn1_setup(); - int i; + const krb5_etype_info_entry *val = vptr; + unsigned int optional = 0; - if (val == NULL) return ASN1_MISSING_FIELD; + if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT) + optional |= (1u << 1); - for (i=0; val[i] != NULL; i++); - for (i--; i>=0; i--) { - retval = asn1_encode_checksum(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - - asn1_cleanup(); + return optional; } +static const struct field_info etype_info_entry_fields[] = { + FIELDOF_NORM(krb5_etype_info_entry, int32, etype, 0), + FIELDOF_OPTSTRING(krb5_etype_info_entry, octetstring, salt, length, 1, 1), +}; +DEFSEQTYPE(etype_info_entry, krb5_etype_info_entry, etype_info_entry_fields, + optional_etype_info_entry); -asn1_error_code asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *rep, unsigned int *retlen) +static unsigned int +optional_etype_info2_entry(const void *vptr) { - asn1_setup(); - - if (rep == NULL) return ASN1_MISSING_FIELD; + const krb5_etype_info_entry *val = vptr; + unsigned int optional = 0; - /* additional-tickets[11] SEQUENCE OF Ticket OPTIONAL */ - if (rep->second_ticket != NULL && rep->second_ticket[0] != NULL) - asn1_addfield((const krb5_ticket**)rep->second_ticket, - 11,asn1_encode_sequence_of_ticket); + if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT) + optional |= (1u << 1); + if (val->s2kparams.data) + optional |= (1u << 2); - /* enc-authorization-data[10] EncryptedData OPTIONAL, */ - /* -- Encrypted AuthorizationData encoding */ - if (rep->authorization_data.ciphertext.data != NULL) - asn1_addfield(&(rep->authorization_data),10,asn1_encode_encrypted_data); - - /* addresses[9] HostAddresses OPTIONAL, */ - if (rep->addresses != NULL && rep->addresses[0] != NULL) - asn1_addfield((const krb5_address**)rep->addresses,9,asn1_encode_host_addresses); - - /* etype[8] SEQUENCE OF INTEGER, -- EncryptionType, */ - /* -- in preference order */ - asn1_addlenfield(rep->nktypes,rep->ktype,8,asn1_encode_sequence_of_enctype); - - /* nonce[7] INTEGER, */ - asn1_addfield(rep->nonce,7,asn1_encode_integer); - - /* rtime[6] KerberosTime OPTIONAL, */ - if (rep->rtime) - asn1_addfield(rep->rtime,6,asn1_encode_kerberos_time); - - /* till[5] KerberosTime, */ - asn1_addfield(rep->till,5,asn1_encode_kerberos_time); + return optional; +} - /* from[4] KerberosTime OPTIONAL, */ - if (rep->from) - asn1_addfield(rep->from,4,asn1_encode_kerberos_time); +static const struct field_info etype_info2_entry_fields[] = { + FIELDOF_NORM(krb5_etype_info_entry, int32, etype, 0), + FIELDOF_OPTSTRING(krb5_etype_info_entry, u_generalstring, salt, length, + 1, 1), + FIELDOF_OPT(krb5_etype_info_entry, ostring_data, s2kparams, 2, 2), +}; +DEFSEQTYPE(etype_info2_entry, krb5_etype_info_entry, etype_info2_entry_fields, + optional_etype_info2_entry); - /* sname[3] PrincipalName OPTIONAL, */ - if (rep->server != NULL) - asn1_addfield(rep->server,3,asn1_encode_principal_name); +DEFPTRTYPE(etype_info_entry_ptr, etype_info_entry); +DEFNULLTERMSEQOFTYPE(etype_info, etype_info_entry_ptr); - /* realm[2] Realm, -- Server's realm */ - /* -- Also client's in AS-REQ */ - if (rep->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) { - if (rep->second_ticket != NULL && rep->second_ticket[0] != NULL) { - asn1_addfield(rep->second_ticket[0]->server,2,asn1_encode_realm) - } else return ASN1_MISSING_FIELD; - } else if (rep->server != NULL) { - asn1_addfield(rep->server,2,asn1_encode_realm); - } else return ASN1_MISSING_FIELD; +DEFPTRTYPE(etype_info2_entry_ptr, etype_info2_entry); +DEFNULLTERMSEQOFTYPE(etype_info2, etype_info2_entry_ptr); - /* cname[1] PrincipalName OPTIONAL, */ - /* -- Used only in AS-REQ */ - if (rep->client != NULL) - asn1_addfield(rep->client,1,asn1_encode_principal_name); +static const struct field_info passwdsequence_fields[] = { + FIELDOF_NORM(passwd_phrase_element, ostring_data_ptr, passwd, 0), + FIELDOF_NORM(passwd_phrase_element, ostring_data_ptr, phrase, 1), +}; +DEFSEQTYPE(passwdsequence, passwd_phrase_element, passwdsequence_fields, 0); - /* kdc-options[0] KDCOptions, */ - asn1_addfield(rep->kdc_options,0,asn1_encode_kdc_options); +DEFPTRTYPE(passwdsequence_ptr, passwdsequence); +DEFNONEMPTYNULLTERMSEQOFTYPE(seqof_passwdsequence, passwdsequence_ptr); +DEFPTRTYPE(ptr_seqof_passwdsequence, seqof_passwdsequence); - /* KDC-REQ-BODY ::= SEQUENCE */ - asn1_makeseq(); - - asn1_cleanup(); -} -asn1_error_code asn1_encode_encryption_key(asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen) +static const struct field_info sam_challenge_fields[] = { + FIELDOF_NORM(krb5_sam_challenge, int32, sam_type, 0), + FIELDOF_NORM(krb5_sam_challenge, krb5_flags, sam_flags, 1), + FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_type_name, 2, 2), + FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_track_id,3, 3), + FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_challenge_label,4, 4), + FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_challenge,5, 5), + FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_response_prompt,6, 6), + FIELDOF_OPT(krb5_sam_challenge, ostring_data, sam_pk_for_sad,7, 7), + FIELDOF_OPT(krb5_sam_challenge, int32, sam_nonce, 8, 8), + FIELDOF_OPT(krb5_sam_challenge, checksum, sam_cksum, 9, 9), +}; +static unsigned int optional_sam_challenge(const void *p) { - asn1_setup(); - - if (val == NULL || - (val->length && val->contents == NULL)) - return ASN1_MISSING_FIELD; - - asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring); - asn1_addfield(val->enctype,0,asn1_encode_integer); - asn1_makeseq(); + const krb5_sam_challenge *val = p; + unsigned int optional = 0; - asn1_cleanup(); -} - -asn1_error_code asn1_encode_checksum(asn1buf *buf, const krb5_checksum *val, unsigned int *retlen) -{ - asn1_setup(); + if (val->sam_cksum.length) + optional |= (1u << 9); - if (val == NULL || - (val->length && val->contents == NULL)) - return ASN1_MISSING_FIELD; + if (val->sam_nonce) + optional |= (1u << 8); - asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring); - asn1_addfield(val->checksum_type,0,asn1_encode_integer); - asn1_makeseq(); + if (val->sam_pk_for_sad.length > 0) optional |= (1u << 7); + if (val->sam_response_prompt.length > 0) optional |= (1u << 6); + if (val->sam_challenge.length > 0) optional |= (1u << 5); + if (val->sam_challenge_label.length > 0) optional |= (1u << 4); + if (val->sam_track_id.length > 0) optional |= (1u << 3); + if (val->sam_type_name.length > 0) optional |= (1u << 2); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(sam_challenge,krb5_sam_challenge,sam_challenge_fields, + optional_sam_challenge); -asn1_error_code asn1_encode_transited_encoding(asn1buf *buf, const krb5_transited *val, unsigned int *retlen) +#if 0 /* encoders not used! */ +MAKE_ENCFN(asn1_encode_sequence_of_checksum, seq_of_checksum); +static asn1_error_code +asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val, + unsigned int *retlen) { asn1_setup(); - - if (val == NULL || - (val->tr_contents.length != 0 && val->tr_contents.data == NULL)) + if ( (!val) || (!val->sam_cksum) || (!val->sam_cksum[0])) return ASN1_MISSING_FIELD; - asn1_addlenfield(val->tr_contents.length,val->tr_contents.data, - 1,asn1_encode_charstring); - asn1_addfield(val->tr_type,0,asn1_encode_integer); - asn1_makeseq(); - - asn1_cleanup(); -} - -asn1_error_code asn1_encode_last_req(asn1buf *buf, const krb5_last_req_entry **val, unsigned int *retlen) -{ - asn1_setup(); - int i; + asn1_addfield(val->sam_cksum, 1, asn1_encode_sequence_of_checksum); - if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD; + { + unsigned int length; - for (i=0; val[i] != NULL; i++); /* go to end of array */ - for (i--; i>=0; i--) { - retval = asn1_encode_last_req_entry(buf,val[i],&length); - if (retval) return retval; + retval = asn1buf_insert_octetstring(buf, val->sam_challenge_2_body.length, + (unsigned char *)val->sam_challenge_2_body.data); + if (retval) { + return retval; + } + sum += val->sam_challenge_2_body.length; + retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, + val->sam_challenge_2_body.length, &length); + if (retval) { + return retval; + } sum += length; } - asn1_makeseq(); - - asn1_cleanup(); -} -asn1_error_code asn1_encode_last_req_entry(asn1buf *buf, const krb5_last_req_entry *val, unsigned int *retlen) -{ - asn1_setup(); - - if (val == NULL) return ASN1_MISSING_FIELD; - - asn1_addfield(val->value,1,asn1_encode_kerberos_time); - asn1_addfield(val->lr_type,0,asn1_encode_integer); asn1_makeseq(); - asn1_cleanup(); } +DEFFNXTYPE(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), + FIELDOF_NORM(krb5_sam_challenge_2_body, krb5_flags, sam_flags, 1), + FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_type_name, 2, 2), + FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_track_id,3, 3), + FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_challenge_label,4, 4), + FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_challenge,5, 5), + FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_response_prompt,6, 6), + FIELDOF_OPT(krb5_sam_challenge_2_body, ostring_data, sam_pk_for_sad,7, 7), + FIELDOF_NORM(krb5_sam_challenge_2_body, int32, sam_nonce, 8), + FIELDOF_NORM(krb5_sam_challenge_2_body, int32, sam_etype, 9), +}; +static unsigned int optional_sam_challenge_2_body(const void *p) +{ + const krb5_sam_challenge_2_body *val = p; + unsigned int optional = 0; + + if (val->sam_pk_for_sad.length > 0) optional |= (1u << 7); + if (val->sam_response_prompt.length > 0) optional |= (1u << 6); + if (val->sam_challenge.length > 0) optional |= (1u << 5); + if (val->sam_challenge_label.length > 0) optional |= (1u << 4); + if (val->sam_track_id.length > 0) optional |= (1u << 3); + if (val->sam_type_name.length > 0) optional |= (1u << 2); + + return optional; +} +DEFSEQTYPE(sam_challenge_2_body,krb5_sam_challenge_2_body,sam_challenge_2_body_fields, + optional_sam_challenge_2_body); +#endif -asn1_error_code asn1_encode_sequence_of_pa_data(asn1buf *buf, const krb5_pa_data **val, unsigned int *retlen) -{ - asn1_setup(); - int i; - - if (val == NULL) return ASN1_MISSING_FIELD; - - for (i=0; val[i] != NULL; i++); - for (i--; i>=0; i--) { - retval = asn1_encode_pa_data(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - - asn1_cleanup(); -} +static const struct field_info sam_key_fields[] = { + FIELDOF_NORM(krb5_sam_key, encryption_key, sam_key, 0), +}; +DEFSEQTYPE(sam_key, krb5_sam_key, sam_key_fields, 0); -asn1_error_code asn1_encode_pa_data(asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen) +static const struct field_info enc_sam_response_enc_fields[] = { + FIELDOF_NORM(krb5_enc_sam_response_enc, int32, sam_nonce, 0), + FIELDOF_NORM(krb5_enc_sam_response_enc, kerberos_time, sam_timestamp, 1), + FIELDOF_NORM(krb5_enc_sam_response_enc, int32, sam_usec, 2), + FIELDOF_OPT(krb5_enc_sam_response_enc, ostring_data, sam_sad, 3, 3), +}; +static unsigned int optional_enc_sam_response_enc(const void *p) { - asn1_setup(); + const krb5_enc_sam_response_enc *val = p; + unsigned int optional = 0; - if (val == NULL || (val->length != 0 && val->contents == NULL)) - return ASN1_MISSING_FIELD; - - asn1_addlenfield(val->length,val->contents,2,asn1_encode_octetstring); - asn1_addfield(val->pa_type,1,asn1_encode_integer); - asn1_makeseq(); + if (val->sam_sad.length > 0) optional |= (1u << 3); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(enc_sam_response_enc, krb5_enc_sam_response_enc, + enc_sam_response_enc_fields, optional_enc_sam_response_enc); -asn1_error_code asn1_encode_sequence_of_ticket(asn1buf *buf, const krb5_ticket **val, unsigned int *retlen) +static const struct field_info enc_sam_response_enc_2_fields[] = { + FIELDOF_NORM(krb5_enc_sam_response_enc_2, int32, sam_nonce, 0), + FIELDOF_OPT(krb5_enc_sam_response_enc_2, ostring_data, sam_sad, 1, 1), +}; +static unsigned int optional_enc_sam_response_enc_2(const void *p) { - asn1_setup(); - int i; - - if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD; + const krb5_enc_sam_response_enc_2 *val = p; + unsigned int optional = 0; - for (i=0; val[i] != NULL; i++); - for (i--; i>=0; i--) { - retval = asn1_encode_ticket(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); + if (val->sam_sad.length > 0) optional |= (1u << 1); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(enc_sam_response_enc_2, krb5_enc_sam_response_enc_2, + enc_sam_response_enc_2_fields, optional_enc_sam_response_enc_2); -asn1_error_code asn1_encode_ticket(asn1buf *buf, const krb5_ticket *val, unsigned int *retlen) +static const struct field_info sam_response_fields[] = { + FIELDOF_NORM(krb5_sam_response, int32, sam_type, 0), + FIELDOF_NORM(krb5_sam_response, krb5_flags, sam_flags, 1), + FIELDOF_OPT(krb5_sam_response, ostring_data, sam_track_id, 2, 2), + FIELDOF_OPT(krb5_sam_response, encrypted_data, sam_enc_key, 3, 3), + FIELDOF_NORM(krb5_sam_response, encrypted_data, sam_enc_nonce_or_ts, 4), + FIELDOF_OPT(krb5_sam_response, int32, sam_nonce, 5, 5), + FIELDOF_OPT(krb5_sam_response, kerberos_time, sam_patimestamp, 6, 6), +}; +static unsigned int optional_sam_response(const void *p) { - asn1_setup(); - - if (val == NULL) return ASN1_MISSING_FIELD; + const krb5_sam_response *val = p; + unsigned int optional = 0; - asn1_addfield(&(val->enc_part),3,asn1_encode_encrypted_data); - asn1_addfield(val->server,2,asn1_encode_principal_name); - asn1_addfield(val->server,1,asn1_encode_realm); - asn1_addfield(KVNO,0,asn1_encode_integer); - asn1_makeseq(); - asn1_apptag(1); + if (val->sam_patimestamp) + optional |= (1u << 6); + if (val->sam_nonce) + optional |= (1u << 5); + if (val->sam_enc_key.ciphertext.length) + optional |= (1u << 3); + if (val->sam_track_id.length > 0) optional |= (1u << 2); + + return optional; +} +DEFSEQTYPE(sam_response, krb5_sam_response, sam_response_fields, + optional_sam_response); + +static const struct field_info sam_response_2_fields[] = { + FIELDOF_NORM(krb5_sam_response_2, int32, sam_type, 0), + FIELDOF_NORM(krb5_sam_response_2, krb5_flags, sam_flags, 1), + FIELDOF_OPT(krb5_sam_response_2, ostring_data, sam_track_id, 2, 2), + FIELDOF_NORM(krb5_sam_response_2, encrypted_data, sam_enc_nonce_or_sad, 3), + FIELDOF_NORM(krb5_sam_response_2, int32, sam_nonce, 4), +}; +static unsigned int optional_sam_response_2(const void *p) +{ + const krb5_sam_response_2 *val = p; + unsigned int optional = 0; + + if (val->sam_track_id.length > 0) optional |= (1u << 2); + + return optional; +} +DEFSEQTYPE(sam_response_2, krb5_sam_response_2, sam_response_2_fields, + optional_sam_response_2); + +static const struct field_info predicted_sam_response_fields[] = { + FIELDOF_NORM(krb5_predicted_sam_response, encryption_key, sam_key, 0), + FIELDOF_NORM(krb5_predicted_sam_response, krb5_flags, sam_flags, 1), + FIELDOF_NORM(krb5_predicted_sam_response, kerberos_time, stime, 2), + FIELDOF_NORM(krb5_predicted_sam_response, int32, susec, 3), + FIELDOF_NORM(krb5_predicted_sam_response, realm_of_principal, client, 4), + FIELDOF_NORM(krb5_predicted_sam_response, principal, client, 5), + FIELDOF_OPT(krb5_predicted_sam_response, ostring_data, msd, 6, 6), +}; +static unsigned int optional_predicted_sam_response(const void *p) +{ + const krb5_predicted_sam_response *val = p; + unsigned int optional = 0; + + if (val->msd.length > 0) optional |= (1u << 6); + + return optional; +} +DEFSEQTYPE(predicted_sam_response, krb5_predicted_sam_response, + predicted_sam_response_fields, + optional_predicted_sam_response); + +static const struct field_info krb5_authenticator_fields[] = { + /* Authenticator ::= [APPLICATION 2] SEQUENCE */ + /* authenticator-vno[0] INTEGER */ + FIELD_INT_IMM(KVNO, 0), + /* crealm[1] Realm */ + FIELDOF_NORM(krb5_authenticator, realm_of_principal, client, 1), + /* cname[2] PrincipalName */ + FIELDOF_NORM(krb5_authenticator, principal, client, 2), + /* cksum[3] Checksum OPTIONAL */ + FIELDOF_OPT(krb5_authenticator, checksum_ptr, checksum, 3, 3), + /* cusec[4] INTEGER */ + FIELDOF_NORM(krb5_authenticator, int32, cusec, 4), + /* ctime[5] KerberosTime */ + FIELDOF_NORM(krb5_authenticator, kerberos_time, ctime, 5), + /* subkey[6] EncryptionKey OPTIONAL */ + FIELDOF_OPT(krb5_authenticator, ptr_encryption_key, subkey, 6, 6), + /* seq-number[7] INTEGER OPTIONAL */ + FIELDOF_OPT(krb5_authenticator, uint, seq_number, 7, 7), + /* authorization-data[8] AuthorizationData OPTIONAL */ + FIELDOF_OPT(krb5_authenticator, auth_data_ptr, authorization_data, 8, 8), +}; +static unsigned int optional_krb5_authenticator(const void *p) +{ + const krb5_authenticator *val = p; + unsigned int optional = 0; + + if (val->authorization_data != NULL && val->authorization_data[0] != NULL) + optional |= (1u << 8); + + if (val->seq_number != 0) + optional |= (1u << 7); + + if (val->subkey != NULL) + optional |= (1u << 6); + + if (val->checksum != NULL) + optional |= (1u << 3); + + return optional; +} +DEFSEQTYPE(untagged_krb5_authenticator, krb5_authenticator, krb5_authenticator_fields, + optional_krb5_authenticator); +DEFAPPTAGGEDTYPE(krb5_authenticator, 2, untagged_krb5_authenticator); + +static const struct field_info enc_tkt_part_fields[] = { + /* EncTicketPart ::= [APPLICATION 3] SEQUENCE */ + /* flags[0] TicketFlags */ + FIELDOF_NORM(krb5_enc_tkt_part, krb5_flags, flags, 0), + /* key[1] EncryptionKey */ + FIELDOF_NORM(krb5_enc_tkt_part, ptr_encryption_key, session, 1), + /* crealm[2] Realm */ + FIELDOF_NORM(krb5_enc_tkt_part, realm_of_principal, client, 2), + /* cname[3] PrincipalName */ + FIELDOF_NORM(krb5_enc_tkt_part, principal, client, 3), + /* transited[4] TransitedEncoding */ + FIELDOF_NORM(krb5_enc_tkt_part, transited, transited, 4), + /* authtime[5] KerberosTime */ + FIELDOF_NORM(krb5_enc_tkt_part, kerberos_time, times.authtime, 5), + /* starttime[6] KerberosTime OPTIONAL */ + FIELDOF_OPT(krb5_enc_tkt_part, kerberos_time, times.starttime, 6, 6), + /* endtime[7] KerberosTime */ + FIELDOF_NORM(krb5_enc_tkt_part, kerberos_time, times.endtime, 7), + /* renew-till[8] KerberosTime OPTIONAL */ + FIELDOF_OPT(krb5_enc_tkt_part, kerberos_time, times.renew_till, 8, 8), + /* caddr[9] HostAddresses OPTIONAL */ + FIELDOF_OPT(krb5_enc_tkt_part, ptr_seqof_host_addresses, caddrs, 9, 9), + /* authorization-data[10] AuthorizationData OPTIONAL */ + FIELDOF_OPT(krb5_enc_tkt_part, auth_data_ptr, authorization_data, 10, 10), +}; +static unsigned int optional_enc_tkt_part(const void *p) +{ + const krb5_enc_tkt_part *val = p; + unsigned int optional = 0; + + if (val->authorization_data != NULL && val->authorization_data[0] != NULL) + optional |= (1u << 10); + if (val->caddrs != NULL && val->caddrs[0] != NULL) + optional |= (1u << 9); + if (val->times.renew_till) + optional |= (1u << 8); + if (val->times.starttime) + optional |= (1u << 6); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(untagged_enc_tkt_part, krb5_enc_tkt_part, enc_tkt_part_fields, + optional_enc_tkt_part); +DEFAPPTAGGEDTYPE(enc_tkt_part, 3, untagged_enc_tkt_part); -asn1_error_code asn1_encode_sequence_of_enctype(asn1buf *buf, const int len, const krb5_enctype *val, unsigned int *retlen) -{ - asn1_setup(); - int i; - - if (val == NULL) return ASN1_MISSING_FIELD; - - for (i=len-1; i>=0; i--) { - retval = asn1_encode_integer(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - - asn1_cleanup(); -} +DEFAPPTAGGEDTYPE(enc_tgs_rep_part, 26, enc_kdc_rep_part); -asn1_error_code asn1_encode_kdc_req(int msg_type, asn1buf *buf, const krb5_kdc_req *val, unsigned int *retlen) +static const struct field_info as_rep_fields[] = { + /* AS-REP ::= [APPLICATION 11] KDC-REP */ + /* But KDC-REP needs to know what type it's being encapsulated + in, so expand each version. */ + FIELD_INT_IMM(KVNO, 0), + FIELD_INT_IMM(KRB5_AS_REP, 1), + FIELDOF_OPT(krb5_kdc_rep, ptr_seqof_pa_data, padata, 2, 2), + FIELDOF_NORM(krb5_kdc_rep, realm_of_principal, client, 3), + FIELDOF_NORM(krb5_kdc_rep, principal, client, 4), + FIELDOF_NORM(krb5_kdc_rep, ticket_ptr, ticket, 5), + FIELDOF_NORM(krb5_kdc_rep, encrypted_data, enc_part, 6), +}; +static unsigned int optional_as_rep(const void *p) { - asn1_setup(); + const krb5_kdc_rep *val = p; + unsigned int optional = 0; - if (val == NULL) return ASN1_MISSING_FIELD; - - asn1_addfield(val,4,asn1_encode_kdc_req_body); if (val->padata != NULL && val->padata[0] != NULL) - asn1_addfield((const krb5_pa_data**)val->padata,3,asn1_encode_sequence_of_pa_data); - if (msg_type != KRB5_AS_REQ && msg_type != KRB5_TGS_REQ) - return KRB5_BADMSGTYPE; - asn1_addfield(msg_type,2,asn1_encode_integer); - asn1_addfield(KVNO,1,asn1_encode_integer); - asn1_makeseq(); + optional |= (1u << 2); + + return optional; +} +DEFSEQTYPE(untagged_as_rep, krb5_kdc_rep, as_rep_fields, optional_as_rep); +DEFAPPTAGGEDTYPE(as_rep, 11, untagged_as_rep); + +static const struct field_info tgs_rep_fields[] = { + /* TGS-REP ::= [APPLICATION 13] KDC-REP */ + /* But KDC-REP needs to know what type it's being encapsulated + in, so expand each version. */ + FIELD_INT_IMM(KVNO, 0), + FIELD_INT_IMM(KRB5_TGS_REP, 1), + FIELDOF_OPT(krb5_kdc_rep, ptr_seqof_pa_data, padata, 2, 2), + FIELDOF_NORM(krb5_kdc_rep, realm_of_principal, client, 3), + FIELDOF_NORM(krb5_kdc_rep, principal, client, 4), + FIELDOF_NORM(krb5_kdc_rep, ticket_ptr, ticket, 5), + FIELDOF_NORM(krb5_kdc_rep, encrypted_data, enc_part, 6), +}; +static unsigned int optional_tgs_rep(const void *p) +{ + const krb5_kdc_rep *val = p; + unsigned int optional = 0; - asn1_cleanup(); -} - -asn1_error_code asn1_encode_krb_safe_body(asn1buf *buf, const krb5_safe *val, unsigned int *retlen) -{ - asn1_setup(); - - if (val == NULL) return ASN1_MISSING_FIELD; + if (val->padata != NULL && val->padata[0] != NULL) + optional |= (1u << 2); + + return optional; +} +DEFSEQTYPE(untagged_tgs_rep, krb5_kdc_rep, tgs_rep_fields, optional_tgs_rep); +DEFAPPTAGGEDTYPE(tgs_rep, 13, untagged_tgs_rep); + +static const struct field_info ap_req_fields[] = { + /* AP-REQ ::= [APPLICATION 14] SEQUENCE */ + /* pvno[0] INTEGER */ + FIELD_INT_IMM(KVNO, 0), + /* msg-type[1] INTEGER */ + FIELD_INT_IMM(ASN1_KRB_AP_REQ, 1), + /* ap-options[2] APOptions */ + FIELDOF_NORM(krb5_ap_req, krb5_flags, ap_options, 2), + /* ticket[3] Ticket */ + FIELDOF_NORM(krb5_ap_req, ticket_ptr, ticket, 3), + /* authenticator[4] EncryptedData */ + FIELDOF_NORM(krb5_ap_req, encrypted_data, authenticator, 4), +}; +DEFSEQTYPE(untagged_ap_req, krb5_ap_req, ap_req_fields, 0); +DEFAPPTAGGEDTYPE(ap_req, 14, untagged_ap_req); + +static const struct field_info ap_rep_fields[] = { + /* AP-REP ::= [APPLICATION 15] SEQUENCE */ + /* pvno[0] INTEGER */ + FIELD_INT_IMM(KVNO, 0), + /* msg-type[1] INTEGER */ + FIELD_INT_IMM(ASN1_KRB_AP_REP, 1), + /* enc-part[2] EncryptedData */ + FIELDOF_NORM(krb5_ap_rep, encrypted_data, enc_part, 2), +}; +DEFSEQTYPE(untagged_ap_rep, krb5_ap_rep, ap_rep_fields, 0); +DEFAPPTAGGEDTYPE(ap_rep, 15, untagged_ap_rep); + +static const struct field_info ap_rep_enc_part_fields[] = { + /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE */ + /* ctime[0] KerberosTime */ + FIELDOF_NORM(krb5_ap_rep_enc_part, kerberos_time, ctime, 0), + /* cusec[1] INTEGER */ + FIELDOF_NORM(krb5_ap_rep_enc_part, int32, cusec, 1), + /* subkey[2] EncryptionKey OPTIONAL */ + FIELDOF_OPT(krb5_ap_rep_enc_part, ptr_encryption_key, subkey, 2, 2), + /* seq-number[3] INTEGER OPTIONAL */ + FIELDOF_OPT(krb5_ap_rep_enc_part, uint, seq_number, 3, 3), +}; +static unsigned int optional_ap_rep_enc_part(const void *p) +{ + const krb5_ap_rep_enc_part *val = p; + unsigned int optional = 0; - if (val->r_address != NULL) - asn1_addfield(val->r_address,5,asn1_encode_host_address); - asn1_addfield(val->s_address,4,asn1_encode_host_address); if (val->seq_number) - asn1_addfield(val->seq_number,3,asn1_encode_unsigned_integer); - if (val->timestamp) { - asn1_addfield(val->usec,2,asn1_encode_integer); - asn1_addfield(val->timestamp,1,asn1_encode_kerberos_time); - } - if (val->user_data.length && val->user_data.data == NULL) - return ASN1_MISSING_FIELD; - asn1_addlenfield(val->user_data.length,val->user_data.data,0,asn1_encode_charstring) - ; + optional |= (1u << 3); + if (val->subkey != NULL) + optional |= (1u << 2); - asn1_makeseq(); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(untagged_ap_rep_enc_part, krb5_ap_rep_enc_part, + ap_rep_enc_part_fields, optional_ap_rep_enc_part); +DEFAPPTAGGEDTYPE(ap_rep_enc_part, 27, untagged_ap_rep_enc_part); -asn1_error_code asn1_encode_sequence_of_krb_cred_info(asn1buf *buf, const krb5_cred_info **val, unsigned int *retlen) +static const struct field_info as_req_fields[] = { + /* AS-REQ ::= [APPLICATION 10] KDC-REQ */ + FIELD_INT_IMM(KVNO, 1), + FIELD_INT_IMM(KRB5_AS_REQ, 2), + FIELDOF_OPT(krb5_kdc_req, ptr_seqof_pa_data, padata, 3, 3), + FIELDOF_ENCODEAS(krb5_kdc_req, kdc_req_body, 4), +}; +static unsigned int optional_as_req(const void *p) { - asn1_setup(); - int i; + const krb5_kdc_req *val = p; + unsigned int optional = 0; - if (val == NULL) return ASN1_MISSING_FIELD; - - for (i=0; val[i] != NULL; i++); - for (i--; i>=0; i--) { - retval = asn1_encode_krb_cred_info(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); + if (val->padata != NULL && val->padata[0] != NULL) + optional |= (1u << 3); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(untagged_as_req, krb5_kdc_req, as_req_fields, optional_as_req); +DEFAPPTAGGEDTYPE(as_req, 10, untagged_as_req); -asn1_error_code asn1_encode_krb_cred_info(asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen) +static const struct field_info tgs_req_fields[] = { + /* TGS-REQ ::= [APPLICATION 12] KDC-REQ */ + FIELD_INT_IMM(KVNO, 1), + FIELD_INT_IMM(KRB5_TGS_REQ, 2), + FIELDOF_OPT(krb5_kdc_req, ptr_seqof_pa_data, padata, 3, 3), + FIELDOF_ENCODEAS(krb5_kdc_req, kdc_req_body, 4), +}; +static unsigned int optional_tgs_req(const void *p) { - asn1_setup(); + const krb5_kdc_req *val = p; + unsigned int optional = 0; - if (val == NULL) return ASN1_MISSING_FIELD; + if (val->padata != NULL && val->padata[0] != NULL) + optional |= (1u << 3); + + return optional; +} +DEFSEQTYPE(untagged_tgs_req, krb5_kdc_req, tgs_req_fields, + optional_tgs_req); +DEFAPPTAGGEDTYPE(tgs_req, 12, untagged_tgs_req); + +static const struct field_info krb5_safe_fields[] = { + FIELD_INT_IMM(KVNO, 0), + FIELD_INT_IMM(ASN1_KRB_SAFE,1), + FIELD_SELF(krb_safe_body, 2), + FIELDOF_NORM(krb5_safe, checksum_ptr, checksum, 3), +}; +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); +DEFFIELDTYPE(krb5_safe_checksum_only, krb5_safe, + FIELDOF_NORM(krb5_safe, checksum_ptr, checksum, -1)); +DEFPTRTYPE(krb5_safe_checksum_only_ptr, krb5_safe_checksum_only); +static const struct field_info krb5_safe_with_body_fields[] = { + FIELD_INT_IMM(KVNO, 0), + FIELD_INT_IMM(ASN1_KRB_SAFE,1), + FIELDOF_NORM(struct krb5_safe_with_body, krb_saved_safe_body_ptr, body, 2), + FIELDOF_NORM(struct krb5_safe_with_body, krb5_safe_checksum_only_ptr, safe, 3), +}; +DEFSEQTYPE(untagged_krb5_safe_with_body, struct krb5_safe_with_body, + krb5_safe_with_body_fields, 0); +DEFAPPTAGGEDTYPE(krb5_safe_with_body, 20, untagged_krb5_safe_with_body); + +static const struct field_info priv_fields[] = { + FIELD_INT_IMM(KVNO, 0), + FIELD_INT_IMM(ASN1_KRB_PRIV, 1), + FIELDOF_NORM(krb5_priv, encrypted_data, enc_part, 3), +}; +DEFSEQTYPE(untagged_priv, krb5_priv, priv_fields, 0); +DEFAPPTAGGEDTYPE(krb5_priv, 21, untagged_priv); + +static const struct field_info priv_enc_part_fields[] = { + FIELDOF_NORM(krb5_priv_enc_part, ostring_data, user_data, 0), + FIELDOF_OPT(krb5_priv_enc_part, kerberos_time, timestamp, 1, 1), + FIELDOF_OPT(krb5_priv_enc_part, int32, usec, 2, 2), + FIELDOF_OPT(krb5_priv_enc_part, uint, seq_number, 3, 3), + FIELDOF_NORM(krb5_priv_enc_part, address_ptr, s_address, 4), + FIELDOF_OPT(krb5_priv_enc_part, address_ptr, r_address, 5, 5), +}; +static unsigned int optional_priv_enc_part(const void *p) +{ + const krb5_priv_enc_part *val = p; + unsigned int optional = 0; - if (val->caddrs != NULL && val->caddrs[0] != NULL) - asn1_addfield((const krb5_address**)val->caddrs,10,asn1_encode_host_addresses); - if (val->server != NULL) { - asn1_addfield(val->server,9,asn1_encode_principal_name); - asn1_addfield(val->server,8,asn1_encode_realm); - } - if (val->times.renew_till) - asn1_addfield(val->times.renew_till,7,asn1_encode_kerberos_time); - if (val->times.endtime) - asn1_addfield(val->times.endtime,6,asn1_encode_kerberos_time); - if (val->times.starttime) - asn1_addfield(val->times.starttime,5,asn1_encode_kerberos_time); - if (val->times.authtime) - asn1_addfield(val->times.authtime,4,asn1_encode_kerberos_time); - if (val->flags) - asn1_addfield(val->flags,3,asn1_encode_ticket_flags); - if (val->client != NULL) { - asn1_addfield(val->client,2,asn1_encode_principal_name); - asn1_addfield(val->client,1,asn1_encode_realm); + if (val->timestamp) { + optional |= (1u << 2); + optional |= (1u << 1); } - asn1_addfield(val->session,0,asn1_encode_encryption_key); + if (val->seq_number) + optional |= (1u << 3); + if (val->r_address) + optional |= (1u << 5); + + return optional; +} +DEFSEQTYPE(untagged_priv_enc_part, krb5_priv_enc_part, priv_enc_part_fields, + optional_priv_enc_part); +DEFAPPTAGGEDTYPE(priv_enc_part, 28, untagged_priv_enc_part); + +static const struct field_info cred_fields[] = { + /* KRB-CRED ::= [APPLICATION 22] SEQUENCE */ + /* pvno[0] INTEGER */ + FIELD_INT_IMM(KVNO, 0), + /* msg-type[1] INTEGER, -- KRB_CRED */ + FIELD_INT_IMM(ASN1_KRB_CRED, 1), + /* tickets[2] SEQUENCE OF Ticket */ + FIELDOF_NORM(krb5_cred, ptr_seqof_ticket, tickets, 2), + /* enc-part[3] EncryptedData */ + FIELDOF_NORM(krb5_cred, encrypted_data, enc_part, 3), +}; +DEFSEQTYPE(untagged_cred, krb5_cred, cred_fields, 0); +DEFAPPTAGGEDTYPE(krb5_cred, 22, untagged_cred); + +static const struct field_info enc_cred_part_fields[] = { + /* EncKrbCredPart ::= [APPLICATION 29] SEQUENCE */ + /* ticket-info[0] SEQUENCE OF KrbCredInfo */ + FIELDOF_NORM(krb5_cred_enc_part, ptrseqof_cred_info, ticket_info, 0), + /* nonce[1] INTEGER OPTIONAL */ + FIELDOF_OPT(krb5_cred_enc_part, int32, nonce, 1, 1), + /* timestamp[2] KerberosTime OPTIONAL */ + FIELDOF_OPT(krb5_cred_enc_part, kerberos_time, timestamp, 2, 2), + /* usec[3] INTEGER OPTIONAL */ + FIELDOF_OPT(krb5_cred_enc_part, int32, usec, 3, 3), + /* s-address[4] HostAddress OPTIONAL */ + FIELDOF_OPT(krb5_cred_enc_part, address_ptr, s_address, 4, 4), + /* r-address[5] HostAddress OPTIONAL */ + FIELDOF_OPT(krb5_cred_enc_part, address_ptr, r_address, 5, 5), +}; +static unsigned int optional_enc_cred_part(const void *p) +{ + const krb5_cred_enc_part *val = p; + unsigned int optional = 0; - asn1_makeseq(); + if (val->r_address != NULL) + optional |= (1u << 5); - asn1_cleanup(); -} + if (val->s_address != NULL) + optional |= (1u << 4); -asn1_error_code asn1_encode_etype_info_entry(asn1buf *buf, const krb5_etype_info_entry *val, - unsigned int *retlen, int etype_info2) -{ - asn1_setup(); + if (val->timestamp) { + optional |= (1u << 2); + optional |= (1u << 3); + } - assert(val->s2kparams.data == NULL || etype_info2); - if (val == NULL || (val->length > 0 && val->length != KRB5_ETYPE_NO_SALT && - val->salt == NULL)) - return ASN1_MISSING_FIELD; - if (val->s2kparams.data != NULL) - asn1_addlenfield(val->s2kparams.length, val->s2kparams.data, 2, - asn1_encode_octetstring); - if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT) { - if (etype_info2) { - asn1_addlenfield(val->length,val->salt,1, - asn1_encode_generalstring); - } else { - asn1_addlenfield(val->length,val->salt,1, - asn1_encode_octetstring); - } + if (val->nonce) + optional |= (1u << 1); + + return optional; +} +DEFSEQTYPE(untagged_enc_cred_part, krb5_cred_enc_part, enc_cred_part_fields, + optional_enc_cred_part); +DEFAPPTAGGEDTYPE(enc_cred_part, 29, untagged_enc_cred_part); + +static const struct field_info error_fields[] = { + /* KRB-ERROR ::= [APPLICATION 30] SEQUENCE */ + /* pvno[0] INTEGER */ + FIELD_INT_IMM(KVNO, 0), + /* msg-type[1] INTEGER */ + FIELD_INT_IMM(ASN1_KRB_ERROR, 1), + /* ctime[2] KerberosTime OPTIONAL */ + FIELDOF_OPT(krb5_error, kerberos_time, ctime, 2, 2), + /* cusec[3] INTEGER OPTIONAL */ + FIELDOF_OPT(krb5_error, int32, cusec, 3, 3), + /* stime[4] KerberosTime */ + FIELDOF_NORM(krb5_error, kerberos_time, stime, 4), + /* susec[5] INTEGER */ + FIELDOF_NORM(krb5_error, int32, susec, 5), + /* error-code[6] INTEGER */ + FIELDOF_NORM(krb5_error, ui_4, error, 6), + /* crealm[7] Realm OPTIONAL */ + FIELDOF_OPT(krb5_error, realm_of_principal, client, 7, 7), + /* cname[8] PrincipalName OPTIONAL */ + FIELDOF_OPT(krb5_error, principal, client, 8, 8), + /* realm[9] Realm -- Correct realm */ + FIELDOF_NORM(krb5_error, realm_of_principal, server, 9), + /* sname[10] PrincipalName -- Correct name */ + FIELDOF_NORM(krb5_error, principal, server, 10), + /* e-text[11] GeneralString OPTIONAL */ + FIELDOF_OPT(krb5_error, gstring_data, text, 11, 11), + /* e-data[12] OCTET STRING OPTIONAL */ + FIELDOF_OPT(krb5_error, ostring_data, e_data, 12, 12), +}; +static unsigned int optional_error(const void *p) +{ + const krb5_error *val = p; + unsigned int optional = 0; + + if (val->ctime) + optional |= (1u << 2); + if (val->cusec) + optional |= (1u << 3); + if (val->client) { + optional |= (1u << 7); + optional |= (1u << 8); } - asn1_addfield(val->etype,0,asn1_encode_integer); - asn1_makeseq(); + if (val->text.data != NULL && val->text.length > 0) + optional |= (1u << 11); + if (val->e_data.data != NULL && val->e_data.length > 0) + optional |= (1u << 12); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(untagged_krb5_error, krb5_error, error_fields, optional_error); +DEFAPPTAGGEDTYPE(krb5_error, 30, untagged_krb5_error); -asn1_error_code asn1_encode_etype_info(asn1buf *buf, const krb5_etype_info_entry **val, - unsigned int *retlen, int etype_info2) +static const struct field_info alt_method_fields[] = { + FIELDOF_NORM(krb5_alt_method, int32, method, 0), + FIELDOF_OPTSTRING(krb5_alt_method, octetstring, data, length, 1, 1), +}; +static unsigned int +optional_alt_method(const void *p) { - asn1_setup(); - int i; + const krb5_alt_method *a = p; + unsigned int optional = 0; - if (val == NULL) return ASN1_MISSING_FIELD; + if (a->data != NULL && a->length > 0) + optional |= (1u << 1); - for (i=0; val[i] != NULL; i++); /* get to the end of the array */ - for (i--; i>=0; i--) { - retval = asn1_encode_etype_info_entry(buf,val[i],&length, etype_info2); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - asn1_cleanup(); + return optional; } +DEFSEQTYPE(alt_method, krb5_alt_method, alt_method_fields, optional_alt_method); -asn1_error_code asn1_encode_sequence_of_passwdsequence(asn1buf *buf, const passwd_phrase_element **val, unsigned int *retlen) +static const struct field_info pa_enc_ts_fields[] = { + FIELDOF_NORM(krb5_pa_enc_ts, kerberos_time, patimestamp, 0), + FIELDOF_OPT(krb5_pa_enc_ts, int32, pausec, 1, 1), +}; +static unsigned int +optional_pa_enc_ts(const void *p) { - asn1_setup(); - int i; - - if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD; - - for (i=0; val[i] != NULL; i++); /* get to the end of the array */ - for (i--; i>=0; i--) { - retval = asn1_encode_passwdsequence(buf,val[i],&length); - if (retval) return retval; - sum += length; - } - asn1_makeseq(); - asn1_cleanup(); -} + const krb5_pa_enc_ts *val = p; + unsigned int optional = 0; -asn1_error_code asn1_encode_passwdsequence(asn1buf *buf, const passwd_phrase_element *val, unsigned int *retlen) -{ - asn1_setup(); - asn1_addlenfield(val->phrase->length,val->phrase->data,1,asn1_encode_charstring); - asn1_addlenfield(val->passwd->length,val->passwd->data,0,asn1_encode_charstring); - asn1_makeseq(); - asn1_cleanup(); -} + if (val->pausec) + optional |= (1u << 1); -asn1_error_code asn1_encode_sam_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen) -{ - return asn1_encode_krb5_flags(buf,val,retlen); + return optional; } +DEFSEQTYPE(pa_enc_ts, krb5_pa_enc_ts, pa_enc_ts_fields, optional_pa_enc_ts); -#define add_optstring(val,n,fn) \ - if ((val).length > 0) {asn1_addlenfield((val).length,(val).data,n,fn);} - -asn1_error_code asn1_encode_sam_challenge(asn1buf *buf, const krb5_sam_challenge *val, unsigned int *retlen) -{ - asn1_setup(); - /* possibly wrong */ - if (val->sam_cksum.length) - asn1_addfield(&(val->sam_cksum),9,asn1_encode_checksum); - - if (val->sam_nonce) - asn1_addfield(val->sam_nonce,8,asn1_encode_integer); - - add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring); - add_optstring(val->sam_response_prompt,6,asn1_encode_charstring); - add_optstring(val->sam_challenge,5,asn1_encode_charstring); - add_optstring(val->sam_challenge_label,4,asn1_encode_charstring); - add_optstring(val->sam_track_id,3,asn1_encode_charstring); - add_optstring(val->sam_type_name,2,asn1_encode_charstring); - - asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags); - asn1_addfield(val->sam_type,0,asn1_encode_integer); +static const struct field_info pwd_data_fields[] = { + FIELDOF_NORM(krb5_pwd_data, int32, sequence_count, 0), + FIELDOF_NORM(krb5_pwd_data, ptr_seqof_passwdsequence, element, 1), +}; +DEFSEQTYPE(pwd_data, krb5_pwd_data, pwd_data_fields, 0); - asn1_makeseq(); - asn1_cleanup(); -} +static const struct field_info setpw_req_fields[] = { + FIELDOF_NORM(struct krb5_setpw_req, ostring_data, password, 0), + FIELDOF_NORM(struct krb5_setpw_req, principal, target, 1), + FIELDOF_NORM(struct krb5_setpw_req, realm_of_principal, target, 2), +}; -asn1_error_code asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val, unsigned int *retlen) -{ - asn1_setup(); - if ( (!val) || (!val->sam_cksum) || (!val->sam_cksum[0])) - return ASN1_MISSING_FIELD; +DEFSEQTYPE(setpw_req, struct krb5_setpw_req, setpw_req_fields, 0); - asn1_addfield((const krb5_checksum **) val->sam_cksum, 1, asn1_encode_sequence_of_checksum); - retval = asn1buf_insert_octetstring(buf, val->sam_challenge_2_body.length, - (unsigned char *)val->sam_challenge_2_body.data); - if (retval) { - asn1buf_destroy(&buf); - return retval; - } - sum += val->sam_challenge_2_body.length; - retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, - val->sam_challenge_2_body.length, &length); - if (retval) { - asn1buf_destroy(&buf); - return retval; - } - sum += length; - asn1_makeseq(); - asn1_cleanup(); -} -asn1_error_code asn1_encode_sam_challenge_2_body(asn1buf *buf, const krb5_sam_challenge_2_body *val, unsigned int *retlen) -{ - asn1_setup(); +/* Exported complete encoders -- these produce a krb5_data with + the encoding in the correct byte order. */ - asn1_addfield(val->sam_etype, 9, asn1_encode_integer); - asn1_addfield(val->sam_nonce,8,asn1_encode_integer); - add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring); - add_optstring(val->sam_response_prompt,6,asn1_encode_charstring); - add_optstring(val->sam_challenge,5,asn1_encode_charstring); - add_optstring(val->sam_challenge_label,4,asn1_encode_charstring); - add_optstring(val->sam_track_id,3,asn1_encode_charstring); - add_optstring(val->sam_type_name,2,asn1_encode_charstring); +MAKE_FULL_ENCODER(encode_krb5_authenticator, krb5_authenticator); +MAKE_FULL_ENCODER(encode_krb5_ticket, ticket); +MAKE_FULL_ENCODER(encode_krb5_encryption_key, encryption_key); +MAKE_FULL_ENCODER(encode_krb5_enc_tkt_part, enc_tkt_part); +/* XXX We currently (for backwards compatibility) encode both + EncASRepPart and EncTGSRepPart with application tag 26. */ +MAKE_FULL_ENCODER(encode_krb5_enc_kdc_rep_part, enc_tgs_rep_part); +MAKE_FULL_ENCODER(encode_krb5_as_rep, as_rep); +MAKE_FULL_ENCODER(encode_krb5_tgs_rep, tgs_rep); +MAKE_FULL_ENCODER(encode_krb5_ap_req, ap_req); +MAKE_FULL_ENCODER(encode_krb5_ap_rep, ap_rep); +MAKE_FULL_ENCODER(encode_krb5_ap_rep_enc_part, ap_rep_enc_part); +MAKE_FULL_ENCODER(encode_krb5_as_req, as_req); +MAKE_FULL_ENCODER(encode_krb5_tgs_req, tgs_req); +MAKE_FULL_ENCODER(encode_krb5_kdc_req_body, kdc_req_body); +MAKE_FULL_ENCODER(encode_krb5_safe, krb5_safe); - asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags); - asn1_addfield(val->sam_type,0,asn1_encode_integer); +/* + * encode_krb5_safe_with_body + * + * Like encode_krb5_safe(), except takes a saved KRB-SAFE-BODY + * encoding to avoid problems with re-encoding. + */ +MAKE_FULL_ENCODER(encode_krb5_safe_with_body, krb5_safe_with_body); + +MAKE_FULL_ENCODER(encode_krb5_priv, krb5_priv); +MAKE_FULL_ENCODER(encode_krb5_enc_priv_part, priv_enc_part); +MAKE_FULL_ENCODER(encode_krb5_cred, krb5_cred); +MAKE_FULL_ENCODER(encode_krb5_enc_cred_part, enc_cred_part); +MAKE_FULL_ENCODER(encode_krb5_error, krb5_error); +MAKE_FULL_ENCODER(encode_krb5_authdata, auth_data); +MAKE_FULL_ENCODER(encode_krb5_authdata_elt, authdata_elt); +MAKE_FULL_ENCODER(encode_krb5_alt_method, alt_method); +MAKE_FULL_ENCODER(encode_krb5_etype_info, etype_info); +MAKE_FULL_ENCODER(encode_krb5_etype_info2, etype_info2); +MAKE_FULL_ENCODER(encode_krb5_enc_data, encrypted_data); +MAKE_FULL_ENCODER(encode_krb5_pa_enc_ts, pa_enc_ts); +/* Sandia Additions */ +MAKE_FULL_ENCODER(encode_krb5_pwd_sequence, passwdsequence); +MAKE_FULL_ENCODER(encode_krb5_pwd_data, pwd_data); +MAKE_FULL_ENCODER(encode_krb5_padata_sequence, seq_of_pa_data); +/* sam preauth additions */ +MAKE_FULL_ENCODER(encode_krb5_sam_challenge, sam_challenge); +#if 0 /* encoders not used! */ +MAKE_FULL_ENCODER(encode_krb5_sam_challenge_2, sam_challenge_2); +MAKE_FULL_ENCODER(encode_krb5_sam_challenge_2_body, + sam_challenge_2_body); +#endif +MAKE_FULL_ENCODER(encode_krb5_sam_key, sam_key); +MAKE_FULL_ENCODER(encode_krb5_enc_sam_response_enc, + enc_sam_response_enc); +MAKE_FULL_ENCODER(encode_krb5_enc_sam_response_enc_2, + enc_sam_response_enc_2); +MAKE_FULL_ENCODER(encode_krb5_sam_response, sam_response); +MAKE_FULL_ENCODER(encode_krb5_sam_response_2, sam_response_2); +MAKE_FULL_ENCODER(encode_krb5_predicted_sam_response, + predicted_sam_response); +MAKE_FULL_ENCODER(encode_krb5_setpw_req, setpw_req); - asn1_makeseq(); - asn1_cleanup(); -} -asn1_error_code asn1_encode_sam_key(asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen) -{ - asn1_setup(); - asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key); - asn1_makeseq(); - asn1_cleanup(); -} -asn1_error_code asn1_encode_enc_sam_response_enc(asn1buf *buf, const krb5_enc_sam_response_enc *val, unsigned int *retlen) -{ - asn1_setup(); - add_optstring(val->sam_sad,3,asn1_encode_charstring); - asn1_addfield(val->sam_usec,2,asn1_encode_integer); - asn1_addfield(val->sam_timestamp,1,asn1_encode_kerberos_time); - asn1_addfield(val->sam_nonce,0,asn1_encode_integer); - asn1_makeseq(); - asn1_cleanup(); -} -asn1_error_code asn1_encode_enc_sam_response_enc_2(asn1buf *buf, const krb5_enc_sam_response_enc_2 *val, unsigned int *retlen) -{ - asn1_setup(); - add_optstring(val->sam_sad,1,asn1_encode_charstring); - asn1_addfield(val->sam_nonce,0,asn1_encode_integer); +#ifndef DISABLE_PKINIT +/* + * PKINIT + */ - asn1_makeseq(); +/* This code hasn't been converted to use the above framework yet, + because we currently have no test cases to validate the new + version. It *also* appears that some of the encodings may disagree + with the specifications, but that's a separate problem. */ - asn1_cleanup(); -} +/**** asn1 macros ****/ +#if 0 + How to write an asn1 encoder function using these macros: -asn1_error_code asn1_encode_sam_response(asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen) -{ - asn1_setup(); + asn1_error_code asn1_encode_krb5_substructure(asn1buf *buf, + const krb5_type *val, + int *retlen) + { + asn1_setup(); - if (val->sam_patimestamp) - asn1_addfield(val->sam_patimestamp,6,asn1_encode_kerberos_time); - if (val->sam_nonce) - asn1_addfield(val->sam_nonce,5,asn1_encode_integer); - asn1_addfield(&(val->sam_enc_nonce_or_ts),4,asn1_encode_encrypted_data); - if (val->sam_enc_key.ciphertext.length) - asn1_addfield(&(val->sam_enc_key),3,asn1_encode_encrypted_data); - add_optstring(val->sam_track_id,2,asn1_encode_charstring); - asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags); - asn1_addfield(val->sam_type,0,asn1_encode_integer); + asn1_addfield(val->last_field, n, asn1_type); + asn1_addfield(rep->next_to_last_field, n-1, asn1_type); + ... - asn1_makeseq(); + /* for OPTIONAL fields */ + if (rep->field_i == should_not_be_omitted) + asn1_addfield(rep->field_i, i, asn1_type); - asn1_cleanup(); -} + /* for string fields (these encoders take an additional argument, + the length of the string) */ + addlenfield(rep->field_length, rep->field, i-1, asn1_type); -asn1_error_code asn1_encode_sam_response_2(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen) -{ - asn1_setup(); + /* if you really have to do things yourself... */ + retval = asn1_encode_asn1_type(buf,rep->field,&length); + if (retval) return retval; + sum += length; + retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, tag_number, length, + &length); + if (retval) return retval; + sum += length; - asn1_addfield(val->sam_nonce,4,asn1_encode_integer); - asn1_addfield(&(val->sam_enc_nonce_or_sad),3,asn1_encode_encrypted_data); - add_optstring(val->sam_track_id,2,asn1_encode_charstring); - asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags); - asn1_addfield(val->sam_type,0,asn1_encode_integer); + ... + asn1_addfield(rep->second_field, 1, asn1_type); + asn1_addfield(rep->first_field, 0, asn1_type); + asn1_makeseq(); - asn1_makeseq(); + asn1_cleanup(); + } +#endif - asn1_cleanup(); -} +/* 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) {\ + asn1buf_destroy(&buf);\ + return retval; }\ + sum += length;\ + retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\ + if (retval) {\ + asn1buf_destroy(&buf);\ + return retval; }\ + sum += length; } -asn1_error_code asn1_encode_predicted_sam_response(asn1buf *buf, const krb5_predicted_sam_response *val, unsigned int *retlen) -{ - asn1_setup(); +/* asn1_addfield_implicit -- add an implicitly tagged field, or component, to the encoding */ +#define asn1_addfield_implicit(value,tag,encoder)\ +{ unsigned int length;\ + retval = encoder(buf,value,&length);\ + if (retval) {\ + return retval; }\ + sum += length;\ + retval = asn1_make_tag(buf,CONTEXT_SPECIFIC,PRIMITIVE,tag,length,&length); \ + if (retval) {\ + return retval; }\ + sum += length; } - add_optstring(val->msd,6,asn1_encode_charstring); - asn1_addfield(val->client,5,asn1_encode_principal_name); - asn1_addfield(val->client,4,asn1_encode_realm); - asn1_addfield(val->susec,3,asn1_encode_integer); - asn1_addfield(val->stime,2,asn1_encode_kerberos_time); - asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags); - asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key); +/* asn1_insert_implicit_octetstring -- add an octet string with implicit tagging */ +#define asn1_insert_implicit_octetstring(len,value,tag)\ +{ unsigned int length;\ + retval = asn1buf_insert_octetstring(buf,len,value);\ + if (retval) {\ + return retval; }\ + sum += len;\ + retval = asn1_make_tag(buf,CONTEXT_SPECIFIC,PRIMITIVE,tag,len,&length); \ + if (retval) {\ + return retval; }\ + sum += length; } - asn1_makeseq(); +/* asn1_insert_implicit_bitstring -- add a bitstring with implicit tagging */ +/* needs "length" declared in enclosing context */ +#define asn1_insert_implicit_bitstring(len,value,tag)\ +{ retval = asn1buf_insert_octetstring(buf,len,value); \ + if (retval) {\ + return retval; }\ + sum += len;\ + retval = asn1buf_insert_octet(buf, 0);\ + if (retval) {\ + return retval; }\ + sum++;\ + retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,tag,len+1,&length); \ + if (retval) {\ + return retval; }\ + sum += length; } - asn1_cleanup(); -} +/* Callable encoders for the types defined above, until the PKINIT + encoders get converted. */ +MAKE_ENCFN(asn1_encode_realm, realm_of_principal_data); +MAKE_ENCFN(asn1_encode_principal_name, principal_data); +MAKE_ENCFN(asn1_encode_encryption_key, encryption_key); +MAKE_ENCFN(asn1_encode_checksum, checksum); -/* - * Do some ugliness to insert a raw pre-encoded KRB-SAFE-BODY. - */ -asn1_error_code asn1_encode_krb_saved_safe_body(asn1buf *buf, const krb5_data *body, unsigned int *retlen) +static asn1_error_code +asn1_encode_kerberos_time(asn1buf *buf, const krb5_timestamp val, + unsigned int *retlen) { - asn1_error_code retval; - - retval = asn1buf_insert_octetstring(buf, body->length, - (krb5_octet *)body->data); - if (retval) { - asn1buf_destroy(&buf); - return retval; - } - *retlen = body->length; - return 0; + return asn1_encode_kerberos_time_at(buf,&val,retlen); } -#ifndef DISABLE_PKINIT -/* - * PKINIT - */ - +/* Now the real PKINIT encoder functions. */ asn1_error_code asn1_encode_pk_authenticator(asn1buf *buf, const krb5_pk_authenticator *val, unsigned int *retlen) { asn1_setup(); @@ -1053,15 +1366,18 @@ asn1_error_code asn1_encode_algorithm_identifier(asn1buf *buf, const krb5_algori sum += val->parameters.length; } - retval = asn1_encode_oid(buf, val->algorithm.length, - val->algorithm.data, - &length); + { + unsigned int length; + retval = asn1_encode_oid(buf, val->algorithm.length, + val->algorithm.data, + &length); - if (retval) { - asn1buf_destroy(&buf); - return retval; + if (retval) { + asn1buf_destroy(&buf); + return retval; + } + sum += length; } - sum += length; asn1_makeseq(); asn1_cleanup(); @@ -1071,9 +1387,14 @@ asn1_error_code asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_ { asn1_setup(); - asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,ASN1_BITSTRING); + { + unsigned int length; + asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,ASN1_BITSTRING); + } if (val->algorithm.parameters.length != 0) { + unsigned int length; + retval = asn1buf_insert_octetstring(buf, val->algorithm.parameters.length, val->algorithm.parameters.data); if (retval) { @@ -1081,27 +1402,28 @@ asn1_error_code asn1_encode_subject_pk_info(asn1buf *buf, const krb5_subject_pk_ return retval; } sum += val->algorithm.parameters.length; - } - retval = asn1_encode_oid(buf, val->algorithm.algorithm.length, - val->algorithm.algorithm.data, - &length); + retval = asn1_encode_oid(buf, val->algorithm.algorithm.length, + val->algorithm.algorithm.data, + &length); + + if (retval) { + asn1buf_destroy(&buf); + return retval; + } + sum += length; - if (retval) { - asn1buf_destroy(&buf); - return retval; - } - sum += length; - retval = asn1_make_etag(buf, UNIVERSAL, ASN1_SEQUENCE, - val->algorithm.parameters.length + length, - &length); + retval = asn1_make_etag(buf, UNIVERSAL, ASN1_SEQUENCE, + val->algorithm.parameters.length + length, + &length); - if (retval) { - asn1buf_destroy(&buf); - return retval; + if (retval) { + asn1buf_destroy(&buf); + return retval; + } + sum += length; } - sum += length; asn1_makeseq(); asn1_cleanup(); @@ -1116,6 +1438,7 @@ asn1_error_code asn1_encode_sequence_of_algorithm_identifier(asn1buf *buf, const for (i=0; val[i] != NULL; i++); for (i--; i>=0; i--) { + unsigned int length; retval = asn1_encode_algorithm_identifier(buf,val[i],&length); if (retval) return retval; sum += length; @@ -1183,6 +1506,7 @@ asn1_error_code asn1_encode_sequence_of_external_principal_identifier(asn1buf *b for (i=0; val[i] != NULL; i++); for (i--; i>=0; i--) { + unsigned int length; retval = asn1_encode_external_principal_identifier(buf,val[i],&length); if (retval) return retval; sum += length; @@ -1238,6 +1562,7 @@ asn1_error_code asn1_encode_sequence_of_trusted_ca(asn1buf *buf, const krb5_trus for (i=0; val[i] != NULL; i++); for (i--; i>=0; i--) { + unsigned int length; retval = asn1_encode_trusted_ca(buf,val[i],&length); if (retval) return retval; sum += length; @@ -1286,15 +1611,19 @@ asn1_error_code asn1_encode_kdc_dh_key_info(asn1buf *buf, const krb5_kdc_dh_key_ asn1_addfield(val->dhKeyExpiration, 2, asn1_encode_kerberos_time); asn1_addfield(val->nonce, 1, asn1_encode_integer); - asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,3); - retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, - val->subjectPublicKey.length + 1 + length, - &length); - if (retval) { - asn1buf_destroy(&buf); - return retval; + { + unsigned int length; + + asn1_insert_implicit_bitstring(val->subjectPublicKey.length,val->subjectPublicKey.data,3); + retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, + val->subjectPublicKey.length + 1 + length, + &length); + if (retval) { + asn1buf_destroy(&buf); + return retval; + } + sum += length; } - sum += length; asn1_makeseq(); asn1_cleanup(); @@ -1363,10 +1692,14 @@ asn1_error_code asn1_encode_pa_pk_as_rep_draft9(asn1buf *buf, const krb5_pa_pk_a asn1_error_code asn1_encode_td_trusted_certifiers(asn1buf *buf, const krb5_external_principal_identifier **val, unsigned int *retlen) { asn1_setup(); - retval = asn1_encode_sequence_of_external_principal_identifier(buf, val, &length); - if (retval) { - asn1buf_destroy(&buf); - return retval; + { + unsigned int length; + retval = asn1_encode_sequence_of_external_principal_identifier(buf, val, &length); + if (retval) { + asn1buf_destroy(&buf); + return retval; + } + /* length set but ignored? sum not updated? */ } asn1_cleanup(); } @@ -1380,6 +1713,8 @@ asn1_error_code asn1_encode_sequence_of_typed_data(asn1buf *buf, const krb5_type for (i=0; val[i] != NULL; i++); for (i--; i>=0; i--) { + unsigned int length; + retval = asn1_encode_typed_data(buf,val[i],&length); if (retval) return retval; sum += length; diff --git a/src/lib/krb5/asn.1/asn1_k_encode.h b/src/lib/krb5/asn.1/asn1_k_encode.h index 7ec2b06..94b8f7b 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.h +++ b/src/lib/krb5/asn.1/asn1_k_encode.h @@ -2,7 +2,7 @@ /* * src/lib/krb5/asn.1/asn1_k_encode.h * - * Copyright 1994 by the Massachusetts Institute of Technology. + * Copyright 1994, 2008 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -33,48 +33,6 @@ #include "asn1buf.h" /* - Overview - - Encoding routines for various ASN.1 "substructures" as defined in - the krb5 protocol. - - Operations - - asn1_encode_krb5_flags - asn1_encode_ap_options - asn1_encode_ticket_flags - asn1_encode_kdc_options - asn1_encode_kerberos_time - - asn1_encode_realm - asn1_encode_principal_name - asn1_encode_encrypted_data - asn1_encode_authorization_data - asn1_encode_krb5_authdata_elt - asn1_encode_kdc_rep - asn1_encode_ticket - asn1_encode_encryption_key - asn1_encode_checksum - asn1_encode_host_address - asn1_encode_transited_encoding - asn1_encode_enc_kdc_rep_part - asn1_encode_kdc_req - asn1_encode_kdc_req_body - asn1_encode_krb_safe_body - asn1_encode_krb_cred_info - asn1_encode_last_req_entry - asn1_encode_pa_data - - asn1_encode_host_addresses - asn1_encode_last_req - asn1_encode_sequence_of_pa_data - asn1_encode_sequence_of_ticket - asn1_encode_sequence_of_enctype - asn1_encode_sequence_of_checksum - asn1_encode_sequence_of_krb_cred_info -*/ - -/* **** for simple val's **** asn1_error_code asn1_encode_asn1_type(asn1buf *buf, const krb5_type val, @@ -107,169 +65,6 @@ asn1_error_code asn1_encode_asn1_type(asn1buf *buf, Returns ENOMEM if memory runs out. */ -asn1_error_code asn1_encode_ui_4 (asn1buf *buf, - const krb5_ui_4 val, - unsigned int *retlen); - -asn1_error_code asn1_encode_msgtype (asn1buf *buf, - const /*krb5_msgtype*/int val, - unsigned int *retlen); - -asn1_error_code asn1_encode_realm - (asn1buf *buf, const krb5_principal val, unsigned int *retlen); - -asn1_error_code asn1_encode_principal_name - (asn1buf *buf, const krb5_principal val, unsigned int *retlen); - -asn1_error_code asn1_encode_encrypted_data - (asn1buf *buf, const krb5_enc_data *val, unsigned int *retlen); - -asn1_error_code asn1_encode_krb5_flags - (asn1buf *buf, const krb5_flags val, unsigned int *retlen); - -asn1_error_code asn1_encode_ap_options - (asn1buf *buf, const krb5_flags val, unsigned int *retlen); - -asn1_error_code asn1_encode_ticket_flags - (asn1buf *buf, const krb5_flags val, unsigned int *retlen); - -asn1_error_code asn1_encode_kdc_options - (asn1buf *buf, const krb5_flags val, unsigned int *retlen); - -asn1_error_code asn1_encode_authorization_data - (asn1buf *buf, const krb5_authdata **val, unsigned int *retlen); - -asn1_error_code asn1_encode_krb5_authdata_elt - (asn1buf *buf, const krb5_authdata *val, unsigned int *retlen); - -asn1_error_code asn1_encode_kdc_rep - (int msg_type, asn1buf *buf, const krb5_kdc_rep *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_enc_kdc_rep_part - (asn1buf *buf, const krb5_enc_kdc_rep_part *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_ticket - (asn1buf *buf, const krb5_ticket *val, unsigned int *retlen); - -asn1_error_code asn1_encode_encryption_key - (asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen); - -asn1_error_code asn1_encode_kerberos_time - (asn1buf *buf, const krb5_timestamp val, unsigned int *retlen); - -asn1_error_code asn1_encode_checksum - (asn1buf *buf, const krb5_checksum *val, unsigned int *retlen); - -asn1_error_code asn1_encode_host_address - (asn1buf *buf, const krb5_address *val, unsigned int *retlen); - -asn1_error_code asn1_encode_host_addresses - (asn1buf *buf, const krb5_address **val, unsigned int *retlen); - -asn1_error_code asn1_encode_transited_encoding - (asn1buf *buf, const krb5_transited *val, unsigned int *retlen); - -asn1_error_code asn1_encode_last_req - (asn1buf *buf, const krb5_last_req_entry **val, - unsigned int *retlen); - -asn1_error_code asn1_encode_sequence_of_pa_data - (asn1buf *buf, const krb5_pa_data **val, unsigned int *retlen); - -asn1_error_code asn1_encode_sequence_of_ticket - (asn1buf *buf, const krb5_ticket **val, unsigned int *retlen); - -asn1_error_code asn1_encode_sequence_of_enctype - (asn1buf *buf, - const int len, const krb5_enctype *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_sequence_of_checksum - (asn1buf *buf, const krb5_checksum **val, unsigned int *retlen); - -asn1_error_code asn1_encode_kdc_req - (int msg_type, - asn1buf *buf, - const krb5_kdc_req *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_kdc_req_body - (asn1buf *buf, const krb5_kdc_req *val, unsigned int *retlen); - -asn1_error_code asn1_encode_krb_safe_body - (asn1buf *buf, const krb5_safe *val, unsigned int *retlen); - -asn1_error_code asn1_encode_sequence_of_krb_cred_info - (asn1buf *buf, const krb5_cred_info **val, unsigned int *retlen); - -asn1_error_code asn1_encode_krb_cred_info - (asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen); - -asn1_error_code asn1_encode_last_req_entry - (asn1buf *buf, const krb5_last_req_entry *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_pa_data - (asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen); - -asn1_error_code asn1_encode_alt_method - (asn1buf *buf, const krb5_alt_method *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_etype_info_entry - (asn1buf *buf, const krb5_etype_info_entry *val, - unsigned int *retlen, int etype_info2); - -asn1_error_code asn1_encode_etype_info - (asn1buf *buf, const krb5_etype_info_entry **val, - unsigned int *retlen, int etype_info2); - -asn1_error_code asn1_encode_passwdsequence - (asn1buf *buf, const passwd_phrase_element *val, unsigned int *retlen); - -asn1_error_code asn1_encode_sequence_of_passwdsequence - (asn1buf *buf, const passwd_phrase_element **val, - unsigned int *retlen); - -asn1_error_code asn1_encode_sam_flags - (asn1buf * buf, const krb5_flags val, unsigned int *retlen); - -asn1_error_code asn1_encode_sam_challenge - (asn1buf *buf, const krb5_sam_challenge * val, unsigned int *retlen); - -asn1_error_code asn1_encode_sam_challenge_2 - (asn1buf *buf, const krb5_sam_challenge_2 * val, unsigned int *retlen); - -asn1_error_code asn1_encode_sam_challenge_2_body - (asn1buf *buf, const krb5_sam_challenge_2_body * val, - unsigned int *retlen); - -asn1_error_code asn1_encode_sam_key - (asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen); - -asn1_error_code asn1_encode_enc_sam_response_enc - (asn1buf *buf, const krb5_enc_sam_response_enc *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_enc_sam_response_enc_2 - (asn1buf *buf, const krb5_enc_sam_response_enc_2 *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_sam_response - (asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen); - -asn1_error_code asn1_encode_sam_response_2 - (asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen); - -asn1_error_code asn1_encode_predicted_sam_response - (asn1buf *buf, const krb5_predicted_sam_response *val, - unsigned int *retlen); - -asn1_error_code asn1_encode_krb_saved_safe_body - (asn1buf *buf, const krb5_data *body, unsigned int *retlen); - /* PKINIT */ asn1_error_code asn1_encode_pk_authenticator @@ -337,4 +132,5 @@ asn1_error_code asn1_encode_typed_data asn1_error_code asn1_encode_sequence_of_typed_data (asn1buf *buf, const krb5_typed_data **val, unsigned int *retlen); + #endif diff --git a/src/lib/krb5/asn.1/asn1buf.c b/src/lib/krb5/asn.1/asn1buf.c index 4162c9e..0779bfd 100644 --- a/src/lib/krb5/asn.1/asn1buf.c +++ b/src/lib/krb5/asn.1/asn1buf.c @@ -117,7 +117,7 @@ asn1_error_code asn1buf_skiptail(asn1buf *buf, const unsigned int length, const nestlevel = 1 + indef; if (!indef) { - if (length <= buf->bound - buf->next + 1) + if (length <= (size_t)(buf->bound - buf->next + 1)) buf->next += length; else return ASN1_OVERRUN; @@ -128,7 +128,7 @@ asn1_error_code asn1buf_skiptail(asn1buf *buf, const unsigned int length, const retval = asn1_get_tag_2(buf, &t); if (retval) return retval; if (!t.indef) { - if (t.length <= buf->bound - buf->next + 1) + if (t.length <= (size_t)(buf->bound - buf->next + 1)) buf->next += t.length; else return ASN1_OVERRUN; @@ -165,29 +165,20 @@ asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o) return 0; } -asn1_error_code asn1buf_insert_octetstring(asn1buf *buf, const unsigned int len, const krb5_octet *s) +asn1_error_code +asn1buf_insert_bytestring(asn1buf *buf, const unsigned int len, const void *sv) { asn1_error_code retval; unsigned int length; + const char *s = sv; retval = asn1buf_ensure_space(buf,len); if (retval) return retval; for (length=1; length<=len; length++,(buf->next)++) - *(buf->next) = (char)(s[len-length]); + *(buf->next) = (s[len-length]); return 0; } -asn1_error_code asn1buf_insert_charstring(asn1buf *buf, const unsigned int len, const char *s) -{ - asn1_error_code retval; - unsigned int length; - - retval = asn1buf_ensure_space(buf,len); - if (retval) return retval; - for (length=1; length<=len; length++,(buf->next)++) - *(buf->next) = (char)(s[len-length]); - return 0; -} #undef asn1buf_remove_octet asn1_error_code asn1buf_remove_octet(asn1buf *buf, asn1_octet *o) @@ -201,7 +192,7 @@ asn1_error_code asn1buf_remove_octetstring(asn1buf *buf, const unsigned int len, { unsigned int i; - if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN; + if (len > (size_t)(buf->bound + 1 - buf->next)) return ASN1_OVERRUN; if (len == 0) { *s = 0; return 0; @@ -219,7 +210,7 @@ asn1_error_code asn1buf_remove_charstring(asn1buf *buf, const unsigned int len, { unsigned int i; - if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN; + if (len > (size_t)(buf->bound + 1 - buf->next)) return ASN1_OVERRUN; if (len == 0) { *s = 0; return 0; @@ -344,7 +335,7 @@ unsigned int asn1buf_free(const asn1buf *buf) #undef asn1buf_ensure_space asn1_error_code asn1buf_ensure_space(asn1buf *buf, const unsigned int amount) { - int avail = asn1buf_free(buf); + unsigned int avail = asn1buf_free(buf); if (avail < amount) { asn1_error_code retval = asn1buf_expand(buf, amount-avail); if (retval) return retval; diff --git a/src/lib/krb5/asn.1/asn1buf.h b/src/lib/krb5/asn.1/asn1buf.h index c492076..33578f9 100644 --- a/src/lib/krb5/asn.1/asn1buf.h +++ b/src/lib/krb5/asn.1/asn1buf.h @@ -162,21 +162,16 @@ extern __inline__ asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o } #endif -asn1_error_code asn1buf_insert_octetstring - (asn1buf *buf, const unsigned int len, const asn1_octet *s); +asn1_error_code asn1buf_insert_bytestring + (asn1buf *buf, const unsigned int len, const void *s); /* requires *buf is allocated modifies *buf - effects Inserts the contents of s (an octet array of length len) + effects Inserts the contents of s (an array of length len) into the buffer *buf, expanding the buffer if necessary. Returns ENOMEM if memory is exhausted. */ -asn1_error_code asn1buf_insert_charstring - (asn1buf *buf, const unsigned int len, const char *s); -/* requires *buf is allocated - modifies *buf - effects Inserts the contents of s (a character array of length len) - into the buffer *buf, expanding the buffer if necessary. - Returns ENOMEM if memory is exhausted. */ +#define asn1buf_insert_octetstring asn1buf_insert_bytestring +#define asn1buf_insert_charstring asn1buf_insert_bytestring asn1_error_code asn1buf_remove_octet (asn1buf *buf, asn1_octet *o); diff --git a/src/lib/krb5/asn.1/krb5_encode.c b/src/lib/krb5/asn.1/krb5_encode.c index 7efbbae..a6fa305 100644 --- a/src/lib/krb5/asn.1/krb5_encode.c +++ b/src/lib/krb5/asn.1/krb5_encode.c @@ -34,47 +34,7 @@ /**************** Macros (these save a lot of typing) ****************/ -/**** krb5 macros ****/ -#if 0 - How to write a krb5 encoder function using these macros: - - asn1_error_code encode_krb5_structure(const krb5_type *rep, - krb5_data **code) - { - krb5_setup(); - - krb5_addfield(rep->last_field, n, asn1_type); - krb5_addfield(rep->next_to_last_field, n-1, asn1_type); - ... - - /* for OPTIONAL fields */ - if (rep->field_i == should_not_be_omitted) - krb5_addfield(rep->field_i, i, asn1_type); - - /* for string fields (these encoders take an additional argument, - the length of the string) */ - addlenfield(rep->field_length, rep->field, i-1, asn1_type); - - /* if you really have to do things yourself... */ - retval = asn1_encode_asn1_type(buf,rep->field,&length); - if (retval) return retval; - sum += length; - retval = asn1_make_etag(buf, - [UNIVERSAL/APPLICATION/CONTEXT_SPECIFIC/PRIVATE], - tag_number, length, &length); - if (retval) return retval; - sum += length; - - ... - krb5_addfield(rep->second_field, 1, asn1_type); - krb5_addfield(rep->first_field, 0, asn1_type); - krb5_makeseq(); - krb5_apptag(tag_number); - - krb5_cleanup(); - } -#endif - +#ifndef DISABLE_PKINIT /* setup() -- create and initialize bookkeeping variables retval: stores error codes returned from subroutines buf: the coding buffer @@ -82,56 +42,14 @@ sum: cumulative length of the entire encoding */ #define krb5_setup()\ asn1_error_code retval;\ + unsigned int length, sum = 0;\ asn1buf *buf=NULL;\ - unsigned int length, sum=0;\ \ if (rep == NULL) return ASN1_MISSING_FIELD;\ \ retval = asn1buf_create(&buf);\ if (retval) return retval -/* krb5_addfield -- add a field, or component, to the encoding */ -#define krb5_addfield(value,tag,encoder)\ -{ retval = encoder(buf,value,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length;\ - retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length; } - -/* krb5_addlenfield -- add a field whose length must be separately specified */ -#define krb5_addlenfield(len,value,tag,encoder)\ -{ retval = encoder(buf,len,value,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length;\ - retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length; } - -/* form a sequence (by adding a sequence header to the current encoding) */ -#define krb5_makeseq()\ - retval = asn1_make_sequence(buf,sum,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length - -/* add an APPLICATION class tag to the current encoding */ -#define krb5_apptag(num)\ - retval = asn1_make_etag(buf,APPLICATION,num,sum,&length);\ - if (retval) {\ - asn1buf_destroy(&buf);\ - return retval; }\ - sum += length - /* produce the final output and clean up the workspace */ #define krb5_cleanup()\ retval = asn12krb5_buf(buf,code);\ @@ -144,769 +62,6 @@ \ return 0 -krb5_error_code encode_krb5_authenticator(const krb5_authenticator *rep, krb5_data **code) -{ - krb5_setup(); - - /* authorization-data[8] AuthorizationData OPTIONAL */ - if (rep->authorization_data != NULL && - rep->authorization_data[0] != NULL) { - retval = asn1_encode_authorization_data(buf, (const krb5_authdata **) - rep->authorization_data, - &length); - if (retval) { - asn1buf_destroy(&buf); - return retval; } - sum += length; - retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,8,length,&length); - if (retval) { - asn1buf_destroy(&buf); - return retval; } - sum += length; - } - - /* seq-number[7] INTEGER OPTIONAL */ - if (rep->seq_number != 0) - krb5_addfield(rep->seq_number,7,asn1_encode_unsigned_integer); - - /* subkey[6] EncryptionKey OPTIONAL */ - if (rep->subkey != NULL) - krb5_addfield(rep->subkey,6,asn1_encode_encryption_key); - - /* ctime[5] KerberosTime */ - krb5_addfield(rep->ctime,5,asn1_encode_kerberos_time); - - /* cusec[4] INTEGER */ - krb5_addfield(rep->cusec,4,asn1_encode_integer); - - /* cksum[3] Checksum OPTIONAL */ - if (rep->checksum != NULL) - krb5_addfield(rep->checksum,3,asn1_encode_checksum); - - /* cname[2] PrincipalName */ - krb5_addfield(rep->client,2,asn1_encode_principal_name); - - /* crealm[1] Realm */ - krb5_addfield(rep->client,1,asn1_encode_realm); - - /* authenticator-vno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* Authenticator ::= [APPLICATION 2] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(2); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code) -{ - krb5_setup(); - - /* enc-part[3] EncryptedData */ - krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data); - - /* sname [2] PrincipalName */ - krb5_addfield(rep->server,2,asn1_encode_principal_name); - - /* realm [1] Realm */ - krb5_addfield(rep->server,1,asn1_encode_realm); - - /* tkt-vno [0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* Ticket ::= [APPLICATION 1] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(1); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_encryption_key(const krb5_keyblock *rep, krb5_data **code) -{ - krb5_setup(); - - /* keyvalue[1] OCTET STRING */ - krb5_addlenfield(rep->length,rep->contents,1,asn1_encode_octetstring); - - /* enctype[0] INTEGER */ - krb5_addfield(rep->enctype,0,asn1_encode_integer); - - /* EncryptionKey ::= SEQUENCE */ - krb5_makeseq(); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_enc_tkt_part(const krb5_enc_tkt_part *rep, krb5_data **code) -{ - krb5_setup(); - - /* authorization-data[10] AuthorizationData OPTIONAL */ - if (rep->authorization_data != NULL && - rep->authorization_data[0] != NULL) - krb5_addfield((const krb5_authdata**)rep->authorization_data, - 10,asn1_encode_authorization_data); - - /* caddr[9] HostAddresses OPTIONAL */ - if (rep->caddrs != NULL && rep->caddrs[0] != NULL) - krb5_addfield((const krb5_address**)rep->caddrs,9,asn1_encode_host_addresses); - - /* renew-till[8] KerberosTime OPTIONAL */ - if (rep->times.renew_till) - krb5_addfield(rep->times.renew_till,8,asn1_encode_kerberos_time); - - /* endtime[7] KerberosTime */ - krb5_addfield(rep->times.endtime,7,asn1_encode_kerberos_time); - - /* starttime[6] KerberosTime OPTIONAL */ - if (rep->times.starttime) - krb5_addfield(rep->times.starttime,6,asn1_encode_kerberos_time); - - /* authtime[5] KerberosTime */ - krb5_addfield(rep->times.authtime,5,asn1_encode_kerberos_time); - - /* transited[4] TransitedEncoding */ - krb5_addfield(&(rep->transited),4,asn1_encode_transited_encoding); - - /* cname[3] PrincipalName */ - krb5_addfield(rep->client,3,asn1_encode_principal_name); - - /* crealm[2] Realm */ - krb5_addfield(rep->client,2,asn1_encode_realm); - - /* key[1] EncryptionKey */ - krb5_addfield(rep->session,1,asn1_encode_encryption_key); - - /* flags[0] TicketFlags */ - krb5_addfield(rep->flags,0,asn1_encode_ticket_flags); - - /* EncTicketPart ::= [APPLICATION 3] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(3); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_enc_kdc_rep_part(const krb5_enc_kdc_rep_part *rep, krb5_data **code) -{ - asn1_error_code retval; - asn1buf *buf=NULL; - unsigned int length, sum=0; - - if (rep == NULL) return ASN1_MISSING_FIELD; - - retval = asn1buf_create(&buf); - if (retval) return retval; - - retval = asn1_encode_enc_kdc_rep_part(buf,rep,&length); - if (retval) return retval; - sum += length; - -#ifdef KRB5_ENCKRB5KDCREPPART_COMPAT - krb5_apptag(26); -#else - /* XXX WRONG!!! Should use 25 || 26, not the outer KDC_REP tags! */ - if (rep->msg_type == KRB5_AS_REP) { krb5_apptag(ASN1_KRB_AS_REP); } - else if (rep->msg_type == KRB5_TGS_REP) { krb5_apptag(ASN1_KRB_TGS_REP); } - else return KRB5_BADMSGTYPE; -#endif - krb5_cleanup(); -} - -/* yes, the translation is identical to that used for KDC__REP */ -krb5_error_code encode_krb5_as_rep(const krb5_kdc_rep *rep, krb5_data **code) -{ - krb5_setup(); - - /* AS-REP ::= [APPLICATION 11] KDC-REP */ - retval = asn1_encode_kdc_rep(KRB5_AS_REP,buf,rep,&length); - if (retval) return retval; - sum += length; - - krb5_apptag(11); - - krb5_cleanup(); -} - -/* yes, the translation is identical to that used for KDC__REP */ -krb5_error_code encode_krb5_tgs_rep(const krb5_kdc_rep *rep, krb5_data **code) -{ - krb5_setup(); - - /* TGS-REP ::= [APPLICATION 13] KDC-REP */ - retval = asn1_encode_kdc_rep(KRB5_TGS_REP,buf,rep,&length); - if (retval) return retval; - sum += length; - - krb5_apptag(13); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_ap_req(const krb5_ap_req *rep, krb5_data **code) -{ - krb5_setup(); - - /* authenticator[4] EncryptedData */ - krb5_addfield(&(rep->authenticator),4,asn1_encode_encrypted_data); - - /* ticket[3] Ticket */ - krb5_addfield(rep->ticket,3,asn1_encode_ticket); - - /* ap-options[2] APOptions */ - krb5_addfield(rep->ap_options,2,asn1_encode_ap_options); - - /* msg-type[1] INTEGER */ - krb5_addfield(ASN1_KRB_AP_REQ,1,asn1_encode_integer); - - /* pvno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* AP-REQ ::= [APPLICATION 14] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(14); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_ap_rep(const krb5_ap_rep *rep, krb5_data **code) -{ - krb5_setup(); - - /* enc-part[2] EncryptedData */ - krb5_addfield(&(rep->enc_part),2,asn1_encode_encrypted_data); - - /* msg-type[1] INTEGER */ - krb5_addfield(ASN1_KRB_AP_REP,1,asn1_encode_integer); - - /* pvno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* AP-REP ::= [APPLICATION 15] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(15); - - krb5_cleanup(); -} - - -krb5_error_code encode_krb5_ap_rep_enc_part(const krb5_ap_rep_enc_part *rep, krb5_data **code) -{ - krb5_setup(); - - /* seq-number[3] INTEGER OPTIONAL */ - if (rep->seq_number) - krb5_addfield(rep->seq_number,3,asn1_encode_unsigned_integer); - - /* subkey[2] EncryptionKey OPTIONAL */ - if (rep->subkey != NULL) - krb5_addfield(rep->subkey,2,asn1_encode_encryption_key); - - /* cusec[1] INTEGER */ - krb5_addfield(rep->cusec,1,asn1_encode_integer); - - /* ctime[0] KerberosTime */ - krb5_addfield(rep->ctime,0,asn1_encode_kerberos_time); - - /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(27); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_as_req(const krb5_kdc_req *rep, krb5_data **code) -{ - krb5_setup(); - - /* AS-REQ ::= [APPLICATION 10] KDC-REQ */ - retval = asn1_encode_kdc_req(KRB5_AS_REQ,buf,rep,&length); - if (retval) return retval; - sum += length; - - krb5_apptag(10); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_tgs_req(const krb5_kdc_req *rep, krb5_data **code) -{ - krb5_setup(); - - /* TGS-REQ ::= [APPLICATION 12] KDC-REQ */ - retval = asn1_encode_kdc_req(KRB5_TGS_REQ,buf,rep,&length); - if (retval) return retval; - sum += length; - - krb5_apptag(12); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_kdc_req_body(const krb5_kdc_req *rep, krb5_data **code) -{ - krb5_setup(); - - retval = asn1_encode_kdc_req_body(buf,rep,&length); - if (retval) return retval; - sum += length; - - krb5_cleanup(); -} - - -krb5_error_code encode_krb5_safe(const krb5_safe *rep, krb5_data **code) -{ - krb5_setup(); - - /* cksum[3] Checksum */ - krb5_addfield(rep->checksum,3,asn1_encode_checksum); - - /* safe-body[2] KRB-SAFE-BODY */ - krb5_addfield(rep,2,asn1_encode_krb_safe_body); - - /* msg-type[1] INTEGER */ - krb5_addfield(ASN1_KRB_SAFE,1,asn1_encode_integer); - - /* pvno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* KRB-SAFE ::= [APPLICATION 20] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(20); - - krb5_cleanup(); -} - -/* - * encode_krb5_safe_with_body - * - * Like encode_krb5_safe(), except takes a saved KRB-SAFE-BODY - * encoding to avoid problems with re-encoding. - */ -krb5_error_code encode_krb5_safe_with_body( - const krb5_safe *rep, - const krb5_data *body, - krb5_data **code) -{ - krb5_setup(); - - if (body == NULL) { - asn1buf_destroy(&buf); - return ASN1_MISSING_FIELD; - } - - /* cksum[3] Checksum */ - krb5_addfield(rep->checksum,3,asn1_encode_checksum); - - /* safe-body[2] KRB-SAFE-BODY */ - krb5_addfield(body,2,asn1_encode_krb_saved_safe_body); - - /* msg-type[1] INTEGER */ - krb5_addfield(ASN1_KRB_SAFE,1,asn1_encode_integer); - - /* pvno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* KRB-SAFE ::= [APPLICATION 20] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(20); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_priv(const krb5_priv *rep, krb5_data **code) -{ - krb5_setup(); - - /* enc-part[3] EncryptedData */ - krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data); - - /* msg-type[1] INTEGER */ - krb5_addfield(ASN1_KRB_PRIV,1,asn1_encode_integer); - - /* pvno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* KRB-PRIV ::= [APPLICATION 21] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(21); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_enc_priv_part(const krb5_priv_enc_part *rep, krb5_data **code) -{ - krb5_setup(); - - /* r-address[5] HostAddress OPTIONAL -- recip's addr */ - if (rep->r_address) - krb5_addfield(rep->r_address,5,asn1_encode_host_address); - - /* s-address[4] HostAddress -- sender's addr */ - krb5_addfield(rep->s_address,4,asn1_encode_host_address); - - /* seq-number[3] INTEGER OPTIONAL */ - if (rep->seq_number) - krb5_addfield(rep->seq_number,3,asn1_encode_unsigned_integer); - - /* usec[2] INTEGER OPTIONAL */ - if (rep->timestamp) { - krb5_addfield(rep->usec,2,asn1_encode_integer); - /* timestamp[1] KerberosTime OPTIONAL */ - krb5_addfield(rep->timestamp,1,asn1_encode_kerberos_time); - } - - /* user-data[0] OCTET STRING */ - krb5_addlenfield(rep->user_data.length,rep->user_data.data,0,asn1_encode_charstring); - - /* EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(28); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_cred(const krb5_cred *rep, krb5_data **code) -{ - krb5_setup(); - - /* enc-part[3] EncryptedData */ - krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data); - - /* tickets[2] SEQUENCE OF Ticket */ - krb5_addfield((const krb5_ticket**)rep->tickets,2,asn1_encode_sequence_of_ticket); - - /* msg-type[1] INTEGER, -- KRB_CRED */ - krb5_addfield(ASN1_KRB_CRED,1,asn1_encode_integer); - - /* pvno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* KRB-CRED ::= [APPLICATION 22] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(22); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_enc_cred_part(const krb5_cred_enc_part *rep, krb5_data **code) -{ - krb5_setup(); - - /* r-address[5] HostAddress OPTIONAL */ - if (rep->r_address != NULL) - krb5_addfield(rep->r_address,5,asn1_encode_host_address); - - /* s-address[4] HostAddress OPTIONAL */ - if (rep->s_address != NULL) - krb5_addfield(rep->s_address,4,asn1_encode_host_address); - - /* usec[3] INTEGER OPTIONAL */ - if (rep->timestamp) { - krb5_addfield(rep->usec,3,asn1_encode_integer); - /* timestamp[2] KerberosTime OPTIONAL */ - krb5_addfield(rep->timestamp,2,asn1_encode_kerberos_time); - } - - /* nonce[1] INTEGER OPTIONAL */ - if (rep->nonce) - krb5_addfield(rep->nonce,1,asn1_encode_integer); - - /* ticket-info[0] SEQUENCE OF KrbCredInfo */ - krb5_addfield((const krb5_cred_info**)rep->ticket_info, - 0,asn1_encode_sequence_of_krb_cred_info); - - /* EncKrbCredPart ::= [APPLICATION 29] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(29); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_error(const krb5_error *rep, krb5_data **code) -{ - krb5_setup(); - - /* e-data[12] OCTET STRING OPTIONAL */ - if (rep->e_data.data != NULL && rep->e_data.length > 0) - krb5_addlenfield(rep->e_data.length,rep->e_data.data,12,asn1_encode_charstring); - - /* e-text[11] GeneralString OPTIONAL */ - if (rep->text.data != NULL && rep->text.length > 0) - krb5_addlenfield(rep->text.length,rep->text.data,11,asn1_encode_generalstring); - - /* sname[10] PrincipalName -- Correct name */ - krb5_addfield(rep->server,10,asn1_encode_principal_name); - - /* realm[9] Realm -- Correct realm */ - krb5_addfield(rep->server,9,asn1_encode_realm); - - /* cname[8] PrincipalName OPTIONAL */ - if (rep->client != NULL) { - krb5_addfield(rep->client,8,asn1_encode_principal_name); - /* crealm[7] Realm OPTIONAL */ - krb5_addfield(rep->client,7,asn1_encode_realm); - } - - /* error-code[6] INTEGER */ - krb5_addfield(rep->error,6,asn1_encode_ui_4); - - /* susec[5] INTEGER */ - krb5_addfield(rep->susec,5,asn1_encode_integer); - - /* stime[4] KerberosTime */ - krb5_addfield(rep->stime,4,asn1_encode_kerberos_time); - - /* cusec[3] INTEGER OPTIONAL */ - if (rep->cusec) - krb5_addfield(rep->cusec,3,asn1_encode_integer); - - /* ctime[2] KerberosTime OPTIONAL */ - if (rep->ctime) - krb5_addfield(rep->ctime,2,asn1_encode_kerberos_time); - - /* msg-type[1] INTEGER */ - krb5_addfield(ASN1_KRB_ERROR,1,asn1_encode_integer); - - /* pvno[0] INTEGER */ - krb5_addfield(KVNO,0,asn1_encode_integer); - - /* KRB-ERROR ::= [APPLICATION 30] SEQUENCE */ - krb5_makeseq(); - krb5_apptag(30); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_authdata(const krb5_authdata **rep, krb5_data **code) -{ - asn1_error_code retval; - asn1buf *buf=NULL; - unsigned int length; - - if (rep == NULL) return ASN1_MISSING_FIELD; - - retval = asn1buf_create(&buf); - if (retval) return retval; - - retval = asn1_encode_authorization_data(buf,(const krb5_authdata**)rep, - &length); - if (retval) return retval; - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_authdata_elt(const krb5_authdata *rep, krb5_data **code) -{ - asn1_error_code retval; - asn1buf *buf=NULL; - unsigned int length; - - if (rep == NULL) return ASN1_MISSING_FIELD; - - retval = asn1buf_create(&buf); - if (retval) return retval; - - retval = asn1_encode_krb5_authdata_elt(buf,rep, &length); - if (retval) return retval; - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_alt_method(const krb5_alt_method *rep, krb5_data **code) -{ - krb5_setup(); - - /* method-data[1] OctetString OPTIONAL */ - if (rep->data != NULL && rep->length > 0) - krb5_addlenfield(rep->length,rep->data,1,asn1_encode_octetstring); - - /* method-type[0] Integer */ - krb5_addfield(rep->method,0,asn1_encode_integer); - - krb5_makeseq(); - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_etype_info(const krb5_etype_info_entry **rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_etype_info(buf,rep,&length, 0); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_etype_info2(const krb5_etype_info_entry **rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_etype_info(buf,rep,&length, 1); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - - -krb5_error_code encode_krb5_enc_data(const krb5_enc_data *rep, krb5_data **code) -{ - krb5_setup(); - - retval = asn1_encode_encrypted_data(buf,rep,&length); - if (retval) return retval; - sum += length; - - krb5_cleanup(); -} - -krb5_error_code encode_krb5_pa_enc_ts(const krb5_pa_enc_ts *rep, krb5_data **code) -{ - krb5_setup(); - - /* pausec[1] INTEGER OPTIONAL */ - if (rep->pausec) - krb5_addfield(rep->pausec,1,asn1_encode_integer); - - /* patimestamp[0] KerberosTime, -- client's time */ - krb5_addfield(rep->patimestamp,0,asn1_encode_kerberos_time); - - krb5_makeseq(); - - krb5_cleanup(); -} - -/* Sandia Additions */ -krb5_error_code encode_krb5_pwd_sequence(const passwd_phrase_element *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_passwdsequence(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_pwd_data(const krb5_pwd_data *rep, krb5_data **code) -{ - krb5_setup(); - krb5_addfield((const passwd_phrase_element**)rep->element,1,asn1_encode_sequence_of_passwdsequence); - krb5_addfield(rep->sequence_count,0,asn1_encode_integer); - krb5_makeseq(); - krb5_cleanup(); -} - -krb5_error_code encode_krb5_padata_sequence(const krb5_pa_data **rep, krb5_data **code) -{ - krb5_setup(); - - retval = asn1_encode_sequence_of_pa_data(buf,rep,&length); - if (retval) return retval; - sum += length; - - krb5_cleanup(); -} - -/* sam preauth additions */ -krb5_error_code encode_krb5_sam_challenge(const krb5_sam_challenge *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_sam_challenge(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_sam_challenge_2(const krb5_sam_challenge_2 *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_sam_challenge_2(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_sam_challenge_2_body(const krb5_sam_challenge_2_body *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_sam_challenge_2_body(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_sam_key(const krb5_sam_key *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_sam_key(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_enc_sam_response_enc(const krb5_enc_sam_response_enc *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_enc_sam_response_enc(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_enc_sam_response_enc_2(const krb5_enc_sam_response_enc_2 *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_enc_sam_response_enc_2(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_sam_response(const krb5_sam_response *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_sam_response(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_sam_response_2(const krb5_sam_response_2 *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_sam_response_2(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_predicted_sam_response(const krb5_predicted_sam_response *rep, krb5_data **code) -{ - krb5_setup(); - retval = asn1_encode_predicted_sam_response(buf,rep,&length); - if (retval) return retval; - sum += length; - krb5_cleanup(); -} - -krb5_error_code encode_krb5_setpw_req(const krb5_principal target, - char *password, krb5_data **code) -{ - /* Macros really want us to have a variable called rep which we do not need*/ - const char *rep = "dummy string"; - - krb5_setup(); - - krb5_addfield(target,2,asn1_encode_realm); - krb5_addfield(target,1,asn1_encode_principal_name); - krb5_addlenfield(strlen(password), password,0,asn1_encode_octetstring); - krb5_makeseq(); - - - krb5_cleanup(); -} - -#ifndef DISABLE_PKINIT krb5_error_code encode_krb5_pa_pk_as_req(const krb5_pa_pk_as_req *rep, krb5_data **code) { krb5_setup(); diff --git a/src/lib/krb5/asn.1/krbasn1.h b/src/lib/krb5/asn.1/krbasn1.h index cc41dfd..da08ec1 100644 --- a/src/lib/krb5/asn.1/krbasn1.h +++ b/src/lib/krb5/asn.1/krbasn1.h @@ -9,16 +9,6 @@ #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif -/* - * Older versions of the Kerberos are always sending the - * enc_kdc_rep_part structure with an application tag of #26, instead - * of using the application tag of #25 (AS REP) or #26 (AS REP) as - * necessary. Worse yet, they will only accept a tag of #26, so we - * need to follow this for backwards compatibility. #defining - * KRB5_ENCKRB5KDCREPPART_COMPAT will preserve this wrong (but - * compatible) behavior. - */ -#define KRB5_ENCKRB5KDCREPPART_COMPAT /* * If KRB5_MSGTYPE_STRICT is defined, then be strict about checking @@ -45,6 +35,9 @@ typedef enum { PRIMITIVE = 0x00, CONSTRUCTED = 0x20 } asn1_construction; typedef enum { UNIVERSAL = 0x00, APPLICATION = 0x40, CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xC0 } asn1_class; +typedef INT64_TYPE asn1_intmax; +typedef UINT64_TYPE asn1_uintmax; + typedef int asn1_tagnum; #define ASN1_TAGNUM_CEILING INT_MAX #define ASN1_TAGNUM_MAX (ASN1_TAGNUM_CEILING-1) diff --git a/src/lib/krb5/asn.1/ldap_key_seq.c b/src/lib/krb5/asn.1/ldap_key_seq.c index 1d48f9b..2807a51 100644 --- a/src/lib/krb5/asn.1/ldap_key_seq.c +++ b/src/lib/krb5/asn.1/ldap_key_seq.c @@ -39,187 +39,86 @@ #include "asn1_decode.h" #include "asn1_make.h" #include "asn1_get.h" +#include "asn1_k_encode.h" #ifdef ENABLE_LDAP -#define asn1_encode_sequence_of_keys krb5int_ldap_encode_sequence_of_keys -#define asn1_decode_sequence_of_keys krb5int_ldap_decode_sequence_of_keys - -#define cleanup(err) \ - { \ - ret = err; \ - goto last; \ - } - -#define checkerr \ - if (ret != 0) \ - goto last - /************************************************************************/ /* Encode the Principal's keys */ /************************************************************************/ -static asn1_error_code -asn1_encode_key(asn1buf *buf, - krb5_key_data key_data, - unsigned int *retlen) -{ - asn1_error_code ret = 0; - unsigned int length, sum = 0; - - /* Encode the key type and value. */ - { - unsigned int key_len = 0; - /* key value */ - ret = asn1_encode_octetstring (buf, - key_data.key_data_length[0], - key_data.key_data_contents[0], - &length); checkerr; - key_len += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); checkerr; - key_len += length; - /* key type */ - ret = asn1_encode_integer (buf, key_data.key_data_type[0], &length); - checkerr; - key_len += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr; - key_len += length; - - ret = asn1_make_sequence(buf, key_len, &length); checkerr; - key_len += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, key_len, &length); checkerr; - key_len += length; - - sum += key_len; - } - /* Encode the salt type and value (optional) */ - if (key_data.key_data_ver > 1) { - unsigned int salt_len = 0; - /* salt value (optional) */ - if (key_data.key_data_length[1] > 0) { - ret = asn1_encode_octetstring (buf, - key_data.key_data_length[1], - key_data.key_data_contents[1], - &length); checkerr; - salt_len += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); - checkerr; - salt_len += length; - } - /* salt type */ - ret = asn1_encode_integer (buf, key_data.key_data_type[1], &length); - checkerr; - salt_len += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr; - salt_len += length; - - ret = asn1_make_sequence(buf, salt_len, &length); checkerr; - salt_len += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, salt_len, &length); checkerr; - salt_len += length; +/* Imports from asn1_k_encode.c. + XXX Must be manually synchronized for now. */ +IMPORT_TYPE(octetstring, unsigned char *); +IMPORT_TYPE(int32, krb5_int32); - sum += salt_len; - } - - ret = asn1_make_sequence(buf, sum, &length); checkerr; - sum += length; - - *retlen = sum; - -last: - return ret; -} +DEFINTTYPE(int16, krb5_int16); +DEFINTTYPE(ui_2, krb5_ui_2); -/* Major version and minor version are both '1' - first version */ -/* asn1_error_code asn1_encode_sequence_of_keys (krb5_key_data *key_data, */ -krb5_error_code -asn1_encode_sequence_of_keys (ldap_seqof_key_data *val, krb5_data **code) +static const struct field_info krbsalt_fields[] = { + FIELDOF_NORM(krb5_key_data, int16, key_data_type[1], 0), + FIELDOF_OPTSTRINGL(krb5_key_data, octetstring, key_data_contents[1], + ui_2, key_data_length[1], 1, 1), +}; +static unsigned int optional_krbsalt (const void *p) { - krb5_key_data *key_data = val->key_data; - krb5_int16 n_key_data = val->n_key_data; - krb5_int32 mkvno = val->mkvno; - asn1_error_code ret = 0; - asn1buf *buf = NULL; - unsigned int length, sum = 0; - unsigned long tmp_ul; + const krb5_key_data *k = p; + unsigned int optional = 0; - *code = NULL; + if (k->key_data_length[1] > 0) + optional |= (1u << 1); - if (n_key_data == 0) cleanup (ASN1_MISSING_FIELD); - - /* Allocate the buffer */ - ret = asn1buf_create(&buf); - checkerr; - - /* Sequence of keys */ - { - int i; - unsigned int seq_len = 0; - - for (i = n_key_data - 1; i >= 0; i--) { - ret = asn1_encode_key (buf, key_data[i], &length); checkerr; - seq_len += length; - } - ret = asn1_make_sequence(buf, seq_len, &length); checkerr; - seq_len += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 4, seq_len, &length); checkerr; - seq_len += length; - - sum += seq_len; - } - - /* mkvno */ - if (mkvno < 0) - cleanup (ASN1_BAD_FORMAT); - tmp_ul = (unsigned long)mkvno; - ret = asn1_encode_unsigned_integer (buf, tmp_ul, &length); checkerr; - sum += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 3, length, &length); checkerr; - sum += length; - - /* kvno (assuming all keys in array have same version) */ - if (key_data[0].key_data_kvno < 0) - cleanup (ASN1_BAD_FORMAT); - tmp_ul = (unsigned long)key_data[0].key_data_kvno; - ret = asn1_encode_unsigned_integer (buf, tmp_ul, &length); - checkerr; - sum += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 2, length, &length); checkerr; - sum += length; - - /* attribute-minor-vno == 1 */ - ret = asn1_encode_unsigned_integer (buf, 1, &length); checkerr; - sum += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); checkerr; - sum += length; - - /* attribute-major-vno == 1 */ - ret = asn1_encode_unsigned_integer (buf, 1, &length); checkerr; - sum += length; - ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr; - sum += length; - - ret = asn1_make_sequence(buf, sum, &length); checkerr; - sum += length; - - /* The reverse encoding is straightened out here */ - ret = asn12krb5_buf (buf, code); checkerr; - -last: - asn1buf_destroy (&buf); - - if (ret != 0 && *code != NULL) { - free ((*code)->data); - free (*code); - } - - return ret; + return optional; } +DEFSEQTYPE(krbsalt, krb5_key_data, krbsalt_fields, optional_krbsalt); +static const struct field_info encryptionkey_fields[] = { + FIELDOF_NORM(krb5_key_data, int16, key_data_type[0], 0), + FIELDOF_STRINGL(krb5_key_data, octetstring, key_data_contents[0], + ui_2, key_data_length[0], 1), +}; +DEFSEQTYPE(encryptionkey, krb5_key_data, encryptionkey_fields, 0); + +static const struct field_info key_data_fields[] = { + FIELDOF_ENCODEAS(krb5_key_data, krbsalt, 0), + FIELDOF_ENCODEAS(krb5_key_data, encryptionkey, 1), +#if 0 /* We don't support this field currently. */ + FIELDOF_blah(krb5_key_data, s2kparams, ...), +#endif +}; +DEFSEQTYPE(key_data, krb5_key_data, key_data_fields, 0); +DEFPTRTYPE(ptr_key_data, key_data); + +DEFFIELDTYPE(key_data_kvno, krb5_key_data, + FIELDOF_NORM(krb5_key_data, int16, key_data_kvno, -1)); +DEFPTRTYPE(ptr_key_data_kvno, key_data_kvno); + +static const struct field_info ldap_key_seq_fields[] = { + FIELD_INT_IMM(1, 0), + FIELD_INT_IMM(1, 1), + FIELDOF_NORM(ldap_seqof_key_data, ptr_key_data_kvno, key_data, 2), + FIELDOF_NORM(ldap_seqof_key_data, int32, mkvno, 3), /* mkvno */ + FIELDOF_SEQOF_LEN(ldap_seqof_key_data, ptr_key_data, key_data, n_key_data, + int16, 4), +}; +DEFSEQTYPE(ldap_key_seq, ldap_seqof_key_data, ldap_key_seq_fields, 0); + +/* Export a function to do the whole encoding. */ +MAKE_FULL_ENCODER(krb5int_ldap_encode_sequence_of_keys, ldap_key_seq); /************************************************************************/ /* Decode the Principal's keys */ /************************************************************************/ +#define cleanup(err) \ + { \ + ret = err; \ + goto last; \ + } + +#define checkerr \ + if (ret != 0) \ + goto last + #define safe_syncbuf(outer,inner,buflen) \ if (! ((inner)->next == (inner)->bound + 1 && \ (inner)->next == (outer)->next + buflen)) \ @@ -279,7 +178,8 @@ last: #endif static asn1_error_code -decode_tagged_octetstring (asn1buf *buf, asn1_tagnum expectedtag, int *len, +decode_tagged_octetstring (asn1buf *buf, asn1_tagnum expectedtag, + unsigned int *len, asn1_octet **val) { int buflen; @@ -328,8 +228,8 @@ static asn1_error_code asn1_decode_key(asn1buf *buf, krb5_key_data *key) if (t.tagnum == 0) { int salt_buflen; asn1buf slt; - unsigned long keytype; - int keylen; + long keytype; + unsigned int keylen; key->key_data_ver = 2; asn1_get_sequence(&subbuf, &length, &seqindef); @@ -358,7 +258,7 @@ static asn1_error_code asn1_decode_key(asn1buf *buf, krb5_key_data *key) int key_buflen; asn1buf kbuf; long lval; - int ival; + unsigned int ival; if (t.tagnum != 1) cleanup (ASN1_MISSING_FIELD); @@ -390,9 +290,8 @@ last: return ret; } -/* asn1_error_code asn1_decode_sequence_of_keys (krb5_data *in, */ -krb5_error_code asn1_decode_sequence_of_keys (krb5_data *in, - ldap_seqof_key_data **rep) +krb5_error_code krb5int_ldap_decode_sequence_of_keys (krb5_data *in, + ldap_seqof_key_data **rep) { ldap_seqof_key_data *repval; krb5_key_data **out; |