Change optional handling in ASN.1 encoder
authorGreg Hudson <ghudson@mit.edu>
Sat, 11 Feb 2012 23:25:21 +0000 (23:25 +0000)
committerGreg Hudson <ghudson@mit.edu>
Sat, 11 Feb 2012 23:25:21 +0000 (23:25 +0000)
Create a new atype_optional with a function pointer to decide whether
the type is present in the C object.  For simple cases, sequences just
reference the optional version of a type.  For more complex cases (such
as when the presence of the usec field of a sequence depends on whether
the timestamp is set), we define a predicate on the structure object
and nest the field type inside the optional type.

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

src/lib/krb5/asn.1/asn1_encode.c
src/lib/krb5/asn.1/asn1_encode.h
src/lib/krb5/asn.1/asn1_k_encode.c
src/lib/krb5/asn.1/ldap_key_seq.c
src/lib/krb5/error_tables/asn1_err.et

index 42fefeaecb612ed0041f33a9ccb380d406624677..85b804a384bfde62fda8a19d1f8d786f0ece90d4 100644 (file)
@@ -400,6 +400,14 @@ encode_atype(asn1buf *buf, const void *val, const struct atype_info *a,
         return encode_atype(buf, (const char *)val + off->dataoff,
                             off->basetype, tag_out);
     }
+    case atype_optional: {
+        const struct optional_info *opt = a->tinfo;
+        assert(opt->is_present != NULL);
+        if (opt->is_present(val))
+            return encode_atype(buf, val, opt->basetype, tag_out);
+        else
+            return ASN1_OMITTED;
+    }
     case atype_counted: {
         const struct counted_info *counted = a->tinfo;
         const void *dataptr = (const char *)val + counted->dataoff;
@@ -555,18 +563,13 @@ encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq,
                 size_t *len_out)
 {
     asn1_error_code ret;
-    unsigned int not_present;
     size_t i, len, sum = 0;
-    const struct atype_info *a;
 
-    /* If any fields might be optional, get a bitmask of fields not present. */
-    not_present = (seq->optional == NULL) ? 0 : seq->optional(val);
     for (i = seq->n_fields; i > 0; i--) {
-        a = seq->fields[i - 1];
-        if ((1u << (i - 1)) & not_present)
+        ret = encode_atype_and_tag(buf, val, seq->fields[i - 1], &len);
+        if (ret == ASN1_OMITTED)
             continue;
-        ret = encode_atype_and_tag(buf, val, a, &len);
-        if (ret)
+        else if (ret != 0)
             return ret;
         sum += len;
     }
index ba6151d122daf523e65937a5d82de85c89e821fa..5515aadf2ffe19fa8cc43d6ee46cfe1b2541c41a 100644 (file)
@@ -77,6 +77,13 @@ enum atype_type {
     /* Actual thing to be encoded is at an offset from the original pointer.
      * tinfo is a struct offset_info *. */
     atype_offset,
+    /*
+     * Indicates a sequence field which may or may not be present in an object.
+     * tinfo is a struct optional_info *.  Must be used within a sequence,
+     * although the optional type may be nested within offset, ptr, and/or tag
+     * types.
+     */
+    atype_optional,
     /*
      * Actual thing to be encoded is an object at an offset from the original
      * pointer, combined with an integer at a different offset, in a manner
@@ -126,6 +133,11 @@ struct offset_info {
     const struct atype_info *basetype;
 };
 
+struct optional_info {
+    int (*is_present)(const void *);
+    const struct atype_info *basetype;
+};
+
 struct counted_info {
     unsigned int dataoff : 9;
     unsigned int lenoff : 9;
@@ -184,10 +196,6 @@ struct choice_info {
 };
 
 struct seq_info {
-    /* If present, returns a bitmask indicating which fields are present.  The
-     * bit (1 << N) corresponds to index N in the fields array. */
-    unsigned int (*optional)(const void *);
-    /* Indicates an array of sequence field descriptors.  */
     const struct atype_info **fields;
     size_t n_fields;
     /* Currently all sequences are assumed to be extensible. */
@@ -224,10 +232,10 @@ struct seq_info {
     }
 /* A sequence, defined by the indicated series of types, and an optional
  * function indicating which fields are not present. */
-#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS, OPT)                    \
+#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS)                         \
     typedef CTYPENAME aux_type_##DESCNAME;                              \
     static const struct seq_info aux_seqinfo_##DESCNAME = {             \
-        OPT, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0])                   \
+        FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0])                        \
     };                                                                  \
     const struct atype_info k5_atype_##DESCNAME = {                     \
         atype_sequence, sizeof(CTYPENAME), &aux_seqinfo_##DESCNAME      \
