krb5_error_code encode_krb5_safe
(const krb5_safe *rep, krb5_data **code);
+struct krb5_safe_with_body {
+ krb5_safe *safe;
+ krb5_data *body;
+};
krb5_error_code encode_krb5_safe_with_body
- (const krb5_safe *rep, const krb5_data *body, krb5_data **code);
+ (const struct krb5_safe_with_body *rep, krb5_data **code);
krb5_error_code encode_krb5_priv
(const krb5_priv *rep, krb5_data **code);
(const krb5_error *rep, krb5_data **code);
krb5_error_code encode_krb5_authdata
- (const krb5_authdata **rep, krb5_data **code);
+ (krb5_authdata *const *rep, krb5_data **code);
krb5_error_code encode_krb5_authdata_elt
(const krb5_authdata *rep, krb5_data **code);
(const krb5_pwd_data *rep, krb5_data **code);
krb5_error_code encode_krb5_padata_sequence
- (const krb5_pa_data ** rep, krb5_data **code);
+ (krb5_pa_data *const *rep, krb5_data **code);
krb5_error_code encode_krb5_alt_method
(const krb5_alt_method *, krb5_data **code);
krb5_error_code encode_krb5_etype_info
- (const krb5_etype_info_entry **, krb5_data **code);
+ (krb5_etype_info_entry *const *, krb5_data **code);
krb5_error_code encode_krb5_etype_info2
- (const krb5_etype_info_entry **, krb5_data **code);
+ (krb5_etype_info_entry *const *, krb5_data **code);
krb5_error_code encode_krb5_enc_data
(const krb5_enc_data *, krb5_data **);
krb5_error_code encode_krb5_sam_response
(const krb5_sam_response * , krb5_data **);
+#if 0 /* currently not compiled because we never use them */
krb5_error_code encode_krb5_sam_challenge_2
(const krb5_sam_challenge_2 * , krb5_data **);
krb5_error_code encode_krb5_sam_challenge_2_body
(const krb5_sam_challenge_2_body * , krb5_data **);
+#endif
krb5_error_code encode_krb5_enc_sam_response_enc_2
(const krb5_enc_sam_response_enc_2 * , krb5_data **);
krb5_error_code encode_krb5_predicted_sam_response
(const krb5_predicted_sam_response * , krb5_data **);
+struct krb5_setpw_req {
+ krb5_principal target;
+ krb5_data password;
+};
krb5_error_code encode_krb5_setpw_req
-(const krb5_principal target, char *password, krb5_data **code);
+(const struct krb5_setpw_req *rep, krb5_data **code);
/*************************************************************************
* End of prototypes for krb5_encode.c
typedef struct ldap_seqof_key_data ldap_seqof_key_data;
krb5_error_code
-krb5int_ldap_encode_sequence_of_keys (ldap_seqof_key_data *val,
+krb5int_ldap_encode_sequence_of_keys (const ldap_seqof_key_data *val,
krb5_data **code);
krb5_error_code
"%spreauth required but hint list is empty",
hw_only ? "hw" : "");
}
- retval = encode_krb5_padata_sequence((const krb5_pa_data **) pa_data,
- &edat);
+ retval = encode_krb5_padata_sequence(pa_data, &edat);
if (retval)
goto errout;
*e_data = *edat;
}
}
if (etype_info2)
- retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry,
- &scratch);
- else retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry,
- &scratch);
+ retval = encode_krb5_etype_info2(entry, &scratch);
+ else
+ retval = encode_krb5_etype_info(entry, &scratch);
if (retval)
goto cleanup;
pa_data->contents = (unsigned char *)scratch->data;
goto cleanup;
if (etype_info2)
- retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, &scratch);
+ retval = encode_krb5_etype_info2(entry, &scratch);
else
- retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry, &scratch);
+ retval = encode_krb5_etype_info(entry, &scratch);
if (retval)
goto cleanup;
--- /dev/null
+-*- 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?
/*
* 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
#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;
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;
return 0;
}
+#if 0
asn1_error_code
asn1_encode_enumerated(asn1buf * buf, long val,
unsigned int *retlen)
*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;
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 */
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;
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;
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;
/*
if (gmt_time == 0) {
sp = "19700101000000Z";
} else {
+ int len;
/*
* Sanity check this just to be paranoid, as gmtime can return NULL,
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;
+}
/*
* 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
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
(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
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
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,
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
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
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
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;
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);
#include "asn1_encode.h"
#include <assert.h>
-/**** asn1 macros ****/
-#if 0
- How to write an asn1 encoder function using these 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();
+/* helper macros
- 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
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;
-
- retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_BITSTRING,sum,
- &length);
- if (retval) return retval;
- sum += length;
+ const krb5_enc_data *val = vptr;
+ unsigned int optional = 0;
- *retlen = sum;
- return 0;
-}
+ if (val->kvno != 0)
+ optional |= (1u << 1);
-asn1_error_code asn1_encode_ap_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
- return asn1_encode_krb5_flags(buf,val,retlen);
+ return optional;
}
-asn1_error_code asn1_encode_ticket_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
- return asn1_encode_krb5_flags(buf,val,retlen);
-}
-
-asn1_error_code asn1_encode_kdc_options(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_authorization_data(asn1buf *buf, const krb5_authdata **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)
{
- 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();
+ 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_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();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_kdc_rep(int msg_type, asn1buf *buf, const krb5_kdc_rep *val, unsigned int *retlen)
-{
- asn1_setup();
-
- if (val == NULL) return ASN1_MISSING_FIELD;
-
- 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();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_enc_kdc_rep_part(asn1buf *buf, const krb5_enc_kdc_rep_part *val, unsigned int *retlen)
-{
- asn1_setup();
-
- if (val == NULL) return ASN1_MISSING_FIELD;
-
- /* 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 */
- 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);
-
- /* last-req[1] LastReq */
- asn1_addfield((const krb5_last_req_entry**)val->last_req,1,asn1_encode_last_req);
-
+ 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 */
- asn1_addfield(val->session,0,asn1_encode_encryption_key);
-
- /* EncKDCRepPart ::= SEQUENCE */
- asn1_makeseq();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_checksum(asn1buf *buf, const krb5_checksum ** 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_checksum(buf,val[i],&length);
- if (retval) return retval;
- sum += length;
- }
- asn1_makeseq();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *rep, unsigned int *retlen)
+ 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)
{
- asn1_setup();
-
- if (rep == NULL) return ASN1_MISSING_FIELD;
-
- /* 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);
-
- /* 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);
+ const krb5_enc_kdc_rep_part *val = p;
+ unsigned int optional = 0;
- /* from[4] KerberosTime OPTIONAL, */
- if (rep->from)
- asn1_addfield(rep->from,4,asn1_encode_kerberos_time);
-
- /* sname[3] PrincipalName OPTIONAL, */
- if (rep->server != NULL)
- asn1_addfield(rep->server,3,asn1_encode_principal_name);
-
- /* 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);
+ 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;
-
- /* cname[1] PrincipalName OPTIONAL, */
- /* -- Used only in AS-REQ */
- if (rep->client != NULL)
- asn1_addfield(rep->client,1,asn1_encode_principal_name);
-
- /* kdc-options[0] KDCOptions, */
- asn1_addfield(rep->kdc_options,0,asn1_encode_kdc_options);
-
- /* KDC-REQ-BODY ::= SEQUENCE */
- asn1_makeseq();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_encryption_key(asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen)
-{
- 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();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_checksum(asn1buf *buf, const krb5_checksum *val, unsigned int *retlen)
-{
- 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->checksum_type,0,asn1_encode_integer);
- asn1_makeseq();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_transited_encoding(asn1buf *buf, const krb5_transited *val, unsigned int *retlen)
-{
- asn1_setup();
-
- if (val == NULL ||
- (val->tr_contents.length != 0 && val->tr_contents.data == NULL))
- 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;
-
- 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_last_req_entry(buf,val[i],&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();
-}
-
-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();
-}
-
-asn1_error_code asn1_encode_pa_data(asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen)
-{
- asn1_setup();
-
- 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();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_ticket(asn1buf *buf, const krb5_ticket **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++);
- for (i--; i>=0; i--) {
- retval = asn1_encode_ticket(buf,val[i],&length);
- if (retval) return retval;
- sum += length;
- }
- asn1_makeseq();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_ticket(asn1buf *buf, const krb5_ticket *val, unsigned int *retlen)
-{
- asn1_setup();
-
- if (val == NULL) return ASN1_MISSING_FIELD;
-
- 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);
-
- asn1_cleanup();
-}
-
-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();
+ 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_req(int msg_type, asn1buf *buf, const krb5_kdc_req *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,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();
+DEFNULLTERMSEQOFTYPE(seq_of_pa_data, pa_data_ptr);
+DEFPTRTYPE(ptr_seqof_pa_data, seq_of_pa_data);
- asn1_cleanup();
-}
-asn1_error_code asn1_encode_krb_safe_body(asn1buf *buf, const krb5_safe *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();
-
- if (val == NULL) return ASN1_MISSING_FIELD;
+ const krb5_safe *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)
- ;
-
- asn1_makeseq();
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_sequence_of_krb_cred_info(asn1buf *buf, const krb5_cred_info **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_krb_cred_info(buf,val[i],&length);
- if (retval) return retval;
- sum += length;
+ optional |= (1u << 1);
+ optional |= (1u << 2);
}
- asn1_makeseq();
-
- asn1_cleanup();
-}
-
-asn1_error_code asn1_encode_krb_cred_info(asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen)
-{
- asn1_setup();
-
- if (val == NULL) return ASN1_MISSING_FIELD;
+ 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;
if (val->caddrs != NULL && val->caddrs[0] != NULL)
- asn1_addfield((const krb5_address**)val->caddrs,10,asn1_encode_host_addresses);
+ optional |= (1u << 10);
if (val->server != NULL) {
- asn1_addfield(val->server,9,asn1_encode_principal_name);
- asn1_addfield(val->server,8,asn1_encode_realm);
+ optional |= (1u << 9);
+ optional |= (1u << 8);
}
if (val->times.renew_till)
- asn1_addfield(val->times.renew_till,7,asn1_encode_kerberos_time);
+ optional |= (1u << 7);
if (val->times.endtime)
- asn1_addfield(val->times.endtime,6,asn1_encode_kerberos_time);
+ optional |= (1u << 6);
if (val->times.starttime)
- asn1_addfield(val->times.starttime,5,asn1_encode_kerberos_time);
+ optional |= (1u << 5);
if (val->times.authtime)
- asn1_addfield(val->times.authtime,4,asn1_encode_kerberos_time);
+ optional |= (1u << 4);
if (val->flags)
- asn1_addfield(val->flags,3,asn1_encode_ticket_flags);
+ optional |= (1u << 3);
if (val->client != NULL) {
- asn1_addfield(val->client,2,asn1_encode_principal_name);
- asn1_addfield(val->client,1,asn1_encode_realm);
- }
- asn1_addfield(val->session,0,asn1_encode_encryption_key);
-
- asn1_makeseq();
+ optional |= (1u << 2);
+ optional |= (1u << 1);
+ }
- asn1_cleanup();
+ 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);
-asn1_error_code asn1_encode_etype_info_entry(asn1buf *buf, const krb5_etype_info_entry *val,
- unsigned int *retlen, int etype_info2)
-{
- asn1_setup();
+DEFPTRTYPE(ptrseqof_cred_info, seq_of_cred_info);
- 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);
- }
- }
- asn1_addfield(val->etype,0,asn1_encode_integer);
- asn1_makeseq();
- asn1_cleanup();
-}
-asn1_error_code asn1_encode_etype_info(asn1buf *buf, const krb5_etype_info_entry **val,
- unsigned int *retlen, int etype_info2)
+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++); /* 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;
}
+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_sequence_of_passwdsequence(asn1buf *buf, const passwd_phrase_element **val, unsigned int *retlen)
+static unsigned int
+optional_etype_info2_entry(const void *vptr)
{
- asn1_setup();
- int i;
+ const krb5_etype_info_entry *val = vptr;
+ unsigned int optional = 0;
- if (val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+ if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT)
+ optional |= (1u << 1);
+ if (val->s2kparams.data)
+ optional |= (1u << 2);
- 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();
+ return optional;
}
-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();
-}
+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);
-asn1_error_code asn1_encode_sam_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
-{
- return asn1_encode_krb5_flags(buf,val,retlen);
-}
+DEFPTRTYPE(etype_info_entry_ptr, etype_info_entry);
+DEFNULLTERMSEQOFTYPE(etype_info, etype_info_entry_ptr);
+
+DEFPTRTYPE(etype_info2_entry_ptr, etype_info2_entry);
+DEFNULLTERMSEQOFTYPE(etype_info2, etype_info2_entry_ptr);
+
+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);
-#define add_optstring(val,n,fn) \
- if ((val).length > 0) {asn1_addlenfield((val).length,(val).data,n,fn);}
+DEFPTRTYPE(passwdsequence_ptr, passwdsequence);
+DEFNONEMPTYNULLTERMSEQOFTYPE(seqof_passwdsequence, passwdsequence_ptr);
+DEFPTRTYPE(ptr_seqof_passwdsequence, seqof_passwdsequence);
-asn1_error_code asn1_encode_sam_challenge(asn1buf *buf, const krb5_sam_challenge *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();
- /* possibly wrong */
+ const krb5_sam_challenge *val = p;
+ unsigned int optional = 0;
+
if (val->sam_cksum.length)
- asn1_addfield(&(val->sam_cksum),9,asn1_encode_checksum);
+ optional |= (1u << 9);
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);
+ optional |= (1u << 8);
- asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
- asn1_addfield(val->sam_type,0,asn1_encode_integer);
+ 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_makeseq();
- asn1_cleanup();
+ return optional;
}
+DEFSEQTYPE(sam_challenge,krb5_sam_challenge,sam_challenge_fields,
+ optional_sam_challenge);
-asn1_error_code asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *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) || (!val->sam_cksum) || (!val->sam_cksum[0]))
return ASN1_MISSING_FIELD;
- 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;
+ asn1_addfield(val->sam_cksum, 1, asn1_encode_sequence_of_checksum);
+
+ {
+ unsigned int length;
+
+ 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;
}
- sum += length;
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_sam_challenge_2_body(asn1buf *buf, const krb5_sam_challenge_2_body *val, unsigned int *retlen)
+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);
+
+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;
- 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);
+ if (val->sam_sad.length > 0) optional |= (1u << 3);
- asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
- asn1_addfield(val->sam_type,0,asn1_encode_integer);
+ return optional;
+}
+DEFSEQTYPE(enc_sam_response_enc, krb5_enc_sam_response_enc,
+ enc_sam_response_enc_fields, optional_enc_sam_response_enc);
- asn1_makeseq();
- asn1_cleanup();
+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)
+{
+ const krb5_enc_sam_response_enc_2 *val = p;
+ unsigned int optional = 0;
+
+ if (val->sam_sad.length > 0) optional |= (1u << 1);
+
+ 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_sam_key(asn1buf *buf, const krb5_sam_key *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();
- asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
+ const krb5_sam_response *val = p;
+ unsigned int optional = 0;
- asn1_makeseq();
+ 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);
+DEFAPPTAGGEDTYPE(enc_tgs_rep_part, 26, enc_kdc_rep_part);
-asn1_error_code asn1_encode_enc_sam_response_enc(asn1buf *buf, const krb5_enc_sam_response_enc *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();
- 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);
+ const krb5_kdc_rep *val = p;
+ unsigned int optional = 0;
- asn1_makeseq();
+ if (val->padata != NULL && val->padata[0] != NULL)
+ 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();
+ 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->seq_number)
+ optional |= (1u << 3);
+ if (val->subkey != NULL)
+ optional |= (1u << 2);
+
+ 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_enc_sam_response_enc_2(asn1buf *buf, const krb5_enc_sam_response_enc_2 *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();
- add_optstring(val->sam_sad,1,asn1_encode_charstring);
- asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
+ const krb5_kdc_req *val = p;
+ unsigned int optional = 0;
- 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_sam_response(asn1buf *buf, const krb5_sam_response *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->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);
+ 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;
- asn1_makeseq();
+ if (val->timestamp) {
+ optional |= (1u << 2);
+ optional |= (1u << 1);
+ }
+ 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_cleanup();
-}
+ if (val->r_address != NULL)
+ optional |= (1u << 5);
-asn1_error_code asn1_encode_sam_response_2(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen)
-{
- asn1_setup();
+ if (val->s_address != NULL)
+ optional |= (1u << 4);
- 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);
+ if (val->timestamp) {
+ optional |= (1u << 2);
+ optional |= (1u << 3);
+ }
- asn1_makeseq();
+ 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);
+ }
+ 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_predicted_sam_response(asn1buf *buf, const krb5_predicted_sam_response *val, unsigned int *retlen)
+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();
+ const krb5_alt_method *a = p;
+ unsigned int optional = 0;
- 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);
+ if (a->data != NULL && a->length > 0)
+ optional |= (1u << 1);
- asn1_makeseq();
+ return optional;
+}
+DEFSEQTYPE(alt_method, krb5_alt_method, alt_method_fields, optional_alt_method);
- asn1_cleanup();
+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)
+{
+ const krb5_pa_enc_ts *val = p;
+ unsigned int optional = 0;
+
+ if (val->pausec)
+ optional |= (1u << 1);
+
+ return optional;
}
+DEFSEQTYPE(pa_enc_ts, krb5_pa_enc_ts, pa_enc_ts_fields, optional_pa_enc_ts);
+
+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);
+
+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),
+};
+
+DEFSEQTYPE(setpw_req, struct krb5_setpw_req, setpw_req_fields, 0);
+
+
+
+/* Exported complete encoders -- these produce a krb5_data with
+ the encoding in the correct byte order. */
+
+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);
/*
- * Do some ugliness to insert a raw pre-encoded KRB-SAFE-BODY.
+ * encode_krb5_safe_with_body
+ *
+ * Like encode_krb5_safe(), except takes a saved KRB-SAFE-BODY
+ * encoding to avoid problems with re-encoding.
*/
-asn1_error_code asn1_encode_krb_saved_safe_body(asn1buf *buf, const krb5_data *body, unsigned int *retlen)
-{
- asn1_error_code retval;
+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);
+
+
+
+
+
+
+
- retval = asn1buf_insert_octetstring(buf, body->length,
- (krb5_octet *)body->data);
- if (retval) {
- asn1buf_destroy(&buf);
- return retval;
- }
- *retlen = body->length;
- return 0;
-}
#ifndef DISABLE_PKINIT
/*
* PKINIT
*/
+/* 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 macros ****/
+#if 0
+ How to write an asn1 encoder function using these 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
+
+/* 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_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; }
+
+/* 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_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; }
+
+/* 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);
+
+static asn1_error_code
+asn1_encode_kerberos_time(asn1buf *buf, const krb5_timestamp val,
+ unsigned int *retlen)
+{
+ return asn1_encode_kerberos_time_at(buf,&val,retlen);
+}
+
+/* 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();
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();
{
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) {
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();
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;
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;
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;
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();
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();
}
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;
/*
* 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
#include <stdio.h>
#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,
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
asn1_error_code asn1_encode_sequence_of_typed_data
(asn1buf *buf, const krb5_typed_data **val, unsigned int *retlen);
+
#endif
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;
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;
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)
{
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;
{
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;
#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;
}
#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);
/**************** 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
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);\
\
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();
#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
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)
#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)) \
#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;
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);
int key_buflen;
asn1buf kbuf;
long lval;
- int ival;
+ unsigned int ival;
if (t.tagnum != 1)
cleanup (ASN1_MISSING_FIELD);
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;
krb5_error_code ret;
krb5_data cipherpw;
krb5_data *encoded_setpw;
+ struct krb5_setpw_req req;
char *ptr;
KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
return(ret);
- ret = encode_krb5_setpw_req(targprinc, passwd, &encoded_setpw);
+ req.target = targprinc;
+ req.password.data = passwd;
+ req.password.length = strlen(passwd);
+ ret = encode_krb5_setpw_req(&req, &encoded_setpw);
if (ret) {
return ret;
}
krb5_octet zero_octet = 0;
krb5_data *scratch;
krb5_boolean valid;
+ struct krb5_safe_with_body swb;
if (!krb5_is_krb_safe(inbuf))
return KRB5KRB_AP_ERR_MSG_TYPE;
message->checksum = &our_cksum;
- retval = encode_krb5_safe_with_body(message, &safe_body, &scratch);
+ swb.body = &safe_body;
+ swb.safe = message;
+ retval = encode_krb5_safe_with_body(&swb, &scratch);
message->checksum = his_cksum;
if (retval)
goto cleanup;
if (authorization_data) {
/* need to encrypt it in the request */
- if ((retval = encode_krb5_authdata((const krb5_authdata**)authorization_data,
- &scratch)))
+ if ((retval = encode_krb5_authdata(authorization_data, &scratch)))
return(retval);
if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
t_trval: t_trval.o
$(CC) -o t_trval $(ALL_CFLAGS) t_trval.o
-check:: check-encode check-decode
+check:: check-encode check-encode-trval check-decode
check-decode: krb5_decode_test
KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; \
cat $(srcdir)/trval_reference.out > expected_trval.out; \
fi
-check-encode: krb5_encode_test expected_encode.out expected_trval.out
- $(RM) test.out
+check-encode: krb5_encode_test expected_encode.out
KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; \
export KRB5_CONFIG ;\
$(RUN_SETUP) $(VALGRIND) ./krb5_encode_test > test.out
cmp test.out expected_encode.out
+
+check-encode-trval: krb5_encode_test expected_trval.out
KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; \
export KRB5_CONFIG ;\
- $(RUN_SETUP) $(VALGRIND) ./krb5_encode_test -t > test.out
- cmp test.out expected_trval.out
- $(RM) test.out
+ $(RUN_SETUP) $(VALGRIND) ./krb5_encode_test -t > trval.out
+ cmp trval.out expected_trval.out
install::
clean::
- rm -f *~ *.o krb5_encode_test krb5_decode_test test.out trval t_trval expected_encode.out expected_trval.out
+ rm -f *~ *.o krb5_encode_test krb5_decode_test test.out trval t_trval expected_encode.out expected_trval.out trval.out
################ Dependencies ################
krb5_authdata **ad;
setup(ad,authorization_data,"authorization_data",ktest_make_sample_authorization_data);
- retval = encode_krb5_authdata((const krb5_authdata**)ad,&(code));
+ retval = encode_krb5_authdata(ad,&(code));
if (retval) {
com_err("encoding authorization_data",retval,"");
exit(1);
krb5_pa_data **pa;
setup(pa,krb5_pa_data,"PreauthData",ktest_make_sample_pa_data_array);
- retval = encode_krb5_padata_sequence((const krb5_pa_data**)pa,&(code));
+ retval = encode_krb5_padata_sequence(pa,&(code));
if (retval) {
com_err("encoding padata_sequence",retval,"");
exit(1);
krb5_pa_data **pa;
setup(pa,krb5_pa_data,"EmptyPreauthData",ktest_make_sample_empty_pa_data_array);
- retval = encode_krb5_padata_sequence((const krb5_pa_data**)pa,&(code));
+ retval = encode_krb5_padata_sequence(pa,&(code));
if (retval) {
com_err("encoding padata_sequence(empty)",retval,"");
exit(1);
setup(info,krb5_etype_info_entry **,"etype_info",
ktest_make_sample_etype_info);
- retval = encode_krb5_etype_info((const krb5_etype_info_entry **)info,&(code));
+ retval = encode_krb5_etype_info(info,&(code));
if (retval) {
com_err("encoding etype_info",retval,"");
exit(1);
ktest_destroy_etype_info_entry(info[2]); info[2] = 0;
ktest_destroy_etype_info_entry(info[1]); info[1] = 0;
- retval = encode_krb5_etype_info((const krb5_etype_info_entry **)info,&(code));
+ retval = encode_krb5_etype_info(info,&(code));
if (retval) {
com_err("encoding etype_info (only 1)",retval,"");
exit(1);
ktest_destroy_etype_info_entry(info[0]); info[0] = 0;
- retval = encode_krb5_etype_info((const krb5_etype_info_entry **)info,&(code));
+ retval = encode_krb5_etype_info(info,&(code));
if (retval) {
com_err("encoding etype_info (no info)",retval,"");
exit(1);
setup(info,krb5_etype_info_entry **,"etype_info2",
ktest_make_sample_etype_info2);
- retval = encode_krb5_etype_info2((const krb5_etype_info_entry **)info,&(code));
+ retval = encode_krb5_etype_info2(info,&(code));
if (retval) {
com_err("encoding etype_info",retval,"");
exit(1);
ktest_destroy_etype_info_entry(info[2]); info[2] = 0;
ktest_destroy_etype_info_entry(info[1]); info[1] = 0;
- retval = encode_krb5_etype_info2((const krb5_etype_info_entry **)info,&(code));
+ retval = encode_krb5_etype_info2(info,&(code));
if (retval) {
com_err("encoding etype_info (only 1)",retval,"");
exit(1);
--- /dev/null
+# Test for the simple clients
+# This is a DejaGnu test script.
+# This script tests that krb-safe and krb-priv messages work.
+
+# This mostly just calls procedures in test/dejagnu/config/default.exp.
+
+if ![info exists KLIST] {
+ set KLIST [findfile $objdir/../../clients/klist/klist]
+}
+
+if ![info exists KDESTROY] {
+ set KDESTROY [findfile $objdir/../../clients/kdestroy/kdestroy]
+}
+
+if ![info exists SIM_SERVER] {
+ set SIM_SERVER [findfile $objdir/../../appl/simple/server/sim_server]
+}
+if ![info exists SIM_CLIENT] {
+ set SIM_CLIENT [findfile $objdir/../../appl/simple/client/sim_client]
+}
+
+# Set up the Kerberos files and environment.
+if {![get_hostname] || ![setup_kerberos_files] || ![setup_kerberos_env]} {
+ return
+}
+
+# Initialize the Kerberos database. The argument tells
+# setup_kerberos_db that it is being called from here.
+if ![setup_kerberos_db 0] {
+ return
+}
+
+proc start_sim_server_daemon { } {
+ global spawn_id
+ global sim_server_pid
+ global sim_server_spawn_id
+ global SIM_SERVER
+ global T_INETD
+ global tmppwd
+ global portbase
+
+ # Start the sim_server
+ spawn $SIM_SERVER -p [expr 8 + $portbase] -S $tmppwd/srvtab
+ set sim_server_pid [exp_pid]
+ set sim_server_spawn_id $spawn_id
+
+ verbose "sim_server_spawn is $sim_server_spawn_id" 1
+
+ # Give sim_server some time to start
+ sleep 2
+
+ return 1
+}
+
+
+proc stop_sim_server_daemon { } {
+ global sim_server_pid
+ global sim_server_spawn_id
+
+ if [info exists sim_server_pid] {
+ catch "close -i $sim_server_spawn_id"
+ catch "exec kill $sim_server_pid"
+ wait -i $sim_server_spawn_id
+ unset sim_server_pid
+ }
+
+ return 1
+}
+
+proc stop_check_sim_server_daemon { } {
+ global sim_server_spawn_id
+ global sim_server_pid
+
+ # Check the exit status of sim_server - should exit here
+ set status_list [wait -i $sim_server_spawn_id]
+ verbose "wait -i $sim_server_spawn_id returned $status_list (sim_server)"
+ catch "close -i $sim_server_spawn_id"
+ if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } {
+ send_log "exit status: $status_list\n"
+ verbose "exit status: $status_list"
+ fail "sim_server"
+ } else {
+ pass "sim_server"
+ }
+ # In either case the server shutdown
+ unset sim_server_pid
+}
+
+proc test_sim_client { msg } {
+ global REALMNAME
+ global SIM_CLIENT
+ global hostname
+ global spawn_id
+ global portbase
+ global sim_server_spawn_id
+
+ # Test the client
+ spawn $SIM_CLIENT -p [expr 8 + $portbase] $hostname
+ verbose "sim_client_spawn is $spawn_id" 1
+
+ expect {
+ "Sent checksummed message: " {
+ verbose "received safe message"
+ }
+ timeout {
+ fail $msg
+ return 0
+ }
+ eof {
+ fail $msg
+ return 0
+ }
+ }
+
+ expect {
+ "Sent encrypted message: " {
+ verbose "received private message"
+ }
+ eof {
+ fail $msg
+ return 0
+ }
+ }
+ expect {
+ "\r" { }
+ }
+
+ expect {
+ -i $sim_server_spawn_id
+ "Safe message is: 'hi there!'" { }
+ timeout {
+ fail $msg
+ return 0
+ }
+ eof {
+ fail $msg
+ return 0
+ }
+ }
+
+ expect {
+ -i $sim_server_spawn_id
+ "Decrypted message is: 'hi there!'" { }
+ timeout {
+ fail $msg
+ return 0
+ }
+ eof {
+ fail $msg
+ return 0
+ }
+ }
+
+ if ![check_exit_status "simple"] {
+ return 0
+ }
+
+ return 1
+}
+# We are about to start up a couple of daemon processes. We do all
+# the rest of the tests inside a proc, so that we can easily kill the
+# processes when the procedure ends.
+
+proc doit { } {
+ global hostname
+ global KEY
+ global sim_server_pid
+ global sim_server_spawn_id
+
+ # Start up the kerberos and kadmind daemons.
+ if ![start_kerberos_daemons 0] {
+ return
+ }
+
+ # Use kadmin to add an host key.
+ if ![add_random_key sample/$hostname 1] {
+ return
+ }
+
+ # Use ksrvutil to create a srvtab entry for sample
+ if ![setup_srvtab 1 sample] {
+ return
+ }
+
+ # Use kinit to get a ticket.
+ if ![kinit krbtest/admin adminpass$KEY 1] {
+ return
+ }
+
+ if ![start_sim_server_daemon] {
+ return
+ }
+
+ if ![test_sim_client sim_client] {
+ return
+ }
+
+ pass "simple - standalone"
+
+ stop_check_sim_server_daemon
+ return
+}
+
+set status [catch doit msg]
+
+stop_sim_server_daemon
+
+stop_kerberos_daemons
+
+if { $status != 0 } {
+ send_error "ERROR: error in simple.exp\n"
+ send_error "$msg\n"
+ exit 1
+}