@@ -305,6 +313,37 @@ struct seq_info {
 #define DEFCOUNTEDTYPE_SIGNED(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, CDESC) \
     DEFCOUNTEDTYPE_base(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, 1, CDESC)
 
+/* Optional sequence fields.  The basic form allows arbitrary test and
+ * initializer functions to be used. */
+#define DEFOPTIONALTYPE(DESCNAME, PRESENT, BASEDESC)            \
+    typedef aux_type_##BASEDESC aux_type_##DESCNAME;            \
+    static const struct optional_info aux_info_##DESCNAME = {   \
+        PRESENT, &k5_atype_##BASEDESC                           \
+    };                                                          \
+    const struct atype_info k5_atype_##DESCNAME = {             \
+        atype_optional, sizeof(aux_type_##DESCNAME),            \
+        &aux_info_##DESCNAME                                    \
+    }
+/* This form defines an is_present function for a zero-valued integer or null
+ * pointer of the base type's C type. */
+#define DEFOPTIONALZEROTYPE(DESCNAME, BASEDESC)                 \
+    static int                                                  \
+    aux_present_##DESCNAME(const void *p)                       \
+    {                                                           \
+        return *(aux_type_##BASEDESC *)p != 0;                  \
+    }                                                           \
+    DEFOPTIONALTYPE(DESCNAME, aux_present_##DESCNAME, BASEDESC)
+/* This form defines an is_present function for a null or empty null-terminated
+ * array of the base type's C type. */
+#define DEFOPTIONALEMPTYTYPE(DESCNAME, BASEDESC)                \
+    static int                                                  \
+    aux_present_##DESCNAME(const void *p)                       \
+    {                                                           \
+        const aux_type_##BASEDESC *val = p;                     \
+        return (*val != NULL && **val != NULL);                 \
+    }                                                           \
+    DEFOPTIONALTYPE(DESCNAME, aux_present_##DESCNAME, BASEDESC)
+
 /*
  * 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
index 3dc9c74e340bdb2a47c89a826ef1a2d19a434e02..ea4b02316baec368cdeca0a0a1049fbf01ac0823 100644 (file)
@@ -32,13 +32,24 @@ DEFINT_IMMEDIATE(krb5_version, KVNO);
 DEFINTTYPE(int32, krb5_int32);
 DEFPTRTYPE(int32_ptr, int32);
 DEFCOUNTEDSEQOFTYPE(cseqof_int32, krb5_int32, int32_ptr);
+DEFOPTIONALZEROTYPE(opt_int32, int32);
 
 DEFUINTTYPE(uint, unsigned int);
 DEFUINTTYPE(octet, krb5_octet);
 DEFUINTTYPE(ui_4, krb5_ui_4);
+DEFOPTIONALZEROTYPE(opt_uint, uint);
+DEFOPTIONALZEROTYPE(opt_ui_4, ui_4);
+
+static int
+nonempty_data(const void *p)
+{
+    const krb5_data *val = p;
+    return (val->data != NULL && val->length != 0);
+}
 
 DEFCOUNTEDDERTYPE(der, char *, unsigned int);
 DEFCOUNTEDTYPE(der_data, krb5_data, data, length, der);
+DEFOPTIONALTYPE(opt_der_data, nonempty_data, der_data);
 
 DEFCOUNTEDSTRINGTYPE(octetstring, unsigned char *, unsigned int,
                      k5_asn1_encode_bytestring, ASN1_OCTETSTRING);
@@ -46,18 +57,22 @@ DEFCOUNTEDSTRINGTYPE(s_octetstring, char *, unsigned int,
                      k5_asn1_encode_bytestring, ASN1_OCTETSTRING);
 DEFCOUNTEDTYPE(ostring_data, krb5_data, data, length, s_octetstring);
 DEFPTRTYPE(ostring_data_ptr, ostring_data);
+DEFOPTIONALTYPE(opt_ostring_data, nonempty_data, ostring_data);
+DEFOPTIONALZEROTYPE(opt_ostring_data_ptr, ostring_data_ptr);
 
 DEFCOUNTEDSTRINGTYPE(generalstring, char *, unsigned int,
                      k5_asn1_encode_bytestring, ASN1_GENERALSTRING);
 DEFCOUNTEDSTRINGTYPE(u_generalstring, unsigned char *, unsigned int,
                      k5_asn1_encode_bytestring, ASN1_GENERALSTRING);
 DEFCOUNTEDTYPE(gstring_data, krb5_data, data, length, generalstring);
+DEFOPTIONALTYPE(opt_gstring_data, nonempty_data, gstring_data);
 DEFPTRTYPE(gstring_data_ptr, gstring_data);
 DEFCOUNTEDSEQOFTYPE(cseqof_gstring_data, krb5_int32, gstring_data_ptr);
 
 DEFOFFSETTYPE(realm_of_principal_data, krb5_principal_data, realm,
               gstring_data);
 DEFPTRTYPE(realm_of_principal, realm_of_principal_data);
+DEFOPTIONALZEROTYPE(opt_realm_of_principal, realm_of_principal);
 
 DEFFIELD(princname_0, krb5_principal_data, type, 0, int32);
 DEFCNFIELD(princname_1, krb5_principal_data, data, length, 1,
@@ -65,8 +80,9 @@ DEFCNFIELD(princname_1, krb5_principal_data, data, length, 1,
 static const struct atype_info *princname_fields[] = {
     &k5_atype_princname_0, &k5_atype_princname_1
 };
-DEFSEQTYPE(principal_data, krb5_principal_data, princname_fields, NULL);
+DEFSEQTYPE(principal_data, krb5_principal_data, princname_fields);
 DEFPTRTYPE(principal, principal_data);
+DEFOPTIONALZEROTYPE(opt_principal, principal);
 
 static asn1_error_code
 encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag)
@@ -79,35 +95,35 @@ encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag)
     return k5_asn1_encode_generaltime(buf, val, &rettag->length);
 }
 DEFFNTYPE(kerberos_time, krb5_timestamp, encode_kerberos_time);
+DEFOPTIONALZEROTYPE(opt_kerberos_time, kerberos_time);
 
 DEFFIELD(address_0, krb5_address, addrtype, 0, int32);
 DEFCNFIELD(address_1, krb5_address, contents, length, 1, octetstring);
 const static struct atype_info *address_fields[] = {
     &k5_atype_address_0, &k5_atype_address_1
 };
-DEFSEQTYPE(address, krb5_address, address_fields, NULL);
+DEFSEQTYPE(address, krb5_address, address_fields);
 DEFPTRTYPE(address_ptr, address);
+DEFOPTIONALZEROTYPE(opt_address_ptr, address_ptr);
 
 DEFNULLTERMSEQOFTYPE(seqof_host_addresses, address_ptr);
 DEFPTRTYPE(ptr_seqof_host_addresses, seqof_host_addresses);
+DEFOPTIONALEMPTYTYPE(opt_ptr_seqof_host_addresses, ptr_seqof_host_addresses);
 
 DEFFIELD(enc_data_0, krb5_enc_data, enctype, 0, int32);
-DEFFIELD(enc_data_1, krb5_enc_data, kvno, 1, uint);
+DEFFIELD(enc_data_1, krb5_enc_data, kvno, 1, opt_uint);
 DEFFIELD(enc_data_2, krb5_enc_data, ciphertext, 2, ostring_data);
 static const struct atype_info *encrypted_data_fields[] = {
     &k5_atype_enc_data_0, &k5_atype_enc_data_1, &k5_atype_enc_data_2
 };
-static unsigned int
-optional_encrypted_data (const void *vptr)
+DEFSEQTYPE(encrypted_data, krb5_enc_data, encrypted_data_fields);
+static int
+nonempty_enc_data(const void *p)
 {
-    const krb5_enc_data *val = vptr;
-    unsigned int not_present = 0;
-    if (val->kvno == 0)
-        not_present |= (1u << 1);
-    return not_present;
+    const krb5_enc_data *val = p;
+    return (val->ciphertext.data != NULL);
 }
-DEFSEQTYPE(encrypted_data, krb5_enc_data, encrypted_data_fields,
-           optional_encrypted_data);
+DEFOPTIONALTYPE(opt_encrypted_data, nonempty_enc_data, encrypted_data);
 
 /*
  * The encode_bitstring function wants an array of bytes (since PKINIT
@@ -125,41 +141,45 @@ encode_krb5_flags(asn1buf *buf, const void *p, taginfo *rettag)
     return k5_asn1_encode_bitstring(buf, &cptr, 4, &rettag->length);
 }
 DEFFNTYPE(krb5_flags, krb5_flags, encode_krb5_flags);
+DEFOPTIONALZEROTYPE(opt_krb5_flags, krb5_flags);
 
 DEFFIELD(authdata_0, krb5_authdata, ad_type, 0, int32);
 DEFCNFIELD(authdata_1, krb5_authdata, contents, length, 1, octetstring);
 static const struct atype_info *authdata_elt_fields[] = {
     &k5_atype_authdata_0, &k5_atype_authdata_1
 };
-DEFSEQTYPE(authdata_elt, krb5_authdata, authdata_elt_fields, NULL);
+DEFSEQTYPE(authdata_elt, krb5_authdata, authdata_elt_fields);
 DEFPTRTYPE(authdata_elt_ptr, authdata_elt);
 DEFNONEMPTYNULLTERMSEQOFTYPE(auth_data, authdata_elt_ptr);
 DEFPTRTYPE(auth_data_ptr, auth_data);
+DEFOPTIONALEMPTYTYPE(opt_auth_data_ptr, auth_data_ptr);
 
 DEFFIELD(keyblock_0, krb5_keyblock, enctype, 0, int32);
 DEFCNFIELD(keyblock_1, krb5_keyblock, contents, length, 1, octetstring);
 static const struct atype_info *encryption_key_fields[] = {
     &k5_atype_keyblock_0, &k5_atype_keyblock_1
 };
-DEFSEQTYPE(encryption_key, krb5_keyblock, encryption_key_fields, NULL);
+DEFSEQTYPE(encryption_key, krb5_keyblock, encryption_key_fields);
 DEFPTRTYPE(ptr_encryption_key, encryption_key);
+DEFOPTIONALZEROTYPE(opt_ptr_encryption_key, ptr_encryption_key);
 
 DEFFIELD(checksum_0, krb5_checksum, checksum_type, 0, int32);
 DEFCNFIELD(checksum_1, krb5_checksum, contents, length, 1, octetstring);
 static const struct atype_info *checksum_fields[] = {
     &k5_atype_checksum_0, &k5_atype_checksum_1
 };
-DEFSEQTYPE(checksum, krb5_checksum, checksum_fields, NULL);
+DEFSEQTYPE(checksum, krb5_checksum, checksum_fields);
 DEFPTRTYPE(checksum_ptr, checksum);
 DEFNULLTERMSEQOFTYPE(seqof_checksum, checksum_ptr);
 DEFPTRTYPE(ptr_seqof_checksum, seqof_checksum);
+DEFOPTIONALZEROTYPE(opt_checksum_ptr, checksum_ptr);
 
 DEFFIELD(last_req_0, krb5_last_req_entry, lr_type, 0, int32);
 DEFFIELD(last_req_1, krb5_last_req_entry, value, 1, kerberos_time);
 static const struct atype_info *lr_fields[] = {
     &k5_atype_last_req_0, &k5_atype_last_req_1
 };
-DEFSEQTYPE(last_req_ent, krb5_last_req_entry, lr_fields, NULL);
+DEFSEQTYPE(last_req_ent, krb5_last_req_entry, lr_fields);
 
 DEFPTRTYPE(last_req_ent_ptr, last_req_ent);
 DEFNONEMPTYNULLTERMSEQOFTYPE(last_req, last_req_ent_ptr);
@@ -173,7 +193,7 @@ static const struct atype_info *ticket_fields[] = {
     &k5_atype_ticket_0, &k5_atype_ticket_1, &k5_atype_ticket_2,
     &k5_atype_ticket_3
 };
-DEFSEQTYPE(untagged_ticket, krb5_ticket, ticket_fields, NULL);
+DEFSEQTYPE(untagged_ticket, krb5_ticket, ticket_fields);
 DEFAPPTAGGEDTYPE(ticket, 1, untagged_ticket);
 
 /* First context tag is 1, not 0. */
@@ -182,35 +202,44 @@ DEFCNFIELD(pa_data_2, krb5_pa_data, contents, length, 2, octetstring);
 static const struct atype_info *pa_data_fields[] = {
     &k5_atype_pa_data_1, &k5_atype_pa_data_2
 };
-DEFSEQTYPE(pa_data, krb5_pa_data, pa_data_fields, 0);
+DEFSEQTYPE(pa_data, krb5_pa_data, pa_data_fields);
 DEFPTRTYPE(pa_data_ptr, pa_data);
 
 DEFNULLTERMSEQOFTYPE(seqof_pa_data, pa_data_ptr);
 DEFPTRTYPE(ptr_seqof_pa_data, seqof_pa_data);
+DEFOPTIONALEMPTYTYPE(opt_ptr_seqof_pa_data, ptr_seqof_pa_data);
 
 DEFPTRTYPE(ticket_ptr, ticket);
 DEFNONEMPTYNULLTERMSEQOFTYPE(seqof_ticket,ticket_ptr);
 DEFPTRTYPE(ptr_seqof_ticket, seqof_ticket);
+DEFOPTIONALEMPTYTYPE(opt_ptr_seqof_ticket, ptr_seqof_ticket);
 
+static int
+is_renewable_flag_set(const void *p)
+{
+    const krb5_enc_kdc_rep_part *val = p;
+    return (val->flags & TKT_FLG_RENEWABLE);
+}
 DEFFIELD(enc_kdc_rep_0, krb5_enc_kdc_rep_part, session, 0, ptr_encryption_key);
 DEFFIELD(enc_kdc_rep_1, krb5_enc_kdc_rep_part, last_req, 1, last_req_ptr);
 DEFFIELD(enc_kdc_rep_2, krb5_enc_kdc_rep_part, nonce, 2, int32);
-DEFFIELD(enc_kdc_rep_3, krb5_enc_kdc_rep_part, key_exp, 3, kerberos_time);
+DEFFIELD(enc_kdc_rep_3, krb5_enc_kdc_rep_part, key_exp, 3, opt_kerberos_time);
 DEFFIELD(enc_kdc_rep_4, krb5_enc_kdc_rep_part, flags, 4, krb5_flags);
 DEFFIELD(enc_kdc_rep_5, krb5_enc_kdc_rep_part, times.authtime, 5,
          kerberos_time);
 DEFFIELD(enc_kdc_rep_6, krb5_enc_kdc_rep_part, times.starttime, 6,
-         kerberos_time);
+         opt_kerberos_time);
 DEFFIELD(enc_kdc_rep_7, krb5_enc_kdc_rep_part, times.endtime, 7,
          kerberos_time);
-DEFFIELD(enc_kdc_rep_8, krb5_enc_kdc_rep_part, times.renew_till, 8,
+DEFFIELD(enc_kdc_rep_8_def, krb5_enc_kdc_rep_part, times.renew_till, 8,
          kerberos_time);
+DEFOPTIONALTYPE(enc_kdc_rep_8, is_renewable_flag_set, enc_kdc_rep_8_def);
 DEFFIELD(enc_kdc_rep_9, krb5_enc_kdc_rep_part, server, 9, realm_of_principal);
 DEFFIELD(enc_kdc_rep_10, krb5_enc_kdc_rep_part, server, 10, principal);
 DEFFIELD(enc_kdc_rep_11, krb5_enc_kdc_rep_part, caddrs, 11,
-         ptr_seqof_host_addresses);
+         opt_ptr_seqof_host_addresses);
 DEFFIELD(enc_kdc_rep_12, krb5_enc_kdc_rep_part, enc_padata, 12,
-         ptr_seqof_pa_data);
+         opt_ptr_seqof_pa_data);
 static const struct atype_info *enc_kdc_rep_part_fields[] = {
     &k5_atype_enc_kdc_rep_0, &k5_atype_enc_kdc_rep_1, &k5_atype_enc_kdc_rep_2,
     &k5_atype_enc_kdc_rep_3, &k5_atype_enc_kdc_rep_4, &k5_atype_enc_kdc_rep_5,
@@ -218,25 +247,7 @@ static const struct atype_info *enc_kdc_rep_part_fields[] = {
     &k5_atype_enc_kdc_rep_9, &k5_atype_enc_kdc_rep_10,
     &k5_atype_enc_kdc_rep_11, &k5_atype_enc_kdc_rep_12
 };
-static unsigned int
-optional_enc_kdc_rep_part(const void *p)
-{
-    const krb5_enc_kdc_rep_part *val = p;
-    unsigned int not_present = 0;
-    if (val->key_exp == 0)
-        not_present |= (1u << 3);
-    if (val->times.starttime == 0)
-        not_present |= (1u << 6);
-    if (!(val->flags & TKT_FLG_RENEWABLE))
-        not_present |= (1u << 8);
-    if (val->caddrs == NULL || val->caddrs[0] == NULL)
-        not_present |= (1u << 11);
-    if (val->enc_padata == NULL)
-        not_present |= (1u << 12);
-    return not_present;
-}
-DEFSEQTYPE(enc_kdc_rep_part, krb5_enc_kdc_rep_part, enc_kdc_rep_part_fields,
-           optional_enc_kdc_rep_part);
+DEFSEQTYPE(enc_kdc_rep_part, krb5_enc_kdc_rep_part, enc_kdc_rep_part_fields);
 
 /*
  * Yuck!  Eventually push this *up* above the encoder API and make the
@@ -249,47 +260,26 @@ typedef struct kdc_req_hack {
     krb5_data *server_realm;
 } kdc_req_hack;
 DEFFIELD(req_body_0, kdc_req_hack, v.kdc_options, 0, krb5_flags);
-DEFFIELD(req_body_1, kdc_req_hack, v.client, 1, principal);
+DEFFIELD(req_body_1, kdc_req_hack, v.client, 1, opt_principal);
 DEFFIELD(req_body_2, kdc_req_hack, server_realm, 2, gstring_data_ptr);
-DEFFIELD(req_body_3, kdc_req_hack, v.server, 3, principal);
-DEFFIELD(req_body_4, kdc_req_hack, v.from, 4, kerberos_time);
+DEFFIELD(req_body_3, kdc_req_hack, v.server, 3, opt_principal);
+DEFFIELD(req_body_4, kdc_req_hack, v.from, 4, opt_kerberos_time);
 DEFFIELD(req_body_5, kdc_req_hack, v.till, 5, kerberos_time);
-DEFFIELD(req_body_6, kdc_req_hack, v.rtime, 6, kerberos_time);
+DEFFIELD(req_body_6, kdc_req_hack, v.rtime, 6, opt_kerberos_time);
 DEFFIELD(req_body_7, kdc_req_hack, v.nonce, 7, int32);
 DEFCNFIELD(req_body_8, kdc_req_hack, v.ktype, v.nktypes, 8, cseqof_int32);
-DEFFIELD(req_body_9, kdc_req_hack, v.addresses, 9, ptr_seqof_host_addresses);
-DEFFIELD(req_body_10, kdc_req_hack, v.authorization_data, 10, encrypted_data);
-DEFFIELD(req_body_11, kdc_req_hack, v.second_ticket, 11, ptr_seqof_ticket);
+DEFFIELD(req_body_9, kdc_req_hack, v.addresses, 9,
+         opt_ptr_seqof_host_addresses);
+DEFFIELD(req_body_10, kdc_req_hack, v.authorization_data, 10,
+         opt_encrypted_data);
+DEFFIELD(req_body_11, kdc_req_hack, v.second_ticket, 11, opt_ptr_seqof_ticket);
 static const struct atype_info *kdc_req_hack_fields[] = {
     &k5_atype_req_body_0, &k5_atype_req_body_1, &k5_atype_req_body_2,
     &k5_atype_req_body_3, &k5_atype_req_body_4, &k5_atype_req_body_5,
     &k5_atype_req_body_6, &k5_atype_req_body_7, &k5_atype_req_body_8,
     &k5_atype_req_body_9, &k5_atype_req_body_10, &k5_atype_req_body_11
 };
-static unsigned int
-optional_kdc_req_hack(const void *p)
-{
-    const kdc_req_hack *val2 = p;
-    const krb5_kdc_req *val = &val2->v;
-    unsigned int not_present = 0;
-    if (val->second_ticket == NULL || val->second_ticket[0] == NULL)
-        not_present |= (1u << 11);
-    if (val->authorization_data.ciphertext.data == NULL)
-        not_present |= (1u << 10);
-    if (val->addresses == NULL || val->addresses[0] == NULL)
-        not_present |= (1u << 9);
-    if (val->rtime == 0)
-        not_present |= (1u << 6);
-    if (val->from == 0)
-        not_present |= (1u << 4);
-    if (val->server == NULL)
-        not_present |= (1u << 3);
-    if (val->client == NULL)
-        not_present |= (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(kdc_req_body_hack, kdc_req_hack, kdc_req_hack_fields,
-           optional_kdc_req_hack);
+DEFSEQTYPE(kdc_req_body_hack, kdc_req_hack, kdc_req_hack_fields);
 static asn1_error_code
 encode_kdc_req_body(asn1buf *buf, const void *p, taginfo *tag_out)
 {
@@ -315,117 +305,75 @@ DEFFIELD(transited_1, krb5_transited, tr_contents, 1, ostring_data);
 static const struct atype_info *transited_fields[] = {
     &k5_atype_transited_0, &k5_atype_transited_1
 };
-DEFSEQTYPE(transited, krb5_transited, transited_fields, NULL);
+DEFSEQTYPE(transited, krb5_transited, transited_fields);
 
+static int
+is_safe_timestamp_set(const void *p)
+{
+    const krb5_safe *val = p;
+    return (val->timestamp != 0);
+}
 DEFFIELD(safe_body_0, krb5_safe, user_data, 0, ostring_data);
-DEFFIELD(safe_body_1, krb5_safe, timestamp, 1, kerberos_time);
-DEFFIELD(safe_body_2, krb5_safe, usec, 2, int32);
-DEFFIELD(safe_body_3, krb5_safe, seq_number, 3, uint);
+DEFFIELD(safe_body_1, krb5_safe, timestamp, 1, opt_kerberos_time);
+DEFFIELD(safe_body_2_def, krb5_safe, usec, 2, int32);
+DEFOPTIONALTYPE(safe_body_2, is_safe_timestamp_set, safe_body_2_def);
+DEFFIELD(safe_body_3, krb5_safe, seq_number, 3, opt_ui_4);
 DEFFIELD(safe_body_4, krb5_safe, s_address, 4, address_ptr);
-DEFFIELD(safe_body_5, krb5_safe, r_address, 5, address_ptr);
+DEFFIELD(safe_body_5, krb5_safe, r_address, 5, opt_address_ptr);
 static const struct atype_info *safe_body_fields[] = {
     &k5_atype_safe_body_0, &k5_atype_safe_body_1, &k5_atype_safe_body_2,
     &k5_atype_safe_body_3, &k5_atype_safe_body_4, &k5_atype_safe_body_5
 };
-static unsigned int
-optional_krb_safe_body(const void *p)
-{
-    const krb5_safe *val = p;
-    unsigned int not_present = 0;
-    if (val->timestamp == 0)
-        not_present |= (1u << 1) | (1u << 2);
-    if (val->seq_number == 0)
-        not_present |= (1u << 3);
-    if (val->r_address == NULL)
-        not_present |= (1u << 5);
-    return not_present;
-}
-DEFSEQTYPE(safe_body, krb5_safe, safe_body_fields, optional_krb_safe_body);
+DEFSEQTYPE(safe_body, krb5_safe, safe_body_fields);
 
 DEFFIELD(cred_info_0, krb5_cred_info, session, 0, ptr_encryption_key);
-DEFFIELD(cred_info_1, krb5_cred_info, client, 1, realm_of_principal);
-DEFFIELD(cred_info_2, krb5_cred_info, client, 2, principal);
-DEFFIELD(cred_info_3, krb5_cred_info, flags, 3, krb5_flags);
-DEFFIELD(cred_info_4, krb5_cred_info, times.authtime, 4, kerberos_time);
-DEFFIELD(cred_info_5, krb5_cred_info, times.starttime, 5, kerberos_time);
-DEFFIELD(cred_info_6, krb5_cred_info, times.endtime, 6, kerberos_time);
-DEFFIELD(cred_info_7, krb5_cred_info, times.renew_till, 7, kerberos_time);
-DEFFIELD(cred_info_8, krb5_cred_info, server, 8, realm_of_principal);
-DEFFIELD(cred_info_9, krb5_cred_info, server, 9, principal);
-DEFFIELD(cred_info_10, krb5_cred_info, caddrs, 10, ptr_seqof_host_addresses);
+DEFFIELD(cred_info_1, krb5_cred_info, client, 1, opt_realm_of_principal);
+DEFFIELD(cred_info_2, krb5_cred_info, client, 2, opt_principal);
+DEFFIELD(cred_info_3, krb5_cred_info, flags, 3, opt_krb5_flags);
+DEFFIELD(cred_info_4, krb5_cred_info, times.authtime, 4, opt_kerberos_time);
+DEFFIELD(cred_info_5, krb5_cred_info, times.starttime, 5, opt_kerberos_time);
+DEFFIELD(cred_info_6, krb5_cred_info, times.endtime, 6, opt_kerberos_time);
+DEFFIELD(cred_info_7, krb5_cred_info, times.renew_till, 7, opt_kerberos_time);
+DEFFIELD(cred_info_8, krb5_cred_info, server, 8, opt_realm_of_principal);
+DEFFIELD(cred_info_9, krb5_cred_info, server, 9, opt_principal);
+DEFFIELD(cred_info_10, krb5_cred_info, caddrs, 10,
+         opt_ptr_seqof_host_addresses);
 static const struct atype_info *krb_cred_info_fields[] = {
     &k5_atype_cred_info_0, &k5_atype_cred_info_1, &k5_atype_cred_info_2,
     &k5_atype_cred_info_3, &k5_atype_cred_info_4, &k5_atype_cred_info_5,
     &k5_atype_cred_info_6, &k5_atype_cred_info_7, &k5_atype_cred_info_8,
     &k5_atype_cred_info_9, &k5_atype_cred_info_10
 };
-static unsigned int
-optional_krb_cred_info(const void *p)
-{
-    const krb5_cred_info *val = p;
-    unsigned int not_present = 0;
-    if (val->caddrs == NULL || val->caddrs[0] == NULL)
-        not_present |= (1u << 10);
-    if (val->server == NULL)
-        not_present |= (1u << 9) | (1u << 8);
-    if (val->times.renew_till == 0)
-        not_present |= (1u << 7);
-    if (val->times.endtime == 0)
-        not_present |= (1u << 6);
-    if (val->times.starttime == 0)
-        not_present |= (1u << 5);
-    if (val->times.authtime == 0)
-        not_present |= (1u << 4);
-    if (val->flags == 0)
-        not_present |= (1u << 3);
-    if (val->client == NULL)
-        not_present |= (1u << 2) | (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(cred_info, krb5_cred_info, krb_cred_info_fields,
-           optional_krb_cred_info);
+DEFSEQTYPE(cred_info, krb5_cred_info, krb_cred_info_fields);
 DEFPTRTYPE(cred_info_ptr, cred_info);
 DEFNULLTERMSEQOFTYPE(seqof_cred_info, cred_info_ptr);
 
 DEFPTRTYPE(ptrseqof_cred_info, seqof_cred_info);
 
+static int
+is_etype_info_salt_present(const void *p)
+{
+    const krb5_etype_info_entry *val = p;
+    return (val->length != KRB5_ETYPE_NO_SALT);
+}
 DEFFIELD(etype_info_0, krb5_etype_info_entry, etype, 0, int32);
-DEFCNFIELD(etype_info_1, krb5_etype_info_entry, salt, length, 1, octetstring);
+DEFCNFIELD(etype_info_1_def, krb5_etype_info_entry, salt, length, 1,
+           octetstring);
+DEFOPTIONALTYPE(etype_info_1, is_etype_info_salt_present, etype_info_1_def);
 static const struct atype_info *etype_info_entry_fields[] = {
     &k5_atype_etype_info_0, &k5_atype_etype_info_1
 };
-static unsigned int
-optional_etype_info_entry(const void *vptr)
-{
-    const krb5_etype_info_entry *val = vptr;
-    unsigned int not_present = 0;
-    if (val->length == KRB5_ETYPE_NO_SALT)
-        not_present |= (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(etype_info_entry, krb5_etype_info_entry, etype_info_entry_fields,
-           optional_etype_info_entry);
+DEFSEQTYPE(etype_info_entry, krb5_etype_info_entry, etype_info_entry_fields);
 
 /* First field is the same as etype-info. */
-DEFCNFIELD(etype_info2_1, krb5_etype_info_entry, salt, length, 1,
+DEFCNFIELD(etype_info2_1_def, krb5_etype_info_entry, salt, length, 1,
            u_generalstring);
-DEFFIELD(etype_info2_2, krb5_etype_info_entry, s2kparams, 2, ostring_data);
+DEFOPTIONALTYPE(etype_info2_1, is_etype_info_salt_present, etype_info2_1_def);
+DEFFIELD(etype_info2_2, krb5_etype_info_entry, s2kparams, 2, opt_ostring_data);
 static const struct atype_info *etype_info2_entry_fields[] = {
     &k5_atype_etype_info_0, &k5_atype_etype_info2_1, &k5_atype_etype_info2_2
 };
-static unsigned int
-optional_etype_info2_entry(const void *vptr)
-{
-    const krb5_etype_info_entry *val = vptr;
-    unsigned int not_present = 0;
-    if (val->length == KRB5_ETYPE_NO_SALT)
-        not_present |= (1u << 1);
-    if (val->s2kparams.data == NULL)
-        not_present |= (1u << 2);
-    return not_present;
-}
-DEFSEQTYPE(etype_info2_entry, krb5_etype_info_entry, etype_info2_entry_fields,
-           optional_etype_info2_entry);
+DEFSEQTYPE(etype_info2_entry, krb5_etype_info_entry, etype_info2_entry_fields);
 
 DEFPTRTYPE(etype_info_entry_ptr, etype_info_entry);
 DEFNULLTERMSEQOFTYPE(etype_info, etype_info_entry_ptr);
@@ -438,19 +386,21 @@ DEFFIELD(sch_1, krb5_sam_challenge_2, sam_cksum, 1, ptr_seqof_checksum);
 static const struct atype_info *sam_challenge_2_fields[] = {
     &k5_atype_sch_0, &k5_atype_sch_1
 };
-DEFSEQTYPE(sam_challenge_2, krb5_sam_challenge_2, sam_challenge_2_fields,
-           NULL);
+DEFSEQTYPE(sam_challenge_2, krb5_sam_challenge_2, sam_challenge_2_fields);
 
 DEFFIELD(schb_0, krb5_sam_challenge_2_body, sam_type, 0, int32);
 DEFFIELD(schb_1, krb5_sam_challenge_2_body, sam_flags, 1, krb5_flags);
-DEFFIELD(schb_2, krb5_sam_challenge_2_body, sam_type_name, 2, ostring_data);
-DEFFIELD(schb_3, krb5_sam_challenge_2_body, sam_track_id, 3, ostring_data);
+DEFFIELD(schb_2, krb5_sam_challenge_2_body, sam_type_name, 2,
+         opt_ostring_data);
+DEFFIELD(schb_3, krb5_sam_challenge_2_body, sam_track_id, 3, opt_ostring_data);
 DEFFIELD(schb_4, krb5_sam_challenge_2_body, sam_challenge_label, 4,
-         ostring_data);
-DEFFIELD(schb_5, krb5_sam_challenge_2_body, sam_challenge, 5, ostring_data);
+         opt_ostring_data);
+DEFFIELD(schb_5, krb5_sam_challenge_2_body, sam_challenge, 5,
+         opt_ostring_data);
 DEFFIELD(schb_6, krb5_sam_challenge_2_body, sam_response_prompt, 6,
-         ostring_data);
-DEFFIELD(schb_7, krb5_sam_challenge_2_body, sam_pk_for_sad, 7, ostring_data);
+         opt_ostring_data);
+DEFFIELD(schb_7, krb5_sam_challenge_2_body, sam_pk_for_sad, 7,
+         opt_ostring_data);
 DEFFIELD(schb_8, krb5_sam_challenge_2_body, sam_nonce, 8, int32);
 DEFFIELD(schb_9, krb5_sam_challenge_2_body, sam_etype, 9, int32);
 static const struct atype_info *sam_challenge_2_body_fields[] = {
@@ -458,49 +408,20 @@ static const struct atype_info *sam_challenge_2_body_fields[] = {
     &k5_atype_schb_4, &k5_atype_schb_5, &k5_atype_schb_6, &k5_atype_schb_7,
     &k5_atype_schb_8, &k5_atype_schb_9
 };
-static unsigned int
-optional_sam_challenge_2_body(const void *p)
-{
-    const krb5_sam_challenge_2_body *val = p;
-    unsigned int not_present = 0;
-    if (val->sam_pk_for_sad.length == 0)
-        not_present |= (1u << 7);
-    if (val->sam_response_prompt.length == 0)
-        not_present |= (1u << 6);
-    if (val->sam_challenge.length == 0)
-        not_present |= (1u << 5);
-    if (val->sam_challenge_label.length == 0)
-        not_present |= (1u << 4);
-    if (val->sam_track_id.length == 0)
-        not_present |= (1u << 3);
-    if (val->sam_type_name.length == 0)
-        not_present |= (1u << 2);
-    return not_present;
-}
 DEFSEQTYPE(sam_challenge_2_body,krb5_sam_challenge_2_body,
-           sam_challenge_2_body_fields,
-           optional_sam_challenge_2_body);
+           sam_challenge_2_body_fields);
 
 DEFFIELD(esre_0, krb5_enc_sam_response_enc_2, sam_nonce, 0, int32);
-DEFFIELD(esre_1, krb5_enc_sam_response_enc_2, sam_sad, 1, ostring_data);
+DEFFIELD(esre_1, krb5_enc_sam_response_enc_2, sam_sad, 1, opt_ostring_data);
 static const struct atype_info *enc_sam_response_enc_2_fields[] = {
     &k5_atype_esre_0, &k5_atype_esre_1
 };
-static unsigned int
-optional_enc_sam_response_enc_2(const void *p)
-{
-    const krb5_enc_sam_response_enc_2 *val = p;
-    unsigned int not_present = 0;
-    if (val->sam_sad.length == 0)
-        not_present |= (1u << 1);
-    return not_present;
-}
 DEFSEQTYPE(enc_sam_response_enc_2, krb5_enc_sam_response_enc_2,
-           enc_sam_response_enc_2_fields, optional_enc_sam_response_enc_2);
+           enc_sam_response_enc_2_fields);
 
 DEFFIELD(sam_resp_0, krb5_sam_response_2, sam_type, 0, int32);
 DEFFIELD(sam_resp_1, krb5_sam_response_2, sam_flags, 1, krb5_flags);
-DEFFIELD(sam_resp_2, krb5_sam_response_2, sam_track_id, 2, ostring_data);
+DEFFIELD(sam_resp_2, krb5_sam_response_2, sam_track_id, 2, opt_ostring_data);
 DEFFIELD(sam_resp_3, krb5_sam_response_2, sam_enc_nonce_or_sad, 3,
          encrypted_data);
 DEFFIELD(sam_resp_4, krb5_sam_response_2, sam_nonce, 4, int32);
@@ -508,28 +429,19 @@ static const struct atype_info *sam_response_2_fields[] = {
     &k5_atype_sam_resp_0, &k5_atype_sam_resp_1, &k5_atype_sam_resp_2,
     &k5_atype_sam_resp_3, &k5_atype_sam_resp_4
 };
-static unsigned int
-optional_sam_response_2(const void *p)
-{
-    const krb5_sam_response_2 *val = p;
-    unsigned int not_present = 0;
-    if (val->sam_track_id.length == 0)
-        not_present |= (1u << 2);
-    return not_present;
-}
-DEFSEQTYPE(sam_response_2, krb5_sam_response_2, sam_response_2_fields,
-           optional_sam_response_2);
+DEFSEQTYPE(sam_response_2, krb5_sam_response_2, sam_response_2_fields);
 
 DEFCTAGGEDTYPE(authenticator_0, 0, krb5_version);
 DEFFIELD(authenticator_1, krb5_authenticator, client, 1, realm_of_principal);
 DEFFIELD(authenticator_2, krb5_authenticator, client, 2, principal);
-DEFFIELD(authenticator_3, krb5_authenticator, checksum, 3, checksum_ptr);
+DEFFIELD(authenticator_3, krb5_authenticator, checksum, 3, opt_checksum_ptr);
 DEFFIELD(authenticator_4, krb5_authenticator, cusec, 4, int32);
 DEFFIELD(authenticator_5, krb5_authenticator, ctime, 5, kerberos_time);
-DEFFIELD(authenticator_6, krb5_authenticator, subkey, 6, ptr_encryption_key);
-DEFFIELD(authenticator_7, krb5_authenticator, seq_number, 7, uint);
+DEFFIELD(authenticator_6, krb5_authenticator, subkey, 6,
+         opt_ptr_encryption_key);
+DEFFIELD(authenticator_7, krb5_authenticator, seq_number, 7, opt_ui_4);
 DEFFIELD(authenticator_8, krb5_authenticator, authorization_data, 8,
-         auth_data_ptr);
+         opt_auth_data_ptr);
 static const struct atype_info *authenticator_fields[] = {
     &k5_atype_authenticator_0, &k5_atype_authenticator_1,
     &k5_atype_authenticator_2, &k5_atype_authenticator_3,
@@ -537,23 +449,7 @@ static const struct atype_info *authenticator_fields[] = {
     &k5_atype_authenticator_6, &k5_atype_authenticator_7,
     &k5_atype_authenticator_8
 };
-static unsigned int
-optional_authenticator(const void *p)
-{
-    const krb5_authenticator *val = p;
-    unsigned int not_present = 0;
-    if (val->authorization_data == NULL || val->authorization_data[0] == NULL)
-        not_present |= (1u << 8);
-    if (val->seq_number == 0)
-        not_present |= (1u << 7);
-    if (val->subkey == NULL)
-        not_present |= (1u << 6);
-    if (val->checksum == NULL)
-        not_present |= (1u << 3);
-    return not_present;
-}
-DEFSEQTYPE(untagged_authenticator, krb5_authenticator, authenticator_fields,
-           optional_authenticator);
+DEFSEQTYPE(untagged_authenticator, krb5_authenticator, authenticator_fields);
 DEFAPPTAGGEDTYPE(authenticator, 2, untagged_authenticator);
 
 DEFFIELD(enc_tkt_0, krb5_enc_tkt_part, flags, 0, krb5_flags);
@@ -562,34 +458,20 @@ DEFFIELD(enc_tkt_2, krb5_enc_tkt_part, client, 2, realm_of_principal);
 DEFFIELD(enc_tkt_3, krb5_enc_tkt_part, client, 3, principal);
 DEFFIELD(enc_tkt_4, krb5_enc_tkt_part, transited, 4, transited);
 DEFFIELD(enc_tkt_5, krb5_enc_tkt_part, times.authtime, 5, kerberos_time);
-DEFFIELD(enc_tkt_6, krb5_enc_tkt_part, times.starttime, 6, kerberos_time);
+DEFFIELD(enc_tkt_6, krb5_enc_tkt_part, times.starttime, 6, opt_kerberos_time);
 DEFFIELD(enc_tkt_7, krb5_enc_tkt_part, times.endtime, 7, kerberos_time);
-DEFFIELD(enc_tkt_8, krb5_enc_tkt_part, times.renew_till, 8, kerberos_time);
-DEFFIELD(enc_tkt_9, krb5_enc_tkt_part, caddrs, 9, ptr_seqof_host_addresses);
-DEFFIELD(enc_tkt_10, krb5_enc_tkt_part, authorization_data, 10, auth_data_ptr);
+DEFFIELD(enc_tkt_8, krb5_enc_tkt_part, times.renew_till, 8, opt_kerberos_time);
+DEFFIELD(enc_tkt_9, krb5_enc_tkt_part, caddrs, 9,
+         opt_ptr_seqof_host_addresses);
+DEFFIELD(enc_tkt_10, krb5_enc_tkt_part, authorization_data, 10,
+         opt_auth_data_ptr);
 static const struct atype_info *enc_tkt_part_fields[] = {
     &k5_atype_enc_tkt_0, &k5_atype_enc_tkt_1, &k5_atype_enc_tkt_2,
     &k5_atype_enc_tkt_3, &k5_atype_enc_tkt_4, &k5_atype_enc_tkt_5,
     &k5_atype_enc_tkt_6, &k5_atype_enc_tkt_7, &k5_atype_enc_tkt_8,
     &k5_atype_enc_tkt_9, &k5_atype_enc_tkt_10
 };
-static unsigned int
-optional_enc_tkt_part(const void *p)
-{
-    const krb5_enc_tkt_part *val = p;
-    unsigned int not_present = 0;
-    if (val->authorization_data == NULL || val->authorization_data[0] == NULL)
-        not_present |= (1u << 10);
-    if (val->caddrs == NULL || val->caddrs[0] == NULL)
-        not_present |= (1u << 9);
-    if (val->times.renew_till == 0)
-        not_present |= (1u << 8);
-    if (val->times.starttime == 0)
-        not_present |= (1u << 6);
-    return not_present;
-}
-DEFSEQTYPE(untagged_enc_tkt_part, krb5_enc_tkt_part, enc_tkt_part_fields,
-           optional_enc_tkt_part);
+DEFSEQTYPE(untagged_enc_tkt_part, krb5_enc_tkt_part, enc_tkt_part_fields);
 DEFAPPTAGGEDTYPE(enc_tkt_part, 3, untagged_enc_tkt_part);
 
 DEFAPPTAGGEDTYPE(enc_tgs_rep_part, 26, enc_kdc_rep_part);
@@ -597,7 +479,7 @@ DEFAPPTAGGEDTYPE(enc_tgs_rep_part, 26, enc_kdc_rep_part);
 DEFINT_IMMEDIATE(as_rep_msg_type, KRB5_AS_REP);
 DEFCTAGGEDTYPE(kdc_rep_0, 0, krb5_version);
 DEFCTAGGEDTYPE(as_rep_1, 1, as_rep_msg_type);
-DEFFIELD(kdc_rep_2, krb5_kdc_rep, padata, 2, ptr_seqof_pa_data);
+DEFFIELD(kdc_rep_2, krb5_kdc_rep, padata, 2, opt_ptr_seqof_pa_data);
 DEFFIELD(kdc_rep_3, krb5_kdc_rep, client, 3, realm_of_principal);
 DEFFIELD(kdc_rep_4, krb5_kdc_rep, client, 4, principal);
 DEFFIELD(kdc_rep_5, krb5_kdc_rep, ticket, 5, ticket_ptr);
@@ -607,16 +489,7 @@ static const struct atype_info *as_rep_fields[] = {
     &k5_atype_kdc_rep_3, &k5_atype_kdc_rep_4, &k5_atype_kdc_rep_5,
     &k5_atype_kdc_rep_6
 };
-static unsigned int
-optional_kdc_rep(const void *p)
-{
-    const krb5_kdc_rep *val = p;
-    unsigned int not_present = 0;
-    if (val->padata == NULL || val->padata[0] == NULL)
-        not_present |= (1u << 2);
-    return not_present;
-}
-DEFSEQTYPE(untagged_as_rep, krb5_kdc_rep, as_rep_fields, optional_kdc_rep);
+DEFSEQTYPE(untagged_as_rep, krb5_kdc_rep, as_rep_fields);
 DEFAPPTAGGEDTYPE(as_rep, 11, untagged_as_rep);
 
 /* TGS-REP ::= [APPLICATION 13] KDC-REP */
@@ -629,7 +502,7 @@ static const struct atype_info *tgs_rep_fields[] = {
     &k5_atype_kdc_rep_3, &k5_atype_kdc_rep_4, &k5_atype_kdc_rep_5,
     &k5_atype_kdc_rep_6
 };
-DEFSEQTYPE(untagged_tgs_rep, krb5_kdc_rep, tgs_rep_fields, optional_kdc_rep);
+DEFSEQTYPE(untagged_tgs_rep, krb5_kdc_rep, tgs_rep_fields);
 DEFAPPTAGGEDTYPE(tgs_rep, 13, untagged_tgs_rep);
 
 DEFINT_IMMEDIATE(ap_req_msg_type, ASN1_KRB_AP_REQ);
@@ -642,7 +515,7 @@ static const struct atype_info *ap_req_fields[] = {
     &k5_atype_ap_req_0, &k5_atype_ap_req_1, &k5_atype_ap_req_2,
     &k5_atype_ap_req_3, &k5_atype_ap_req_4
 };
-DEFSEQTYPE(untagged_ap_req, krb5_ap_req, ap_req_fields, NULL);
+DEFSEQTYPE(untagged_ap_req, krb5_ap_req, ap_req_fields);
 DEFAPPTAGGEDTYPE(ap_req, 14, untagged_ap_req);
 
 DEFINT_IMMEDIATE(ap_rep_msg_type, ASN1_KRB_AP_REP);
@@ -652,31 +525,20 @@ DEFFIELD(ap_rep_2, krb5_ap_rep, enc_part, 2, encrypted_data);
 static const struct atype_info *ap_rep_fields[] = {
     &k5_atype_ap_rep_0, &k5_atype_ap_rep_1, &k5_atype_ap_rep_2
 };
-DEFSEQTYPE(untagged_ap_rep, krb5_ap_rep, ap_rep_fields, NULL);
+DEFSEQTYPE(untagged_ap_rep, krb5_ap_rep, ap_rep_fields);
 DEFAPPTAGGEDTYPE(ap_rep, 15, untagged_ap_rep);
 
 DEFFIELD(ap_rep_enc_part_0, krb5_ap_rep_enc_part, ctime, 0, kerberos_time);
 DEFFIELD(ap_rep_enc_part_1, krb5_ap_rep_enc_part, cusec, 1, int32);
 DEFFIELD(ap_rep_enc_part_2, krb5_ap_rep_enc_part, subkey, 2,
-         ptr_encryption_key);
-DEFFIELD(ap_rep_enc_part_3, krb5_ap_rep_enc_part, seq_number, 3, uint);
+         opt_ptr_encryption_key);
+DEFFIELD(ap_rep_enc_part_3, krb5_ap_rep_enc_part, seq_number, 3, opt_ui_4);
 static const struct atype_info *ap_rep_enc_part_fields[] = {
     &k5_atype_ap_rep_enc_part_0, &k5_atype_ap_rep_enc_part_1,
     &k5_atype_ap_rep_enc_part_2, &k5_atype_ap_rep_enc_part_3
 };
-static unsigned int
-optional_ap_rep_enc_part(const void *p)
-{
-    const krb5_ap_rep_enc_part *val = p;
-    unsigned int not_present = 0;
-    if (val->seq_number == 0)
-        not_present |= (1u << 3);
-    if (val->subkey == NULL)
-        not_present |= (1u << 2);
-    return not_present;
-}
 DEFSEQTYPE(untagged_ap_rep_enc_part, krb5_ap_rep_enc_part,
-           ap_rep_enc_part_fields, optional_ap_rep_enc_part);
+           ap_rep_enc_part_fields);
 DEFAPPTAGGEDTYPE(ap_rep_enc_part, 27, untagged_ap_rep_enc_part);
 
 /* First context tag is 1.  Fourth field is the encoding of the krb5_kdc_req
@@ -684,22 +546,13 @@ DEFAPPTAGGEDTYPE(ap_rep_enc_part, 27, untagged_ap_rep_enc_part);
 DEFINT_IMMEDIATE(as_req_msg_type, KRB5_AS_REQ);
 DEFCTAGGEDTYPE(as_req_1, 1, krb5_version);
 DEFCTAGGEDTYPE(as_req_2, 2, as_req_msg_type);
-DEFFIELD(as_req_3, krb5_kdc_req, padata, 3, ptr_seqof_pa_data);
+DEFFIELD(as_req_3, krb5_kdc_req, padata, 3, opt_ptr_seqof_pa_data);
 DEFCTAGGEDTYPE(as_req_4, 4, kdc_req_body);
 static const struct atype_info *as_req_fields[] = {
     &k5_atype_as_req_1, &k5_atype_as_req_2, &k5_atype_as_req_3,
     &k5_atype_as_req_4
 };
-static unsigned int
-optional_as_req(const void *p)
-{
-    const krb5_kdc_req *val = p;
-    unsigned int not_present = 0;
-    if (val->padata == NULL || val->padata[0] == NULL)
-        not_present |= (1u << 2);
-    return not_present;
-}
-DEFSEQTYPE(untagged_as_req, krb5_kdc_req, as_req_fields, optional_as_req);
+DEFSEQTYPE(untagged_as_req, krb5_kdc_req, as_req_fields);
 DEFAPPTAGGEDTYPE(as_req, 10, untagged_as_req);
 
 /* Most fields are the same as as_req. */
@@ -709,8 +562,7 @@ static const struct atype_info *tgs_req_fields[] = {
     &k5_atype_as_req_1, &k5_atype_tgs_req_2, &k5_atype_as_req_3,
     &k5_atype_as_req_4
 };
-DEFSEQTYPE(untagged_tgs_req, krb5_kdc_req, tgs_req_fields,
-           optional_as_req);
+DEFSEQTYPE(untagged_tgs_req, krb5_kdc_req, tgs_req_fields);
 DEFAPPTAGGEDTYPE(tgs_req, 12, untagged_tgs_req);
 
 DEFINT_IMMEDIATE(safe_msg_type, ASN1_KRB_SAFE);
@@ -721,7 +573,7 @@ DEFFIELD(safe_3, krb5_safe, checksum, 3, checksum_ptr);
 static const struct atype_info *safe_fields[] = {
     &k5_atype_safe_0, &k5_atype_safe_1, &k5_atype_safe_2, &k5_atype_safe_3
 };
-DEFSEQTYPE(untagged_safe, krb5_safe, safe_fields, NULL);
+DEFSEQTYPE(untagged_safe, krb5_safe, safe_fields);
 DEFAPPTAGGEDTYPE(safe, 20, untagged_safe);
 
 /* Hack to encode a KRB-SAFE with a pre-specified body encoding.  The integer-
@@ -738,7 +590,7 @@ static const struct atype_info *safe_with_body_fields[] = {
     &k5_atype_safe_with_body_3
 };
 DEFSEQTYPE(untagged_safe_with_body, struct krb5_safe_with_body,
-           safe_with_body_fields, NULL);
+           safe_with_body_fields);
 DEFAPPTAGGEDTYPE(safe_with_body, 20, untagged_safe_with_body);
 
 /* Third tag is [3] instead of [2]. */
@@ -749,35 +601,28 @@ DEFFIELD(priv_3, krb5_priv, enc_part, 3, encrypted_data);
 static const struct atype_info *priv_fields[] = {
     &k5_atype_priv_0, &k5_atype_priv_1, &k5_atype_priv_3
 };
-DEFSEQTYPE(untagged_priv, krb5_priv, priv_fields, NULL);
+DEFSEQTYPE(untagged_priv, krb5_priv, priv_fields);
 DEFAPPTAGGEDTYPE(priv, 21, untagged_priv);
 
+static int
+is_priv_timestamp_set(const void *p)
+{
+    const krb5_priv_enc_part *val = p;
+    return (val->timestamp != 0);
+}
 DEFFIELD(priv_enc_part_0, krb5_priv_enc_part, user_data, 0, ostring_data);
-DEFFIELD(priv_enc_part_1, krb5_priv_enc_part, timestamp, 1, kerberos_time);
-DEFFIELD(priv_enc_part_2, krb5_priv_enc_part, usec, 2, int32);
-DEFFIELD(priv_enc_part_3, krb5_priv_enc_part, seq_number, 3, uint);
+DEFFIELD(priv_enc_part_1, krb5_priv_enc_part, timestamp, 1, opt_kerberos_time);
+DEFFIELD(priv_enc_part_2_def, krb5_priv_enc_part, usec, 2, int32);
+DEFOPTIONALTYPE(priv_enc_part_2, is_priv_timestamp_set, priv_enc_part_2_def);
+DEFFIELD(priv_enc_part_3, krb5_priv_enc_part, seq_number, 3, opt_ui_4);
 DEFFIELD(priv_enc_part_4, krb5_priv_enc_part, s_address, 4, address_ptr);
-DEFFIELD(priv_enc_part_5, krb5_priv_enc_part, r_address, 5, address_ptr);
+DEFFIELD(priv_enc_part_5, krb5_priv_enc_part, r_address, 5, opt_address_ptr);
 static const struct atype_info *priv_enc_part_fields[] = {
     &k5_atype_priv_enc_part_0, &k5_atype_priv_enc_part_1,
     &k5_atype_priv_enc_part_2, &k5_atype_priv_enc_part_3,
     &k5_atype_priv_enc_part_4, &k5_atype_priv_enc_part_5
 };
-static unsigned int
-optional_priv_enc_part(const void *p)
-{
-    const krb5_priv_enc_part *val = p;
-    unsigned int not_present = 0;
-    if (val->timestamp == 0)
-        not_present |= (1u << 2) | (1u << 1);
-    if (val->seq_number == 0)
-        not_present |= (1u << 3);
-    if (val->r_address == NULL)
-        not_present |= (1u << 5);
-    return not_present;
-}
-DEFSEQTYPE(untagged_priv_enc_part, krb5_priv_enc_part, priv_enc_part_fields,
-           optional_priv_enc_part);
+DEFSEQTYPE(untagged_priv_enc_part, krb5_priv_enc_part, priv_enc_part_fields);
 DEFAPPTAGGEDTYPE(priv_enc_part, 28, untagged_priv_enc_part);
 
 DEFINT_IMMEDIATE(cred_msg_type, ASN1_KRB_CRED);
@@ -788,95 +633,60 @@ DEFFIELD(cred_3, krb5_cred, enc_part, 3, encrypted_data);
 static const struct atype_info *cred_fields[] = {
     &k5_atype_cred_0, &k5_atype_cred_1, &k5_atype_cred_2, &k5_atype_cred_3
 };
-DEFSEQTYPE(untagged_cred, krb5_cred, cred_fields, NULL);
+DEFSEQTYPE(untagged_cred, krb5_cred, cred_fields);
 DEFAPPTAGGEDTYPE(krb5_cred, 22, untagged_cred);
 
+static int
+is_cred_timestamp_set(const void *p)
+{
+    const krb5_cred_enc_part *val = p;
+    return (val->timestamp != 0);
+}
 DEFFIELD(enc_cred_part_0, krb5_cred_enc_part, ticket_info, 0,
          ptrseqof_cred_info);
-DEFFIELD(enc_cred_part_1, krb5_cred_enc_part, nonce, 1, int32);
-DEFFIELD(enc_cred_part_2, krb5_cred_enc_part, timestamp, 2, kerberos_time);
-DEFFIELD(enc_cred_part_3, krb5_cred_enc_part, usec, 3, int32);
-DEFFIELD(enc_cred_part_4, krb5_cred_enc_part, s_address, 4, address_ptr);
-DEFFIELD(enc_cred_part_5, krb5_cred_enc_part, r_address, 5, address_ptr);
+DEFFIELD(enc_cred_part_1, krb5_cred_enc_part, nonce, 1, opt_int32);
+DEFFIELD(enc_cred_part_2, krb5_cred_enc_part, timestamp, 2, opt_kerberos_time);
+DEFFIELD(enc_cred_part_3_def, krb5_cred_enc_part, usec, 3, int32);
+DEFOPTIONALTYPE(enc_cred_part_3, is_cred_timestamp_set, enc_cred_part_3_def);
+DEFFIELD(enc_cred_part_4, krb5_cred_enc_part, s_address, 4, opt_address_ptr);
+DEFFIELD(enc_cred_part_5, krb5_cred_enc_part, r_address, 5, opt_address_ptr);
 static const struct atype_info *enc_cred_part_fields[] = {
     &k5_atype_enc_cred_part_0, &k5_atype_enc_cred_part_1,
     &k5_atype_enc_cred_part_2, &k5_atype_enc_cred_part_3,
     &k5_atype_enc_cred_part_4, &k5_atype_enc_cred_part_5
 };
-static unsigned int
-optional_enc_cred_part(const void *p)
-{
-    const krb5_cred_enc_part *val = p;
-    unsigned int not_present = 0;
-    if (val->r_address == NULL)
-        not_present |= (1u << 5);
-    if (val->s_address == NULL)
-        not_present |= (1u << 4);
-    if (val->timestamp == 0)
-        not_present |= (1u << 2) | (1u << 3);
-    if (val->nonce == 0)
-        not_present |= (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(untagged_enc_cred_part, krb5_cred_enc_part, enc_cred_part_fields,
-           optional_enc_cred_part);
+DEFSEQTYPE(untagged_enc_cred_part, krb5_cred_enc_part, enc_cred_part_fields);
 DEFAPPTAGGEDTYPE(enc_cred_part, 29, untagged_enc_cred_part);
 
 DEFINT_IMMEDIATE(error_msg_type, ASN1_KRB_ERROR);
 DEFCTAGGEDTYPE(error_0, 0, krb5_version);
 DEFCTAGGEDTYPE(error_1, 1, error_msg_type);
-DEFFIELD(error_2, krb5_error, ctime, 2, kerberos_time);
-DEFFIELD(error_3, krb5_error, cusec, 3, int32);
+DEFFIELD(error_2, krb5_error, ctime, 2, opt_kerberos_time);
+DEFFIELD(error_3, krb5_error, cusec, 3, opt_int32);
 DEFFIELD(error_4, krb5_error, stime, 4, kerberos_time);
 DEFFIELD(error_5, krb5_error, susec, 5, int32);
 DEFFIELD(error_6, krb5_error, error, 6, ui_4);
-DEFFIELD(error_7, krb5_error, client, 7, realm_of_principal);
-DEFFIELD(error_8, krb5_error, client, 8, principal);
+DEFFIELD(error_7, krb5_error, client, 7, opt_realm_of_principal);
+DEFFIELD(error_8, krb5_error, client, 8, opt_principal);
 DEFFIELD(error_9, krb5_error, server, 9, realm_of_principal);
 DEFFIELD(error_10, krb5_error, server, 10, principal);
-DEFFIELD(error_11, krb5_error, text, 11, gstring_data);
-DEFFIELD(error_12, krb5_error, e_data, 12, ostring_data);
+DEFFIELD(error_11, krb5_error, text, 11, opt_gstring_data);
+DEFFIELD(error_12, krb5_error, e_data, 12, opt_ostring_data);
 static const struct atype_info *error_fields[] = {
     &k5_atype_error_0, &k5_atype_error_1, &k5_atype_error_2, &k5_atype_error_3,
     &k5_atype_error_4, &k5_atype_error_5, &k5_atype_error_6, &k5_atype_error_7,
     &k5_atype_error_8, &k5_atype_error_9, &k5_atype_error_10,
     &k5_atype_error_11, &k5_atype_error_12
 };
-static unsigned int
-optional_error(const void *p)
-{
-    const krb5_error *val = p;
-    unsigned int not_present = 0;
-    if (val->ctime == 0)
-        not_present |= (1u << 2);
-    if (val->cusec == 0)
-        not_present |= (1u << 3);
-    if (val->client == NULL)
-        not_present |= (1u << 7) | (1u << 8);
-    if (val->text.data == NULL || val->text.length == 0)
-        not_present |= (1u << 11);
-    if (val->e_data.data == NULL || val->e_data.length == 0)
-        not_present |= (1u << 12);
-    return not_present;
-}
-DEFSEQTYPE(untagged_krb5_error, krb5_error, error_fields, optional_error);
+DEFSEQTYPE(untagged_krb5_error, krb5_error, error_fields);
 DEFAPPTAGGEDTYPE(krb5_error, 30, untagged_krb5_error);
 
 DEFFIELD(pa_enc_ts_0, krb5_pa_enc_ts, patimestamp, 0, kerberos_time);
-DEFFIELD(pa_enc_ts_1, krb5_pa_enc_ts, pausec, 1, int32);
+DEFFIELD(pa_enc_ts_1, krb5_pa_enc_ts, pausec, 1, opt_int32);
 static const struct atype_info *pa_enc_ts_fields[] = {
     &k5_atype_pa_enc_ts_0, &k5_atype_pa_enc_ts_1
 };
-static unsigned int
-optional_pa_enc_ts(const void *p)
-{
-    const krb5_pa_enc_ts *val = p;
-    unsigned int not_present = 0;
-    if (val->pausec == 0)
-        not_present |= (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(pa_enc_ts, krb5_pa_enc_ts, pa_enc_ts_fields, optional_pa_enc_ts);
+DEFSEQTYPE(pa_enc_ts, krb5_pa_enc_ts, pa_enc_ts_fields);
 
 DEFFIELD(setpw_0, struct krb5_setpw_req, password, 0, ostring_data);
 DEFFIELD(setpw_1, struct krb5_setpw_req, target, 1, principal);
@@ -884,7 +694,7 @@ DEFFIELD(setpw_2, struct krb5_setpw_req, target, 2, realm_of_principal);
 static const struct atype_info *setpw_req_fields[] = {
     &k5_atype_setpw_0, &k5_atype_setpw_1, &k5_atype_setpw_2
 };
-DEFSEQTYPE(setpw_req, struct krb5_setpw_req, setpw_req_fields, NULL);
+DEFSEQTYPE(setpw_req, struct krb5_setpw_req, setpw_req_fields);
 
 /* [MS-SFU] Section 2.2.1. */
 DEFFIELD(pa_for_user_0, krb5_pa_for_user, user, 0, principal);
@@ -895,41 +705,34 @@ static const struct atype_info *pa_for_user_fields[] = {
     &k5_atype_pa_for_user_0, &k5_atype_pa_for_user_1, &k5_atype_pa_for_user_2,
     &k5_atype_pa_for_user_3,
 };
-DEFSEQTYPE(pa_for_user, krb5_pa_for_user, pa_for_user_fields, NULL);
+DEFSEQTYPE(pa_for_user, krb5_pa_for_user, pa_for_user_fields);
 
 /* [MS-SFU] Section 2.2.2. */
+/* The user principal name may be absent, but the realm is required. */
+static int
+is_s4u_principal_present(const void *p)
+{
+    krb5_const_principal val = *(krb5_const_principal *)p;
+    return (val->length != 0);
+}
+DEFOPTIONALTYPE(opt_s4u_principal, is_s4u_principal_present, principal);
 DEFFIELD(s4u_userid_0, krb5_s4u_userid, nonce, 0, int32);
-DEFFIELD(s4u_userid_1, krb5_s4u_userid, user, 1, principal);
+DEFFIELD(s4u_userid_1, krb5_s4u_userid, user, 1, opt_s4u_principal);
 DEFFIELD(s4u_userid_2, krb5_s4u_userid, user, 2, realm_of_principal);
-DEFFIELD(s4u_userid_3, krb5_s4u_userid, subject_cert, 3, ostring_data);
-DEFFIELD(s4u_userid_4, krb5_s4u_userid, options, 4, krb5_flags);
+DEFFIELD(s4u_userid_3, krb5_s4u_userid, subject_cert, 3, opt_ostring_data);
+DEFFIELD(s4u_userid_4, krb5_s4u_userid, options, 4, opt_krb5_flags);
 static const struct atype_info *s4u_userid_fields[] = {
     &k5_atype_s4u_userid_0, &k5_atype_s4u_userid_1, &k5_atype_s4u_userid_2,
     &k5_atype_s4u_userid_3, &k5_atype_s4u_userid_4
 };
-static unsigned int
-s4u_userid_optional(const void *p)
-{
-    const krb5_s4u_userid *val = p;
-    unsigned int not_present = 0;
-    if (val->user == NULL || val->user->length == 0)
-        not_present |= (1u << 1);
-    if (val->subject_cert.length == 0)
-        not_present |= (1u << 3);
-    if (val->options == 0)
-        not_present |= (1u << 4);
-    return not_present;
-}
-DEFSEQTYPE(s4u_userid, krb5_s4u_userid, s4u_userid_fields,
-           s4u_userid_optional);
+DEFSEQTYPE(s4u_userid, krb5_s4u_userid, s4u_userid_fields);
 
 DEFFIELD(pa_s4u_x509_user_0, krb5_pa_s4u_x509_user, user_id, 0, s4u_userid);
 DEFFIELD(pa_s4u_x509_user_1, krb5_pa_s4u_x509_user, cksum, 1, checksum);
 static const struct atype_info *pa_s4u_x509_user_fields[] = {
     &k5_atype_pa_s4u_x509_user_0, &k5_atype_pa_s4u_x509_user_1
 };
-DEFSEQTYPE(pa_s4u_x509_user, krb5_pa_s4u_x509_user, pa_s4u_x509_user_fields,
-           NULL);
+DEFSEQTYPE(pa_s4u_x509_user, krb5_pa_s4u_x509_user, pa_s4u_x509_user_fields);
 
 /* RFC 4537 */
 DEFCOUNTEDTYPE(etype_list, krb5_etype_list, etypes, length, cseqof_int32);
@@ -940,10 +743,12 @@ DEFFIELD(fast_armor_1, krb5_fast_armor, armor_value, 1, ostring_data);
 static const struct atype_info *fast_armor_fields[] = {
     &k5_atype_fast_armor_0, &k5_atype_fast_armor_1
 };
-DEFSEQTYPE(fast_armor, krb5_fast_armor, fast_armor_fields, NULL);
+DEFSEQTYPE(fast_armor, krb5_fast_armor, fast_armor_fields);
 DEFPTRTYPE(ptr_fast_armor, fast_armor);
+DEFOPTIONALZEROTYPE(opt_ptr_fast_armor, ptr_fast_armor);
 
-DEFFIELD(fast_armored_req_0, krb5_fast_armored_req, armor, 0, ptr_fast_armor);
+DEFFIELD(fast_armored_req_0, krb5_fast_armored_req, armor, 0,
+         opt_ptr_fast_armor);
 DEFFIELD(fast_armored_req_1, krb5_fast_armored_req, req_checksum, 1, checksum);
 DEFFIELD(fast_armored_req_2, krb5_fast_armored_req, enc_part, 2,
          encrypted_data);
@@ -951,17 +756,7 @@ static const struct atype_info *fast_armored_req_fields[] = {
     &k5_atype_fast_armored_req_0, &k5_atype_fast_armored_req_1,
     &k5_atype_fast_armored_req_2
 };
-static unsigned int
-fast_armored_req_optional(const void *p)
-{
-    const krb5_fast_armored_req *val = p;
-    unsigned int not_present = 0;
-    if (val->armor == NULL)
-        not_present |= (1u << 0);
-    return not_present;
-}
-DEFSEQTYPE(fast_armored_req, krb5_fast_armored_req, fast_armored_req_fields,
-           fast_armored_req_optional);
+DEFSEQTYPE(fast_armored_req, krb5_fast_armored_req, fast_armored_req_fields);
 
 /* This is a CHOICE type with only one choice (so far) and we're not using a
  * distinguisher/union for it. */
@@ -977,7 +772,7 @@ DEFFIELD(fast_req_2, krb5_fast_req, req_body, 2, ptr_kdc_req_body);
 static const struct atype_info *fast_req_fields[] = {
     &k5_atype_fast_req_0, &k5_atype_fast_req_1, &k5_atype_fast_req_2
 };
-DEFSEQTYPE(fast_req, krb5_fast_req, fast_req_fields, NULL);
+DEFSEQTYPE(fast_req, krb5_fast_req, fast_req_fields);
 
 DEFFIELD(fast_finished_0, krb5_fast_finished, timestamp, 0, kerberos_time);
 DEFFIELD(fast_finished_1, krb5_fast_finished, usec, 1, int32);
@@ -989,37 +784,27 @@ static const struct atype_info *fast_finished_fields[] = {
     &k5_atype_fast_finished_2, &k5_atype_fast_finished_3,
     &k5_atype_fast_finished_4
 };
-DEFSEQTYPE(fast_finished, krb5_fast_finished, fast_finished_fields, NULL);
+DEFSEQTYPE(fast_finished, krb5_fast_finished, fast_finished_fields);
 DEFPTRTYPE(ptr_fast_finished, fast_finished);
+DEFOPTIONALZEROTYPE(opt_ptr_fast_finished, ptr_fast_finished);
 
 DEFFIELD(fast_response_0, krb5_fast_response, padata, 0, ptr_seqof_pa_data);
 DEFFIELD(fast_response_1, krb5_fast_response, strengthen_key, 1,
-         ptr_encryption_key);
-DEFFIELD(fast_response_2, krb5_fast_response, finished, 2, ptr_fast_finished);
+         opt_ptr_encryption_key);
+DEFFIELD(fast_response_2, krb5_fast_response, finished, 2,
+         opt_ptr_fast_finished);
 DEFFIELD(fast_response_3, krb5_fast_response, nonce, 3, int32);
 static const struct atype_info *fast_response_fields[] = {
     &k5_atype_fast_response_0, &k5_atype_fast_response_1,
     &k5_atype_fast_response_2, &k5_atype_fast_response_3
 };
-static unsigned int
-fast_response_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_fast_response *val = p;
-    if (val->strengthen_key == NULL)
-        not_present |= (1u <<1);
-    if (val->finished == NULL)
-        not_present |= (1u<<2);
-    return not_present;
-}
-DEFSEQTYPE(fast_response, krb5_fast_response, fast_response_fields,
-           fast_response_optional);
+DEFSEQTYPE(fast_response, krb5_fast_response, fast_response_fields);
 
 DEFCTAGGEDTYPE(fast_rep_0, 0, encrypted_data);
 static const struct atype_info *fast_rep_fields[] = {
     &k5_atype_fast_rep_0
 };
-DEFSEQTYPE(fast_rep, krb5_enc_data, fast_rep_fields, NULL);
+DEFSEQTYPE(fast_rep, krb5_enc_data, fast_rep_fields);
 
 /* This is a CHOICE type with only one choice (so far) and we're not using a
  * distinguisher/union for it. */
@@ -1028,111 +813,69 @@ DEFTAGGEDTYPE(pa_fx_fast_reply, CONTEXT_SPECIFIC, CONSTRUCTED, 0, 0,
 
 DEFFIELD(ad_kdcissued_0, krb5_ad_kdcissued, ad_checksum, 0, checksum);
 DEFFIELD(ad_kdcissued_1, krb5_ad_kdcissued, i_principal, 1,
-         realm_of_principal);
-DEFFIELD(ad_kdcissued_2, krb5_ad_kdcissued, i_principal, 2, principal);
+         opt_realm_of_principal);
+DEFFIELD(ad_kdcissued_2, krb5_ad_kdcissued, i_principal, 2, opt_principal);
 DEFFIELD(ad_kdcissued_3, krb5_ad_kdcissued, elements, 3, auth_data_ptr);
 static const struct atype_info *ad_kdcissued_fields[] = {
     &k5_atype_ad_kdcissued_0, &k5_atype_ad_kdcissued_1,
     &k5_atype_ad_kdcissued_2, &k5_atype_ad_kdcissued_3
 };
-static unsigned int
-ad_kdcissued_optional(const void *p)
-{
-    unsigned int optional = 0;
-    const krb5_ad_kdcissued *val = p;
-    if (val->i_principal == NULL)
-        optional |= (1u << 1) | (1u << 2);
-    return optional;
-}
-DEFSEQTYPE(ad_kdc_issued, krb5_ad_kdcissued, ad_kdcissued_fields,
-           ad_kdcissued_optional);
+DEFSEQTYPE(ad_kdc_issued, krb5_ad_kdcissued, ad_kdcissued_fields);
 
 DEFCTAGGEDTYPE(princ_plus_realm_0, 0, principal_data);
 DEFCTAGGEDTYPE(princ_plus_realm_1, 1, realm_of_principal_data);
 static const struct atype_info *princ_plus_realm_fields[] = {
     &k5_atype_princ_plus_realm_0, &k5_atype_princ_plus_realm_1
 };
-DEFSEQTYPE(princ_plus_realm_data, krb5_principal_data, princ_plus_realm_fields,
-           NULL);
+DEFSEQTYPE(princ_plus_realm_data, krb5_principal_data,
+           princ_plus_realm_fields);
 DEFPTRTYPE(princ_plus_realm, princ_plus_realm_data);
 DEFNULLTERMSEQOFTYPE(seqof_princ_plus_realm, princ_plus_realm);
 DEFPTRTYPE(ptr_seqof_princ_plus_realm, seqof_princ_plus_realm);
+DEFOPTIONALEMPTYTYPE(opt_ptr_seqof_princ_plus_realm,
+                     ptr_seqof_princ_plus_realm);
 
 DEFFIELD(spdata_0, krb5_ad_signedpath_data, client, 0, princ_plus_realm);
 DEFFIELD(spdata_1, krb5_ad_signedpath_data, authtime, 1, kerberos_time);
 DEFFIELD(spdata_2, krb5_ad_signedpath_data, delegated, 2,
-         ptr_seqof_princ_plus_realm);
-DEFFIELD(spdata_3, krb5_ad_signedpath_data, method_data, 3, ptr_seqof_pa_data);
+         opt_ptr_seqof_princ_plus_realm);
+DEFFIELD(spdata_3, krb5_ad_signedpath_data, method_data, 3,
+         opt_ptr_seqof_pa_data);
 DEFFIELD(spdata_4, krb5_ad_signedpath_data, authorization_data, 4,
-         auth_data_ptr);
+         opt_auth_data_ptr);
 static const struct atype_info *ad_signedpath_data_fields[] = {
     &k5_atype_spdata_0, &k5_atype_spdata_1, &k5_atype_spdata_2,
     &k5_atype_spdata_3, &k5_atype_spdata_4
 };
-static unsigned int
-ad_signedpath_data_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_ad_signedpath_data *val = p;
-    if (val->delegated == NULL || val->delegated[0] == NULL)
-        not_present |= (1u << 2);
-    if (val->method_data == NULL || val->method_data[0] == NULL)
-        not_present |= (1u << 3);
-    if (val->authorization_data == NULL || val->authorization_data[0] == NULL)
-        not_present |= (1u << 4);
-    return not_present;
-}
 DEFSEQTYPE(ad_signedpath_data, krb5_ad_signedpath_data,
-           ad_signedpath_data_fields, ad_signedpath_data_optional);
+           ad_signedpath_data_fields);
 
 DEFFIELD(signedpath_0, krb5_ad_signedpath, enctype, 0, int32);
 DEFFIELD(signedpath_1, krb5_ad_signedpath, checksum, 1, checksum);
 DEFFIELD(signedpath_2, krb5_ad_signedpath, delegated, 2,
-         ptr_seqof_princ_plus_realm);
-DEFFIELD(signedpath_3, krb5_ad_signedpath, method_data, 3, ptr_seqof_pa_data);
+         opt_ptr_seqof_princ_plus_realm);
+DEFFIELD(signedpath_3, krb5_ad_signedpath, method_data, 3,
+         opt_ptr_seqof_pa_data);
 static const struct atype_info *ad_signedpath_fields[] = {
     &k5_atype_signedpath_0, &k5_atype_signedpath_1, &k5_atype_signedpath_2,
     &k5_atype_signedpath_3
 };
-static unsigned int
-ad_signedpath_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_ad_signedpath *val = p;
-    if (val->delegated == NULL || val->delegated[0] == NULL)
-        not_present |= (1u << 2);
-    if (val->method_data == NULL || val->method_data[0] == NULL)
-        not_present |= (1u << 3);
-    return not_present;
-}
-DEFSEQTYPE(ad_signedpath, krb5_ad_signedpath, ad_signedpath_fields,
-           ad_signedpath_optional);
+DEFSEQTYPE(ad_signedpath, krb5_ad_signedpath, ad_signedpath_fields);
 
 /* First context tag is 1, not 0. */
 DEFFIELD(iakerb_header_1, krb5_iakerb_header, target_realm, 1, ostring_data);
-DEFFIELD(iakerb_header_2, krb5_iakerb_header, cookie, 2, ostring_data_ptr);
+DEFFIELD(iakerb_header_2, krb5_iakerb_header, cookie, 2, opt_ostring_data_ptr);
 static const struct atype_info *iakerb_header_fields[] = {
     &k5_atype_iakerb_header_1, &k5_atype_iakerb_header_2
 };
-static unsigned int
-iakerb_header_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_iakerb_header *val = p;
-    if (val->cookie == NULL || val->cookie->data == NULL)
-        not_present |= (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(iakerb_header, krb5_iakerb_header, iakerb_header_fields,
-           iakerb_header_optional);
+DEFSEQTYPE(iakerb_header, krb5_iakerb_header, iakerb_header_fields);
 
 /* First context tag is 1, not 0. */
 DEFFIELD(iakerb_finished_0, krb5_iakerb_finished, checksum, 1, checksum);
 static const struct atype_info *iakerb_finished_fields[] = {
     &k5_atype_iakerb_finished_0
 };
-DEFSEQTYPE(iakerb_finished, krb5_iakerb_finished, iakerb_finished_fields,
-           NULL);
+DEFSEQTYPE(iakerb_finished, krb5_iakerb_finished, iakerb_finished_fields);
 
 /* Exported complete encoders -- these produce a krb5_data with
    the encoding in the correct byte order.  */
@@ -1210,31 +953,24 @@ DEFPTRTYPE(oid_data_ptr, oid_data);
 
 /* RFC 3280.  No context tags. */
 DEFOFFSETTYPE(algid_0, krb5_algorithm_identifier, algorithm, oid_data);
-DEFOFFSETTYPE(algid_1, krb5_algorithm_identifier, parameters, der_data);
+DEFOFFSETTYPE(algid_1, krb5_algorithm_identifier, parameters, opt_der_data);
 static const struct atype_info *algorithm_identifier_fields[] = {
     &k5_atype_algid_0, &k5_atype_algid_1
 };
-static unsigned int
-algorithm_identifier_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_algorithm_identifier *val = p;
-    if (val->parameters.length == 0)
-        not_present |= (1u << 1);
-    return not_present;
-}
 DEFSEQTYPE(algorithm_identifier, krb5_algorithm_identifier,
-           algorithm_identifier_fields, algorithm_identifier_optional);
+           algorithm_identifier_fields);
 DEFPTRTYPE(algorithm_identifier_ptr, algorithm_identifier);
 
 DEFCTAGGEDTYPE(kdf_alg_id_0, 0, oid_data);
 static const struct atype_info *kdf_alg_id_fields[] = {
     &k5_atype_kdf_alg_id_0
 };
-DEFSEQTYPE(kdf_alg_id, krb5_data, kdf_alg_id_fields, NULL);
-DEFPTRTYPE(kdf_alg_id_ptr, kdf_alg_id);
-DEFNONEMPTYNULLTERMSEQOFTYPE(supported_kdfs, kdf_alg_id_ptr);
-DEFPTRTYPE(supported_kdfs_ptr, supported_kdfs);
+DEFSEQTYPE(kdf_alg_id, krb5_data, kdf_alg_id_fields);
+DEFPTRTYPE(ptr_kdf_alg_id, kdf_alg_id);
+DEFNONEMPTYNULLTERMSEQOFTYPE(supported_kdfs, ptr_kdf_alg_id);
+DEFPTRTYPE(ptr_supported_kdfs, supported_kdfs);
+DEFOPTIONALZEROTYPE(opt_ptr_kdf_alg_id, ptr_kdf_alg_id);
+DEFOPTIONALZEROTYPE(opt_ptr_supported_kdfs, ptr_supported_kdfs);
 
 /* KRB5PrincipalName from RFC 4556 (*not* PrincipalName from RFC 4120) */
 DEFCTAGGEDTYPE(pkinit_princ_0, 0, realm_of_principal_data);
@@ -1243,7 +979,7 @@ static const struct atype_info *pkinit_krb5_principal_name_fields[] = {
     &k5_atype_pkinit_princ_0, &k5_atype_pkinit_princ_1
 };
 DEFSEQTYPE(pkinit_krb5_principal_name_data, krb5_principal_data,
-           pkinit_krb5_principal_name_fields, NULL);
+           pkinit_krb5_principal_name_fields);
 DEFPTRTYPE(pkinit_krb5_principal_name, pkinit_krb5_principal_name_data);
 
 /* SP80056A OtherInfo, for pkinit agility.  No context tag on first field. */
@@ -1261,7 +997,7 @@ static const struct atype_info *sp80056a_other_info_fields[] = {
     &k5_atype_oinfo_2
 };
 DEFSEQTYPE(sp80056a_other_info, krb5_sp80056a_other_info,
-           sp80056a_other_info_fields, NULL);
+           sp80056a_other_info_fields);
 
 /* For PkinitSuppPubInfo, for pkinit agility */
 DEFFIELD(supp_pub_0, krb5_pkinit_supp_pub_info, enctype, 0, int32);
@@ -1271,7 +1007,7 @@ static const struct atype_info *pkinit_supp_pub_info_fields[] = {
     &k5_atype_supp_pub_0, &k5_atype_supp_pub_1, &k5_atype_supp_pub_2
 };
 DEFSEQTYPE(pkinit_supp_pub_info, krb5_pkinit_supp_pub_info,
-           pkinit_supp_pub_info_fields, NULL);
+           pkinit_supp_pub_info_fields);
 
 MAKE_ENCODER(encode_krb5_pkinit_supp_pub_info, pkinit_supp_pub_info);
 MAKE_ENCODER(encode_krb5_sp80056a_other_info, sp80056a_other_info);
@@ -1288,8 +1024,7 @@ static const struct atype_info *pk_authenticator_fields[] = {
     &k5_atype_pk_authenticator_0, &k5_atype_pk_authenticator_1,
     &k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3
 };
-DEFSEQTYPE(pk_authenticator, krb5_pk_authenticator, pk_authenticator_fields,
-           NULL);
+DEFSEQTYPE(pk_authenticator, krb5_pk_authenticator, pk_authenticator_fields);
 
 DEFFIELD(pkauth9_0, krb5_pk_authenticator_draft9, kdcName, 0, principal);
 DEFFIELD(pkauth9_1, krb5_pk_authenticator_draft9, kdcName, 1,
@@ -1302,7 +1037,7 @@ static const struct atype_info *pk_authenticator_draft9_fields[] = {
     &k5_atype_pkauth9_3, &k5_atype_pkauth9_4
 };
 DEFSEQTYPE(pk_authenticator_draft9, krb5_pk_authenticator_draft9,
-           pk_authenticator_draft9_fields, NULL);
+           pk_authenticator_draft9_fields);
 
 DEFCOUNTEDSTRINGTYPE(s_bitstring, char *, unsigned int,
                      k5_asn1_encode_bitstring, ASN1_BITSTRING);
@@ -1314,113 +1049,68 @@ DEFOFFSETTYPE(spki_1, krb5_subject_pk_info, subjectPublicKey, bitstring_data);
 static const struct atype_info *subject_pk_info_fields[] = {
     &k5_atype_spki_0, &k5_atype_spki_1
 };
-DEFSEQTYPE(subject_pk_info, krb5_subject_pk_info, subject_pk_info_fields,
-           NULL);
+DEFSEQTYPE(subject_pk_info, krb5_subject_pk_info, subject_pk_info_fields);
 DEFPTRTYPE(subject_pk_info_ptr, subject_pk_info);
+DEFOPTIONALZEROTYPE(opt_subject_pk_info_ptr, subject_pk_info_ptr);
 
 DEFNULLTERMSEQOFTYPE(seqof_algorithm_identifier, algorithm_identifier_ptr);
 DEFPTRTYPE(ptr_seqof_algorithm_identifier, seqof_algorithm_identifier);
+DEFOPTIONALZEROTYPE(opt_ptr_seqof_algorithm_identifier,
+                    ptr_seqof_algorithm_identifier);
 DEFFIELD(auth_pack_0, krb5_auth_pack, pkAuthenticator, 0, pk_authenticator);
 DEFFIELD(auth_pack_1, krb5_auth_pack, clientPublicValue, 1,
-         subject_pk_info_ptr);
+         opt_subject_pk_info_ptr);
 DEFFIELD(auth_pack_2, krb5_auth_pack, supportedCMSTypes, 2,
-         ptr_seqof_algorithm_identifier);
-DEFFIELD(auth_pack_3, krb5_auth_pack, clientDHNonce, 3, ostring_data);
-DEFFIELD(auth_pack_4, krb5_auth_pack, supportedKDFs, 4, supported_kdfs_ptr);
+         opt_ptr_seqof_algorithm_identifier);
+DEFFIELD(auth_pack_3, krb5_auth_pack, clientDHNonce, 3, opt_ostring_data);
+DEFFIELD(auth_pack_4, krb5_auth_pack, supportedKDFs, 4,
+         opt_ptr_supported_kdfs);
 static const struct atype_info *auth_pack_fields[] = {
     &k5_atype_auth_pack_0, &k5_atype_auth_pack_1, &k5_atype_auth_pack_2,
     &k5_atype_auth_pack_3, &k5_atype_auth_pack_4
 };
-static unsigned int
-auth_pack_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_auth_pack *val = p;
-    if (val->clientPublicValue == NULL)
-        not_present |= (1u << 1);
-    if (val->supportedCMSTypes == NULL)
-        not_present |= (1u << 2);
-    if (val->clientDHNonce.length == 0)
-        not_present |= (1u << 3);
-    if (val->supportedKDFs == NULL)
-        not_present |= (1u << 4);
-    return not_present;
-}
-DEFSEQTYPE(auth_pack, krb5_auth_pack, auth_pack_fields, auth_pack_optional);
+DEFSEQTYPE(auth_pack, krb5_auth_pack, auth_pack_fields);
 
 DEFFIELD(auth_pack9_0, krb5_auth_pack_draft9, pkAuthenticator, 0,
          pk_authenticator_draft9);
 DEFFIELD(auth_pack9_1, krb5_auth_pack_draft9, clientPublicValue, 1,
-         subject_pk_info_ptr);
+         opt_subject_pk_info_ptr);
 static const struct atype_info *auth_pack_draft9_fields[] = {
     &k5_atype_auth_pack9_0, &k5_atype_auth_pack9_1
 };
-static unsigned int
-auth_pack_draft9_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_auth_pack_draft9 *val = p;
-    if (val->clientPublicValue == NULL)
-        not_present |= (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(auth_pack_draft9, krb5_auth_pack_draft9, auth_pack_draft9_fields,
-           auth_pack_draft9_optional);
+DEFSEQTYPE(auth_pack_draft9, krb5_auth_pack_draft9, auth_pack_draft9_fields);
 
 DEFFIELD_IMPLICIT(extprinc_0, krb5_external_principal_identifier,
-                  subjectName, 0, ostring_data);
+                  subjectName, 0, opt_ostring_data);
 DEFFIELD_IMPLICIT(extprinc_1, krb5_external_principal_identifier,
-                  issuerAndSerialNumber, 1, ostring_data);
+                  issuerAndSerialNumber, 1, opt_ostring_data);
 DEFFIELD_IMPLICIT(extprinc_2, krb5_external_principal_identifier,
-                  subjectKeyIdentifier, 2, ostring_data);
+                  subjectKeyIdentifier, 2, opt_ostring_data);
 static const struct atype_info *external_principal_identifier_fields[] = {
     &k5_atype_extprinc_0, &k5_atype_extprinc_1, &k5_atype_extprinc_2
 };
-static unsigned int
-external_principal_identifier_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_external_principal_identifier *val = p;
-    if (val->subjectName.length == 0)
-        not_present |= (1u << 0);
-    if (val->issuerAndSerialNumber.length == 0)
-        not_present |= (1u << 1);
-    if (val->subjectKeyIdentifier.length == 0)
-        not_present |= (1u << 2);
-    return not_present;
-}
 DEFSEQTYPE(external_principal_identifier, krb5_external_principal_identifier,
-           external_principal_identifier_fields,
-           external_principal_identifier_optional);
+           external_principal_identifier_fields);
 DEFPTRTYPE(external_principal_identifier_ptr, external_principal_identifier);
 
 DEFNULLTERMSEQOFTYPE(seqof_external_principal_identifier,
                      external_principal_identifier_ptr);
 DEFPTRTYPE(ptr_seqof_external_principal_identifier,
            seqof_external_principal_identifier);
+DEFOPTIONALZEROTYPE(opt_ptr_seqof_external_principal_identifier,
+                    ptr_seqof_external_principal_identifier);
 
 DEFFIELD_IMPLICIT(pa_pk_as_req_0, krb5_pa_pk_as_req, signedAuthPack, 0,
                   ostring_data);
 DEFFIELD(pa_pk_as_req_1, krb5_pa_pk_as_req, trustedCertifiers, 1,
-         ptr_seqof_external_principal_identifier);
-DEFFIELD_IMPLICIT(pa_pk_as_req_2, krb5_pa_pk_as_req, kdcPkId, 2, ostring_data);
+         opt_ptr_seqof_external_principal_identifier);
+DEFFIELD_IMPLICIT(pa_pk_as_req_2, krb5_pa_pk_as_req, kdcPkId, 2,
+                  opt_ostring_data);
 static const struct atype_info *pa_pk_as_req_fields[] = {
     &k5_atype_pa_pk_as_req_0, &k5_atype_pa_pk_as_req_1,
     &k5_atype_pa_pk_as_req_2
 };
-static unsigned int
-pa_pk_as_req_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_pa_pk_as_req *val = p;
-    if (val->trustedCertifiers == NULL)
-        not_present |= (1u << 1);
-    if (val->kdcPkId.length == 0)
-        not_present |= (1u << 2);
-    return not_present;
-}
-DEFSEQTYPE(pa_pk_as_req, krb5_pa_pk_as_req, pa_pk_as_req_fields,
-           pa_pk_as_req_optional);
+DEFSEQTYPE(pa_pk_as_req, krb5_pa_pk_as_req, pa_pk_as_req_fields);
 
 /*
  * In draft-ietf-cat-kerberos-pk-init-09, this sequence has four fields, but we
@@ -1432,67 +1122,37 @@ DEFSEQTYPE(pa_pk_as_req, krb5_pa_pk_as_req, pa_pk_as_req_fields,
 DEFFIELD_IMPLICIT(pa_pk_as_req9_0, krb5_pa_pk_as_req_draft9, signedAuthPack, 0,
                   ostring_data);
 DEFFIELD_IMPLICIT(pa_pk_as_req9_2, krb5_pa_pk_as_req_draft9, kdcCert, 2,
-                  ostring_data);
+                  opt_ostring_data);
 static const struct atype_info *pa_pk_as_req_draft9_fields[] = {
     &k5_atype_pa_pk_as_req9_0, &k5_atype_pa_pk_as_req9_2
 };
-static unsigned int
-pa_pk_as_req_draft9_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_pa_pk_as_req_draft9 *val = p;
-    if (val->kdcCert.length == 0)
-        not_present |= (1u << 1);
-    return not_present;
-}
 DEFSEQTYPE(pa_pk_as_req_draft9, krb5_pa_pk_as_req_draft9,
-           pa_pk_as_req_draft9_fields, pa_pk_as_req_draft9_optional);
+           pa_pk_as_req_draft9_fields);
 
 DEFFIELD_IMPLICIT(dh_rep_info_0, krb5_dh_rep_info, dhSignedData, 0,
                   ostring_data);
-DEFFIELD(dh_rep_info_1, krb5_dh_rep_info, serverDHNonce, 1, ostring_data);
-DEFFIELD(dh_rep_info_2, krb5_dh_rep_info, kdfID, 2, kdf_alg_id_ptr);
+DEFFIELD(dh_rep_info_1, krb5_dh_rep_info, serverDHNonce, 1, opt_ostring_data);
+DEFFIELD(dh_rep_info_2, krb5_dh_rep_info, kdfID, 2, opt_ptr_kdf_alg_id);
 static const struct atype_info *dh_rep_info_fields[] = {
     &k5_atype_dh_rep_info_0, &k5_atype_dh_rep_info_1, &k5_atype_dh_rep_info_2
 };
-static unsigned int
-dh_rep_info_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_dh_rep_info *val = p;
-    if (val->serverDHNonce.length == 0)
-        not_present |= (1u << 1);
-    if (val->kdfID == NULL)
-        not_present |= (1u << 2);
-    return not_present;
-}
-DEFSEQTYPE(dh_rep_info, krb5_dh_rep_info, dh_rep_info_fields,
-           dh_rep_info_optional);
+DEFSEQTYPE(dh_rep_info, krb5_dh_rep_info, dh_rep_info_fields);
 
 DEFFIELD(dh_key_0, krb5_kdc_dh_key_info, subjectPublicKey, 0, bitstring_data);
 DEFFIELD(dh_key_1, krb5_kdc_dh_key_info, nonce, 1, int32);
-DEFFIELD(dh_key_2, krb5_kdc_dh_key_info, dhKeyExpiration, 2, kerberos_time);
+DEFFIELD(dh_key_2, krb5_kdc_dh_key_info, dhKeyExpiration, 2,
+         opt_kerberos_time);
 static const struct atype_info *kdc_dh_key_info_fields[] = {
     &k5_atype_dh_key_0, &k5_atype_dh_key_1, &k5_atype_dh_key_2
 };
-static unsigned int
-kdc_dh_key_info_optional(const void *p)
-{
-    unsigned int not_present = 0;
-    const krb5_kdc_dh_key_info *val = p;
-    if (val->dhKeyExpiration == 0)
-        not_present |= (1u << 2);
-    return not_present;
-}
-DEFSEQTYPE(kdc_dh_key_info, krb5_kdc_dh_key_info, kdc_dh_key_info_fields,
-           kdc_dh_key_info_optional);
+DEFSEQTYPE(kdc_dh_key_info, krb5_kdc_dh_key_info, kdc_dh_key_info_fields);
 
 DEFFIELD(reply_key_pack_0, krb5_reply_key_pack, replyKey, 0, encryption_key);
 DEFFIELD(reply_key_pack_1, krb5_reply_key_pack, asChecksum, 1, checksum);
 static const struct atype_info *reply_key_pack_fields[] = {
     &k5_atype_reply_key_pack_0, &k5_atype_reply_key_pack_1
 };
-DEFSEQTYPE(reply_key_pack, krb5_reply_key_pack, reply_key_pack_fields, NULL);
+DEFSEQTYPE(reply_key_pack, krb5_reply_key_pack, reply_key_pack_fields);
 
 DEFFIELD(key_pack9_0, krb5_reply_key_pack_draft9, replyKey, 0, encryption_key);
 DEFFIELD(key_pack9_1, krb5_reply_key_pack_draft9, nonce, 1, int32);
@@ -1500,7 +1160,7 @@ static const struct atype_info *reply_key_pack_draft9_fields[] = {
     &k5_atype_key_pack9_0, &k5_atype_key_pack9_1
 };
 DEFSEQTYPE(reply_key_pack_draft9, krb5_reply_key_pack_draft9,
-           reply_key_pack_draft9_fields, NULL);
+           reply_key_pack_draft9_fields);
 
 DEFCTAGGEDTYPE(pa_pk_as_rep_0, 0, dh_rep_info);
 DEFCTAGGEDTYPE_IMPLICIT(pa_pk_as_rep_1, 1, ostring_data);
@@ -1571,7 +1231,7 @@ DEFCNFIELD(typed_data_1, krb5_pa_data, contents, length, 1, octetstring);
 static const struct atype_info *typed_data_fields[] = {
     &k5_atype_typed_data_0, &k5_atype_typed_data_1
 };
-DEFSEQTYPE(typed_data, krb5_pa_data, typed_data_fields, NULL);
+DEFSEQTYPE(typed_data, krb5_pa_data, typed_data_fields);
 DEFPTRTYPE(typed_data_ptr, typed_data);
 
 DEFNULLTERMSEQOFTYPE(seqof_typed_data, typed_data_ptr);
index 2c34091e4afce615ecd9c9fef283a40002cdd855..f407d98098fc7ef7671106ece3b0c81c55ae0332 100644 (file)
@@ -57,22 +57,21 @@ DEFINTTYPE(int16, krb5_int16);
 DEFCOUNTEDSTRINGTYPE(ui2_octetstring, unsigned char *, krb5_ui_2,
                      k5_asn1_encode_bytestring, ASN1_OCTETSTRING);
 
+static int
+is_salt_present(const void *p)
+{
+    const krb5_key_data *val = p;
+    return (val->key_data_length[1] != 0);
+}
+DEFCOUNTEDTYPE(krbsalt_salt, krb5_key_data, key_data_contents[1],
+               key_data_length[1], ui2_octetstring);
+DEFOPTIONALTYPE(krbsalt_salt_if_present, is_salt_present, krbsalt_salt);
 DEFFIELD(krbsalt_0, krb5_key_data, key_data_type[1], 0, int16);
-DEFCNFIELD(krbsalt_1, krb5_key_data, key_data_contents[1], key_data_length[1],
-           1, ui2_octetstring);
+DEFCTAGGEDTYPE(krbsalt_1, 1, krbsalt_salt_if_present);
 static const struct atype_info *krbsalt_fields[] = {
     &k5_atype_krbsalt_0, &k5_atype_krbsalt_1
 };
-static unsigned int
-optional_krbsalt (const void *p)
-{
-    const krb5_key_data *k = p;
-    unsigned int not_present = 0;
-    if (k->key_data_length[1] == 0)
-        not_present |= (1u << 1);
-    return not_present;
-}
-DEFSEQTYPE(krbsalt, krb5_key_data, krbsalt_fields, optional_krbsalt);
+DEFSEQTYPE(krbsalt, krb5_key_data, krbsalt_fields);
 
 DEFFIELD(encryptionkey_0, krb5_key_data, key_data_type[0], 0, int16);
 DEFCNFIELD(encryptionkey_1, krb5_key_data, key_data_contents[0],
@@ -80,7 +79,7 @@ DEFCNFIELD(encryptionkey_1, krb5_key_data, key_data_contents[0],
 static const struct atype_info *encryptionkey_fields[] = {
     &k5_atype_encryptionkey_0, &k5_atype_encryptionkey_1
 };
-DEFSEQTYPE(encryptionkey, krb5_key_data, encryptionkey_fields, NULL);
+DEFSEQTYPE(encryptionkey, krb5_key_data, encryptionkey_fields);
 
 DEFCTAGGEDTYPE(key_data_0, 0, krbsalt);
 DEFCTAGGEDTYPE(key_data_1, 1, encryptionkey);
@@ -90,7 +89,7 @@ DEFCTAGGEDTYPE(key_data_2, 2, s2kparams),
 static const struct atype_info *key_data_fields[] = {
     &k5_atype_key_data_0, &k5_atype_key_data_1
 };
-DEFSEQTYPE(key_data, krb5_key_data, key_data_fields, 0);
+DEFSEQTYPE(key_data, krb5_key_data, key_data_fields);
 DEFPTRTYPE(ptr_key_data, key_data);
 DEFCOUNTEDSEQOFTYPE(cseqof_key_data, krb5_int16, ptr_key_data);
 
@@ -109,7 +108,7 @@ static const struct atype_info *ldap_key_seq_fields[] = {
     &k5_atype_ldap_key_seq_2, &k5_atype_ldap_key_seq_3,
     &k5_atype_ldap_key_seq_4
 };
-DEFSEQTYPE(ldap_key_seq, ldap_seqof_key_data, ldap_key_seq_fields, NULL);
+DEFSEQTYPE(ldap_key_seq, ldap_seqof_key_data, ldap_key_seq_fields);
 
 /* Export a function to do the whole encoding.  */
 MAKE_ENCODER(krb5int_ldap_encode_sequence_of_keys, ldap_key_seq);
index 06078ffbc5d5192f735b5dceb255b55a27d41036..30c43564124eba0d6b16c4826668d1fd03f4c7d2 100644 (file)
@@ -12,4 +12,5 @@ error_code ASN1_PARSE_ERROR, "ASN.1 parse error"
 error_code ASN1_BAD_GMTIME, "ASN.1 bad return from gmtime"
 error_code ASN1_MISMATCH_INDEF, "ASN.1 non-constructed indefinite encoding"
 error_code ASN1_MISSING_EOC, "ASN.1 missing expected EOC"
+error_code ASN1_OMITTED, "ASN.1 object omitted in sequence"
 end