krb5 commit: Add ASN.1 support for OTP

Greg Hudson ghudson at MIT.EDU
Thu Aug 23 13:32:24 EDT 2012


https://github.com/krb5/krb5/commit/a7dc565cafbaa6c18d5a76ea3cc823c7159a0d6b
commit a7dc565cafbaa6c18d5a76ea3cc823c7159a0d6b
Author: Greg Hudson <ghudson at mit.edu>
Date:   Fri Jul 27 11:51:18 2012 -0400

    Add ASN.1 support for OTP
    
    Add encoders and decoders for the OTP-TOKENINFO, PA-OTP-CHALLENGE,
    PA-OTP-REQUEST, and PA-OTP-ENC-REQUEST types from RFC 6560.  For more
    thorough testing, add support for generating test encodings using
    asn1c for sample objects (currently only for the OTP types).

 src/include/k5-int.h                 |   75 ++++
 src/lib/krb5/asn.1/asn1_k_encode.c   |  129 ++++++-
 src/lib/krb5/asn.1/krbasn1.h         |    1 +
 src/lib/krb5/krb/kfree.c             |   65 ++++
 src/lib/krb5/libkrb5.exports         |   12 +
 src/tests/asn.1/Makefile.in          |   13 +
 src/tests/asn.1/krb5.asn1            |  392 ++++++++++++++++++++
 src/tests/asn.1/krb5_decode_test.c   |   47 +++
 src/tests/asn.1/krb5_encode_test.c   |   44 +++
 src/tests/asn.1/ktest.c              |  171 +++++++++-
 src/tests/asn.1/ktest.h              |   11 +
 src/tests/asn.1/ktest_equal.c        |  102 +++++-
 src/tests/asn.1/ktest_equal.h        |   10 +
 src/tests/asn.1/make-vectors.c       |  170 +++++++++
 src/tests/asn.1/otp.asn1             |  109 ++++++
 src/tests/asn.1/pkix.asn1            |  654 ++++++++++++++++++++++++++++++++++
 src/tests/asn.1/reference_encode.out |    7 +
 src/tests/asn.1/trval_reference.out  |  130 +++++++
 18 files changed, 2099 insertions(+), 43 deletions(-)

diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 86fe650..6a853ce 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -471,6 +471,51 @@ typedef struct _krb5_enc_sam_response_enc_2 {
 
 #include "k5-int-pkinit.h"
 
+#define KRB5_OTP_FLAG_NEXTOTP        0x40000000
+#define KRB5_OTP_FLAG_COMBINE        0x20000000
+#define KRB5_OTP_FLAG_COLLECT_PIN    0x10000000
+#define KRB5_OTP_FLAG_NO_COLLECT_PIN 0x08000000
+#define KRB5_OTP_FLAG_ENCRYPT_NONCE  0x04000000
+#define KRB5_OTP_FLAG_SEPARATE_PIN   0x02000000
+#define KRB5_OTP_FLAG_CHECK_DIGIT    0x01000000
+
+typedef struct _krb5_otp_tokeninfo {
+    krb5_flags flags;
+    krb5_data vendor;
+    krb5_data challenge;
+    krb5_int32 length;          /* -1 for unspecified */
+    krb5_int32 format;          /* -1 for unspecified */
+    krb5_data token_id;
+    krb5_data alg_id;
+    krb5_algorithm_identifier **supported_hash_alg;
+    krb5_int32 iteration_count; /* -1 for unspecified */
+} krb5_otp_tokeninfo;
+
+typedef struct _krb5_pa_otp_challenge {
+    krb5_data nonce;
+    krb5_data service;
+    krb5_otp_tokeninfo **tokeninfo;
+    krb5_data salt;
+    krb5_data s2kparams;
+} krb5_pa_otp_challenge;
+
+typedef struct _krb5_pa_otp_req {
+    krb5_int32 flags;
+    krb5_data nonce;
+    krb5_enc_data enc_data;
+    krb5_algorithm_identifier *hash_alg;
+    krb5_int32 iteration_count; /* -1 for unspecified */
+    krb5_data otp_value;
+    krb5_data pin;
+    krb5_data challenge;
+    krb5_timestamp time;
+    krb5_data counter;
+    krb5_int32 format;          /* -1 for unspecified */
+    krb5_data token_id;
+    krb5_data alg_id;
+    krb5_data vendor;
+} krb5_pa_otp_req;
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -1110,6 +1155,12 @@ void KRB5_CALLCONV krb5_free_ad_signedpath(krb5_context, krb5_ad_signedpath *);
 void KRB5_CALLCONV krb5_free_iakerb_header(krb5_context, krb5_iakerb_header *);
 void KRB5_CALLCONV krb5_free_iakerb_finished(krb5_context,
                                              krb5_iakerb_finished *);
+void k5_free_algorithm_identifier(krb5_context context,
+                                  krb5_algorithm_identifier *val);
+void k5_free_otp_tokeninfo(krb5_context context, krb5_otp_tokeninfo *val);
+void k5_free_pa_otp_challenge(krb5_context context,
+                              krb5_pa_otp_challenge *val);
+void k5_free_pa_otp_req(krb5_context context, krb5_pa_otp_req *val);
 
 /* #include "krb5/wordsize.h" -- comes in through base-defs.h. */
 #include "com_err.h"
@@ -1642,6 +1693,18 @@ encode_krb5_ad_signedpath(const krb5_ad_signedpath *, krb5_data **);
 krb5_error_code
 encode_krb5_ad_signedpath_data(const krb5_ad_signedpath_data *, krb5_data **);
 
+krb5_error_code
+encode_krb5_otp_tokeninfo(const krb5_otp_tokeninfo *, krb5_data **);
+
+krb5_error_code
+encode_krb5_pa_otp_challenge(const krb5_pa_otp_challenge *, krb5_data **);
+
+krb5_error_code
+encode_krb5_pa_otp_req(const krb5_pa_otp_req *, krb5_data **);
+
+krb5_error_code
+encode_krb5_pa_otp_enc_req(const krb5_data *, krb5_data **);
+
 /*************************************************************************
  * End of prototypes for krb5_encode.c
  *************************************************************************/
@@ -1800,6 +1863,18 @@ decode_krb5_iakerb_header(const krb5_data *, krb5_iakerb_header **);
 krb5_error_code
 decode_krb5_iakerb_finished(const krb5_data *, krb5_iakerb_finished **);
 
+krb5_error_code
+decode_krb5_otp_tokeninfo(const krb5_data *, krb5_otp_tokeninfo **);
+
+krb5_error_code
+decode_krb5_pa_otp_challenge(const krb5_data *, krb5_pa_otp_challenge **);
+
+krb5_error_code
+decode_krb5_pa_otp_req(const krb5_data *, krb5_pa_otp_req **);
+
+krb5_error_code
+decode_krb5_pa_otp_enc_req(const krb5_data *, krb5_data **);
+
 struct _krb5_key_data;          /* kdb.h */
 
 struct ldap_seqof_key_data {
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
index d8a2a87..68a907f 100644
--- a/src/lib/krb5/asn.1/asn1_k_encode.c
+++ b/src/lib/krb5/asn.1/asn1_k_encode.c
@@ -29,11 +29,24 @@
 
 DEFINT_IMMEDIATE(krb5_version, KVNO, KRB5KDC_ERR_BAD_PVNO);
 
+static int
+int32_not_minus1(const void *p)
+{
+    return (*(krb5_int32 *)p != -1);
+}
+
+static void
+init_int32_minus1(void *p)
+{
+    *(krb5_int32 *)p = -1;
+}
+
 DEFBOOLTYPE(bool, krb5_boolean);
 DEFINTTYPE(int32, krb5_int32);
 DEFPTRTYPE(int32_ptr, int32);
 DEFCOUNTEDSEQOFTYPE(cseqof_int32, krb5_int32, int32_ptr);
 DEFOPTIONALZEROTYPE(opt_int32, int32);
+DEFOPTIONALTYPE(opt_int32_minus1, int32_not_minus1, init_int32_minus1, int32);
 
 DEFUINTTYPE(uint, unsigned int);
 DEFUINTTYPE(octet, krb5_octet);
@@ -73,6 +86,19 @@ DEFOPTIONALTYPE(opt_gstring_data, nonempty_data, NULL, gstring_data);
 DEFPTRTYPE(gstring_data_ptr, gstring_data);
 DEFCOUNTEDSEQOFTYPE(cseqof_gstring_data, krb5_int32, gstring_data_ptr);
 
+DEFCOUNTEDSTRINGTYPE(utf8string, char *, unsigned int,
+                     k5_asn1_encode_bytestring, k5_asn1_decode_bytestring,
+                     ASN1_UTF8STRING);
+DEFCOUNTEDTYPE(utf8_data, krb5_data, data, length, utf8string);
+DEFOPTIONALTYPE(opt_utf8_data, nonempty_data, NULL, utf8_data);
+DEFPTRTYPE(utf8_data_ptr, utf8_data);
+
+DEFCOUNTEDSTRINGTYPE(object_identifier, char *, unsigned int,
+                     k5_asn1_encode_bytestring, k5_asn1_decode_bytestring,
+                     ASN1_OBJECTIDENTIFIER);
+DEFCOUNTEDTYPE(oid_data, krb5_data, data, length, object_identifier);
+DEFPTRTYPE(oid_data_ptr, oid_data);
+
 DEFOFFSETTYPE(realm_of_principal_data, krb5_principal_data, realm,
               gstring_data);
 DEFPTRTYPE(realm_of_principal, realm_of_principal_data);
@@ -1311,18 +1337,6 @@ krb5int_get_authdata_containee_types(krb5_context context,
     return 0;
 }
 
-/*
- * PKINIT
- */
-
-#ifndef DISABLE_PKINIT
-
-DEFCOUNTEDSTRINGTYPE(object_identifier, char *, unsigned int,
-                     k5_asn1_encode_bytestring, k5_asn1_decode_bytestring,
-                     ASN1_OBJECTIDENTIFIER);
-DEFCOUNTEDTYPE(oid_data, krb5_data, data, length, object_identifier);
-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, opt_der_data);
@@ -1331,7 +1345,18 @@ static const struct atype_info *algorithm_identifier_fields[] = {
 };
 DEFSEQTYPE(algorithm_identifier, krb5_algorithm_identifier,
            algorithm_identifier_fields);
-DEFPTRTYPE(algorithm_identifier_ptr, algorithm_identifier);
+DEFPTRTYPE(ptr_algorithm_identifier, algorithm_identifier);
+DEFOPTIONALZEROTYPE(opt_ptr_algorithm_identifier, ptr_algorithm_identifier);
+DEFNULLTERMSEQOFTYPE(seqof_algorithm_identifier, ptr_algorithm_identifier);
+DEFPTRTYPE(ptr_seqof_algorithm_identifier, seqof_algorithm_identifier);
+DEFOPTIONALEMPTYTYPE(opt_ptr_seqof_algorithm_identifier,
+                     ptr_seqof_algorithm_identifier);
+
+/*
+ * PKINIT
+ */
+
+#ifndef DISABLE_PKINIT
 
 DEFCTAGGEDTYPE(kdf_alg_id_0, 0, oid_data);
 static const struct atype_info *kdf_alg_id_fields[] = {
@@ -1426,10 +1451,6 @@ 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,
          opt_subject_pk_info_ptr);
@@ -1616,3 +1637,77 @@ DEFPTRTYPE(typed_data_ptr, typed_data);
 
 DEFNULLTERMSEQOFTYPE(seqof_typed_data, typed_data_ptr);
 MAKE_CODEC(krb5_typed_data, seqof_typed_data);
+
+/* Definitions for OTP preauth (RFC 6560) */
+
+DEFFIELD_IMPLICIT(tokinfo_0, krb5_otp_tokeninfo, flags, 0, krb5_flags);
+DEFFIELD_IMPLICIT(tokinfo_1, krb5_otp_tokeninfo, vendor, 1, opt_utf8_data);
+DEFFIELD_IMPLICIT(tokinfo_2, krb5_otp_tokeninfo, challenge, 2,
+                  opt_ostring_data);
+DEFFIELD_IMPLICIT(tokinfo_3, krb5_otp_tokeninfo, length, 3, opt_int32_minus1);
+DEFFIELD_IMPLICIT(tokinfo_4, krb5_otp_tokeninfo, format, 4, opt_int32_minus1);
+DEFFIELD_IMPLICIT(tokinfo_5, krb5_otp_tokeninfo, token_id, 5,
+                  opt_ostring_data);
+DEFFIELD_IMPLICIT(tokinfo_6, krb5_otp_tokeninfo, alg_id, 6, opt_utf8_data);
+DEFFIELD_IMPLICIT(tokinfo_7, krb5_otp_tokeninfo, supported_hash_alg, 7,
+                  opt_ptr_seqof_algorithm_identifier);
+DEFFIELD_IMPLICIT(tokinfo_8, krb5_otp_tokeninfo, iteration_count, 8,
+                  opt_int32_minus1);
+static const struct atype_info *otp_tokeninfo_fields[] = {
+    &k5_atype_tokinfo_0, &k5_atype_tokinfo_1, &k5_atype_tokinfo_2,
+    &k5_atype_tokinfo_3, &k5_atype_tokinfo_4, &k5_atype_tokinfo_5,
+    &k5_atype_tokinfo_6, &k5_atype_tokinfo_7, &k5_atype_tokinfo_8
+};
+DEFSEQTYPE(otp_tokeninfo, krb5_otp_tokeninfo, otp_tokeninfo_fields);
+MAKE_CODEC(krb5_otp_tokeninfo, otp_tokeninfo);
+
+DEFPTRTYPE(otp_tokeninfo_ptr, otp_tokeninfo);
+DEFNONEMPTYNULLTERMSEQOFTYPE(seqof_otp_tokeninfo, otp_tokeninfo_ptr);
+DEFPTRTYPE(ptr_seqof_otp_tokeninfo, seqof_otp_tokeninfo);
+
+DEFFIELD_IMPLICIT(otp_ch_0, krb5_pa_otp_challenge, nonce, 0, ostring_data);
+DEFFIELD_IMPLICIT(otp_ch_1, krb5_pa_otp_challenge, service, 1, opt_utf8_data);
+DEFFIELD_IMPLICIT(otp_ch_2, krb5_pa_otp_challenge, tokeninfo, 2,
+                  ptr_seqof_otp_tokeninfo);
+DEFFIELD_IMPLICIT(otp_ch_3, krb5_pa_otp_challenge, salt, 3, opt_gstring_data);
+DEFFIELD_IMPLICIT(otp_ch_4, krb5_pa_otp_challenge, s2kparams, 4,
+                  opt_ostring_data);
+static const struct atype_info *pa_otp_challenge_fields[] = {
+    &k5_atype_otp_ch_0, &k5_atype_otp_ch_1, &k5_atype_otp_ch_2,
+    &k5_atype_otp_ch_3, &k5_atype_otp_ch_4
+};
+DEFSEQTYPE(pa_otp_challenge, krb5_pa_otp_challenge, pa_otp_challenge_fields);
+MAKE_CODEC(krb5_pa_otp_challenge, pa_otp_challenge);
+
+DEFFIELD_IMPLICIT(otp_req_0, krb5_pa_otp_req, flags, 0, krb5_flags);
+DEFFIELD_IMPLICIT(otp_req_1, krb5_pa_otp_req, nonce, 1, opt_ostring_data);
+DEFFIELD_IMPLICIT(otp_req_2, krb5_pa_otp_req, enc_data, 2, encrypted_data);
+DEFFIELD_IMPLICIT(otp_req_3, krb5_pa_otp_req, hash_alg, 3,
+                  opt_ptr_algorithm_identifier);
+DEFFIELD_IMPLICIT(otp_req_4, krb5_pa_otp_req, iteration_count, 4,
+                  opt_int32_minus1);
+DEFFIELD_IMPLICIT(otp_req_5, krb5_pa_otp_req, otp_value, 5, opt_ostring_data);
+DEFFIELD_IMPLICIT(otp_req_6, krb5_pa_otp_req, pin, 6, opt_utf8_data);
+DEFFIELD_IMPLICIT(otp_req_7, krb5_pa_otp_req, challenge, 7, opt_ostring_data);
+DEFFIELD_IMPLICIT(otp_req_8, krb5_pa_otp_req, time, 8, opt_kerberos_time);
+DEFFIELD_IMPLICIT(otp_req_9, krb5_pa_otp_req, counter, 9, opt_ostring_data);
+DEFFIELD_IMPLICIT(otp_req_10, krb5_pa_otp_req, format, 10, opt_int32_minus1);
+DEFFIELD_IMPLICIT(otp_req_11, krb5_pa_otp_req, token_id, 11, opt_ostring_data);
+DEFFIELD_IMPLICIT(otp_req_12, krb5_pa_otp_req, alg_id, 12, opt_utf8_data);
+DEFFIELD_IMPLICIT(otp_req_13, krb5_pa_otp_req, vendor, 13, opt_utf8_data);
+static const struct atype_info *pa_otp_req_fields[] = {
+    &k5_atype_otp_req_0, &k5_atype_otp_req_1, &k5_atype_otp_req_2,
+    &k5_atype_otp_req_3, &k5_atype_otp_req_4, &k5_atype_otp_req_5,
+    &k5_atype_otp_req_6, &k5_atype_otp_req_7, &k5_atype_otp_req_8,
+    &k5_atype_otp_req_9, &k5_atype_otp_req_10, &k5_atype_otp_req_11,
+    &k5_atype_otp_req_12, &k5_atype_otp_req_13
+};
+DEFSEQTYPE(pa_otp_req, krb5_pa_otp_req, pa_otp_req_fields);
+MAKE_CODEC(krb5_pa_otp_req, pa_otp_req);
+
+DEFCTAGGEDTYPE_IMPLICIT(pa_otp_enc_req_0, 0, ostring_data);
+static const struct atype_info *pa_otp_enc_req_fields[] = {
+    &k5_atype_pa_otp_enc_req_0
+};
+DEFSEQTYPE(pa_otp_enc_req, krb5_data, pa_otp_enc_req_fields);
+MAKE_CODEC(krb5_pa_otp_enc_req, pa_otp_enc_req);
diff --git a/src/lib/krb5/asn.1/krbasn1.h b/src/lib/krb5/asn.1/krbasn1.h
index 215dc5b..73de724 100644
--- a/src/lib/krb5/asn.1/krbasn1.h
+++ b/src/lib/krb5/asn.1/krbasn1.h
@@ -53,6 +53,7 @@ typedef int asn1_tagnum;
 #define ASN1_NULL               5
 #define ASN1_OBJECTIDENTIFIER   6
 #define ASN1_ENUMERATED         10
+#define ASN1_UTF8STRING         12
 #define ASN1_SEQUENCE           16
 #define ASN1_SET                17
 #define ASN1_PRINTABLESTRING    19
diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c
index 5c79900..9629ae6 100644
--- a/src/lib/krb5/krb/kfree.c
+++ b/src/lib/krb5/krb/kfree.c
@@ -765,3 +765,68 @@ krb5_free_iakerb_finished(krb5_context context, krb5_iakerb_finished *val)
     krb5_free_checksum_contents(context, &val->checksum);
     free(val);
 }
+
+void
+k5_free_algorithm_identifier(krb5_context context,
+                             krb5_algorithm_identifier *val)
+{
+    if (val == NULL)
+        return;
+    free(val->algorithm.data);
+    free(val->parameters.data);
+    free(val);
+}
+
+void
+k5_free_otp_tokeninfo(krb5_context context, krb5_otp_tokeninfo *val)
+{
+    krb5_algorithm_identifier **alg;
+
+    if (val == NULL)
+        return;
+    free(val->vendor.data);
+    free(val->challenge.data);
+    free(val->token_id.data);
+    free(val->alg_id.data);
+    for (alg = val->supported_hash_alg; alg != NULL && *alg != NULL; alg++)
+        k5_free_algorithm_identifier(context, *alg);
+    free(val->supported_hash_alg);
+    free(val);
+}
+
+void
+k5_free_pa_otp_challenge(krb5_context context, krb5_pa_otp_challenge *val)
+{
+    krb5_otp_tokeninfo **ti;
+
+    if (val == NULL)
+        return;
+    free(val->nonce.data);
+    free(val->service.data);
+    for (ti = val->tokeninfo; *ti != NULL; ti++)
+        k5_free_otp_tokeninfo(context, *ti);
+    free(val->tokeninfo);
+    free(val->salt.data);
+    free(val->s2kparams.data);
+    free(val);
+}
+
+void
+k5_free_pa_otp_req(krb5_context context, krb5_pa_otp_req *val)
+{
+    if (val == NULL)
+        return;
+    val->flags = 0;
+    free(val->nonce.data);
+    free(val->enc_data.ciphertext.data);
+    if (val->hash_alg != NULL)
+        k5_free_algorithm_identifier(context, val->hash_alg);
+    free(val->otp_value.data);
+    free(val->pin.data);
+    free(val->challenge.data);
+    free(val->counter.data);
+    free(val->token_id.data);
+    free(val->alg_id.data);
+    free(val->vendor.data);
+    free(val);
+}
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 1591b35..2709598 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -24,10 +24,14 @@ decode_krb5_fast_response
 decode_krb5_iakerb_finished
 decode_krb5_iakerb_header
 decode_krb5_kdc_req_body
+decode_krb5_otp_tokeninfo
 decode_krb5_pa_enc_ts
 decode_krb5_pa_for_user
 decode_krb5_pa_fx_fast_reply
 decode_krb5_pa_fx_fast_request
+decode_krb5_pa_otp_challenge
+decode_krb5_pa_otp_req
+decode_krb5_pa_otp_enc_req
 decode_krb5_pa_pac_req
 decode_krb5_pa_s4u_x509_user
 decode_krb5_padata_sequence
@@ -67,9 +71,13 @@ encode_krb5_fast_response
 encode_krb5_iakerb_finished
 encode_krb5_iakerb_header
 encode_krb5_kdc_req_body
+encode_krb5_otp_tokeninfo
 encode_krb5_pa_enc_ts
 encode_krb5_pa_for_user
 encode_krb5_pa_fx_fast_reply
+encode_krb5_pa_otp_challenge
+encode_krb5_pa_otp_req
+encode_krb5_pa_otp_enc_req
 encode_krb5_pa_s4u_x509_user
 encode_krb5_padata_sequence
 encode_krb5_pkinit_supp_pub_info
@@ -103,6 +111,10 @@ k5_count_etypes
 k5_etypes_contains
 k5_expand_path_tokens
 k5_expand_path_tokens_extra
+k5_free_algorithm_identifier
+k5_free_otp_tokeninfo
+k5_free_pa_otp_challenge
+k5_free_pa_otp_req
 k5_free_serverlist
 k5_kt_get_principal
 k5_locate_kdc
diff --git a/src/tests/asn.1/Makefile.in b/src/tests/asn.1/Makefile.in
index b2899d5..fe24c24 100644
--- a/src/tests/asn.1/Makefile.in
+++ b/src/tests/asn.1/Makefile.in
@@ -11,6 +11,8 @@ SRCS= $(srcdir)/krb5_encode_test.c $(srcdir)/krb5_decode_test.c \
 	$(srcdir)/ktest_equal.c $(srcdir)/utility.c \
 	$(srcdir)/trval.c $(srcdir)/t_trval.c
 
+ASN1SRCS= $(srcdir)/krb5.asn1 $(srcdir)/pkix.asn1 $(srcdir)/otp.asn1
+
 all:: krb5_encode_test krb5_decode_test krb5_decode_leak t_trval
 
 LOCALINCLUDES = -I$(srcdir)/../../lib/krb5/asn.1
@@ -79,6 +81,17 @@ check-encode-trval: krb5_encode_test expected_trval.out
 		$(RUN_SETUP) $(VALGRIND) ./krb5_encode_test -t > trval.out
 	cmp trval.out expected_trval.out
 
+# This target uses asn1c to generate encodings of sample objects, to
+# help ensure that our implementation is correct.  asn1c must be in the
+# path for this to work.
+test-vectors:
+	$(RM) -r vectors
+	mkdir vectors
+	cp $(ASN1SRCS) $(srcdir)/make-vectors.c vectors
+	(cd vectors && asn1c *.asn1 && rm converter-sample.c)
+	(cd vectors && $(CC) -I. -w *.c -o make-vectors)
+	(cd vectors && ./make-vectors)
+
 install::
 
 clean::
diff --git a/src/tests/asn.1/krb5.asn1 b/src/tests/asn.1/krb5.asn1
new file mode 100644
index 0000000..f58637a
--- /dev/null
+++ b/src/tests/asn.1/krb5.asn1
@@ -0,0 +1,392 @@
+KerberosV5Spec2 {
+        iso(1) identified-organization(3) dod(6) internet(1)
+        security(5) kerberosV5(2) modules(4) krb5spec2(2)
+} DEFINITIONS EXPLICIT TAGS ::= BEGIN
+
+-- OID arc for KerberosV5
+--
+-- This OID may be used to identify Kerberos protocol messages
+-- encapsulated in other protocols.
+--
+-- This OID also designates the OID arc for KerberosV5-related OIDs.
+--
+-- NOTE: RFC 1510 had an incorrect value (5) for "dod" in its OID.
+id-krb5         OBJECT IDENTIFIER ::= {
+        iso(1) identified-organization(3) dod(6) internet(1)
+        security(5) kerberosV5(2)
+}
+
+Int32           ::= INTEGER (-2147483648..2147483647)
+                    -- signed values representable in 32 bits
+
+UInt32          ::= INTEGER (0..4294967295)
+                    -- unsigned 32 bit values
+
+Microseconds    ::= INTEGER (0..999999)
+                    -- microseconds
+
+KerberosString  ::= GeneralString -- (IA5String)
+
+Realm           ::= KerberosString
+
+PrincipalName   ::= SEQUENCE {
+        name-type       [0] Int32,
+        name-string     [1] SEQUENCE OF KerberosString
+}
+
+KerberosTime    ::= GeneralizedTime -- with no fractional seconds
+
+HostAddress     ::= SEQUENCE  {
+        addr-type       [0] Int32,
+        address         [1] OCTET STRING
+}
+
+-- NOTE: HostAddresses is always used as an OPTIONAL field and
+-- should not be empty.
+HostAddresses   -- NOTE: subtly different from rfc1510,
+                -- but has a value mapping and encodes the same
+        ::= SEQUENCE OF HostAddress
+
+-- NOTE: AuthorizationData is always used as an OPTIONAL field and
+-- should not be empty.
+AuthorizationData       ::= SEQUENCE OF SEQUENCE {
+        ad-type         [0] Int32,
+        ad-data         [1] OCTET STRING
+}
+
+PA-DATA         ::= SEQUENCE {
+        -- NOTE: first tag is [1], not [0]
+        padata-type     [1] Int32,
+        padata-value    [2] OCTET STRING -- might be encoded AP-REQ
+}
+
+KerberosFlags   ::= BIT STRING (SIZE (32..MAX))
+                    -- minimum number of bits shall be sent,
+                    -- but no fewer than 32
+
+EncryptedData   ::= SEQUENCE {
+        etype   [0] Int32 -- EncryptionType --,
+        kvno    [1] UInt32 OPTIONAL,
+        cipher  [2] OCTET STRING -- ciphertext
+}
+
+EncryptionKey   ::= SEQUENCE {
+        keytype         [0] Int32 -- actually encryption type --,
+        keyvalue        [1] OCTET STRING
+}
+
+Checksum        ::= SEQUENCE {
+        cksumtype       [0] Int32,
+        checksum        [1] OCTET STRING
+}
+
+Ticket          ::= [APPLICATION 1] SEQUENCE {
+        tkt-vno         [0] INTEGER (5),
+        realm           [1] Realm,
+        sname           [2] PrincipalName,
+        enc-part        [3] EncryptedData -- EncTicketPart
+}
+
+-- Encrypted part of ticket
+EncTicketPart   ::= [APPLICATION 3] SEQUENCE {
+        flags                   [0] TicketFlags,
+        key                     [1] EncryptionKey,
+        crealm                  [2] Realm,
+        cname                   [3] PrincipalName,
+        transited               [4] TransitedEncoding,
+        authtime                [5] KerberosTime,
+        starttime               [6] KerberosTime OPTIONAL,
+        endtime                 [7] KerberosTime,
+        renew-till              [8] KerberosTime OPTIONAL,
+        caddr                   [9] HostAddresses OPTIONAL,
+        authorization-data      [10] AuthorizationData OPTIONAL
+}
+
+-- encoded Transited field
+TransitedEncoding       ::= SEQUENCE {
+        tr-type         [0] Int32 -- must be registered --,
+        contents        [1] OCTET STRING
+}
+
+TicketFlags     ::= KerberosFlags
+        -- reserved(0),
+        -- forwardable(1),
+        -- forwarded(2),
+        -- proxiable(3),
+        -- proxy(4),
+        -- may-postdate(5),
+        -- postdated(6),
+        -- invalid(7),
+        -- renewable(8),
+        -- initial(9),
+        -- pre-authent(10),
+        -- hw-authent(11),
+-- the following are new since 1510
+        -- transited-policy-checked(12),
+        -- ok-as-delegate(13)
+
+AS-REQ          ::= [APPLICATION 10] KDC-REQ
+
+TGS-REQ         ::= [APPLICATION 12] KDC-REQ
+
+KDC-REQ         ::= SEQUENCE {
+        -- NOTE: first tag is [1], not [0]
+        pvno            [1] INTEGER (5) ,
+        msg-type        [2] INTEGER (10 -- AS -- | 12 -- TGS --),
+        padata          [3] SEQUENCE OF PA-DATA OPTIONAL
+                            -- NOTE: not empty --,
+        req-body        [4] KDC-REQ-BODY
+}
+
+KDC-REQ-BODY    ::= SEQUENCE {
+        kdc-options             [0] KDCOptions,
+        cname                   [1] PrincipalName OPTIONAL
+                                    -- Used only in AS-REQ --,
+        realm                   [2] Realm
+                                    -- Server's realm
+                                    -- Also client's in AS-REQ --,
+        sname                   [3] PrincipalName OPTIONAL,
+        from                    [4] KerberosTime OPTIONAL,
+        till                    [5] KerberosTime,
+        rtime                   [6] KerberosTime OPTIONAL,
+        nonce                   [7] UInt32,
+        etype                   [8] SEQUENCE OF Int32 -- EncryptionType
+                                    -- in preference order --,
+        addresses               [9] HostAddresses OPTIONAL,
+        enc-authorization-data  [10] EncryptedData OPTIONAL
+                                    -- AuthorizationData --,
+        additional-tickets      [11] SEQUENCE OF Ticket OPTIONAL
+                                        -- NOTE: not empty
+}
+
+KDCOptions      ::= KerberosFlags
+        -- reserved(0),
+        -- forwardable(1),
+        -- forwarded(2),
+        -- proxiable(3),
+        -- proxy(4),
+        -- allow-postdate(5),
+        -- postdated(6),
+        -- unused7(7),
+        -- renewable(8),
+        -- unused9(9),
+        -- unused10(10),
+        -- opt-hardware-auth(11),
+        -- unused12(12),
+        -- unused13(13),
+-- 15 is reserved for canonicalize
+        -- unused15(15),
+-- 26 was unused in 1510
+        -- disable-transited-check(26),
+--
+        -- renewable-ok(27),
+        -- enc-tkt-in-skey(28),
+        -- renew(30),
+        -- validate(31)
+
+AS-REP          ::= [APPLICATION 11] KDC-REP
+
+TGS-REP         ::= [APPLICATION 13] KDC-REP
+
+KDC-REP         ::= SEQUENCE {
+        pvno            [0] INTEGER (5),
+        msg-type        [1] INTEGER (11 -- AS -- | 13 -- TGS --),
+        padata          [2] SEQUENCE OF PA-DATA OPTIONAL
+                                -- NOTE: not empty --,
+        crealm          [3] Realm,
+        cname           [4] PrincipalName,
+        ticket          [5] Ticket,
+        enc-part        [6] EncryptedData
+                                -- EncASRepPart or EncTGSRepPart,
+                                -- as appropriate
+}
+
+EncASRepPart    ::= [APPLICATION 25] EncKDCRepPart
+
+EncTGSRepPart   ::= [APPLICATION 26] EncKDCRepPart
+
+EncKDCRepPart   ::= SEQUENCE {
+        key             [0] EncryptionKey,
+        last-req        [1] LastReq,
+        nonce           [2] UInt32,
+        key-expiration  [3] KerberosTime OPTIONAL,
+        flags           [4] TicketFlags,
+        authtime        [5] KerberosTime,
+        starttime       [6] KerberosTime OPTIONAL,
+        endtime         [7] KerberosTime,
+        renew-till      [8] KerberosTime OPTIONAL,
+        srealm          [9] Realm,
+        sname           [10] PrincipalName,
+        caddr           [11] HostAddresses OPTIONAL
+}
+
+LastReq         ::=     SEQUENCE OF SEQUENCE {
+        lr-type         [0] Int32,
+        lr-value        [1] KerberosTime
+}
+
+AP-REQ          ::= [APPLICATION 14] SEQUENCE {
+        pvno            [0] INTEGER (5),
+        msg-type        [1] INTEGER (14),
+        ap-options      [2] APOptions,
+        ticket          [3] Ticket,
+        authenticator   [4] EncryptedData -- Authenticator
+}
+
+APOptions       ::= KerberosFlags
+        -- reserved(0),
+        -- use-session-key(1),
+        -- mutual-required(2)
+
+-- Unencrypted authenticator
+Authenticator   ::= [APPLICATION 2] SEQUENCE  {
+        authenticator-vno       [0] INTEGER (5),
+        crealm                  [1] Realm,
+        cname                   [2] PrincipalName,
+        cksum                   [3] Checksum OPTIONAL,
+        cusec                   [4] Microseconds,
+        ctime                   [5] KerberosTime,
+        subkey                  [6] EncryptionKey OPTIONAL,
+        seq-number              [7] UInt32 OPTIONAL,
+        authorization-data      [8] AuthorizationData OPTIONAL
+}
+
+AP-REP          ::= [APPLICATION 15] SEQUENCE {
+        pvno            [0] INTEGER (5),
+        msg-type        [1] INTEGER (15),
+        enc-part        [2] EncryptedData -- EncAPRepPart
+}
+
+EncAPRepPart    ::= [APPLICATION 27] SEQUENCE {
+        ctime           [0] KerberosTime,
+        cusec           [1] Microseconds,
+        subkey          [2] EncryptionKey OPTIONAL,
+        seq-number      [3] UInt32 OPTIONAL
+}
+
+KRB-SAFE        ::= [APPLICATION 20] SEQUENCE {
+        pvno            [0] INTEGER (5),
+        msg-type        [1] INTEGER (20),
+        safe-body       [2] KRB-SAFE-BODY,
+        cksum           [3] Checksum
+}
+
+KRB-SAFE-BODY   ::= SEQUENCE {
+        user-data       [0] OCTET STRING,
+        timestamp       [1] KerberosTime OPTIONAL,
+        usec            [2] Microseconds OPTIONAL,
+        seq-number      [3] UInt32 OPTIONAL,
+        s-address       [4] HostAddress,
+        r-address       [5] HostAddress OPTIONAL
+}
+
+KRB-PRIV        ::= [APPLICATION 21] SEQUENCE {
+        pvno            [0] INTEGER (5),
+        msg-type        [1] INTEGER (21),
+                        -- NOTE: there is no [2] tag
+        enc-part        [3] EncryptedData -- EncKrbPrivPart
+}
+
+EncKrbPrivPart  ::= [APPLICATION 28] SEQUENCE {
+        user-data       [0] OCTET STRING,
+        timestamp       [1] KerberosTime OPTIONAL,
+        usec            [2] Microseconds OPTIONAL,
+        seq-number      [3] UInt32 OPTIONAL,
+        s-address       [4] HostAddress -- sender's addr --,
+        r-address       [5] HostAddress OPTIONAL -- recip's addr
+}
+
+KRB-CRED        ::= [APPLICATION 22] SEQUENCE {
+        pvno            [0] INTEGER (5),
+        msg-type        [1] INTEGER (22),
+        tickets         [2] SEQUENCE OF Ticket,
+        enc-part        [3] EncryptedData -- EncKrbCredPart
+}
+
+EncKrbCredPart  ::= [APPLICATION 29] SEQUENCE {
+        ticket-info     [0] SEQUENCE OF KrbCredInfo,
+        nonce           [1] UInt32 OPTIONAL,
+        timestamp       [2] KerberosTime OPTIONAL,
+        usec            [3] Microseconds OPTIONAL,
+        s-address       [4] HostAddress OPTIONAL,
+        r-address       [5] HostAddress OPTIONAL
+}
+
+KrbCredInfo     ::= SEQUENCE {
+        key             [0] EncryptionKey,
+        prealm          [1] Realm OPTIONAL,
+        pname           [2] PrincipalName OPTIONAL,
+        flags           [3] TicketFlags OPTIONAL,
+        authtime        [4] KerberosTime OPTIONAL,
+        starttime       [5] KerberosTime OPTIONAL,
+        endtime         [6] KerberosTime OPTIONAL,
+        renew-till      [7] KerberosTime OPTIONAL,
+        srealm          [8] Realm OPTIONAL,
+        sname           [9] PrincipalName OPTIONAL,
+        caddr           [10] HostAddresses OPTIONAL
+}
+
+KRB-ERROR       ::= [APPLICATION 30] SEQUENCE {
+        pvno            [0] INTEGER (5),
+        msg-type        [1] INTEGER (30),
+        ctime           [2] KerberosTime OPTIONAL,
+        cusec           [3] Microseconds OPTIONAL,
+        stime           [4] KerberosTime,
+        susec           [5] Microseconds,
+        error-code      [6] Int32,
+        crealm          [7] Realm OPTIONAL,
+        cname           [8] PrincipalName OPTIONAL,
+        realm           [9] Realm -- service realm --,
+        sname           [10] PrincipalName -- service name --,
+        e-text          [11] KerberosString OPTIONAL,
+        e-data          [12] OCTET STRING OPTIONAL
+}
+
+METHOD-DATA     ::= SEQUENCE OF PA-DATA
+
+TYPED-DATA      ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+        data-type       [0] Int32,
+        data-value      [1] OCTET STRING OPTIONAL
+}
+
+-- preauth stuff follows
+
+PA-ENC-TIMESTAMP        ::= EncryptedData -- PA-ENC-TS-ENC
+
+PA-ENC-TS-ENC           ::= SEQUENCE {
+        patimestamp     [0] KerberosTime -- client's time --,
+        pausec          [1] Microseconds OPTIONAL
+}
+
+ETYPE-INFO-ENTRY        ::= SEQUENCE {
+        etype           [0] Int32,
+        salt            [1] OCTET STRING OPTIONAL
+}
+
+ETYPE-INFO              ::= SEQUENCE OF ETYPE-INFO-ENTRY
+
+ETYPE-INFO2-ENTRY       ::= SEQUENCE {
+        etype           [0] Int32,
+        salt            [1] KerberosString OPTIONAL,
+        s2kparams       [2] OCTET STRING OPTIONAL
+}
+
+ETYPE-INFO2             ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY
+
+AD-IF-RELEVANT          ::= AuthorizationData
+
+AD-KDCIssued            ::= SEQUENCE {
+        ad-checksum     [0] Checksum,
+        i-realm         [1] Realm OPTIONAL,
+        i-sname         [2] PrincipalName OPTIONAL,
+        elements        [3] AuthorizationData
+}
+
+AD-AND-OR               ::= SEQUENCE {
+        condition-count [0] Int32,
+        elements        [1] AuthorizationData
+}
+
+AD-MANDATORY-FOR-KDC    ::= AuthorizationData
+
+END
diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c
index 87d3bc4..8719978 100644
--- a/src/tests/asn.1/krb5_decode_test.c
+++ b/src/tests/asn.1/krb5_decode_test.c
@@ -1030,6 +1030,53 @@ int main(argc, argv)
         ktest_destroy_enc_data(&ref);
     }
 
+    /****************************************************************/
+    /* decode_krb5_otp_tokeninfo */
+    {
+        setup(krb5_otp_tokeninfo,ktest_make_minimal_otp_tokeninfo);
+        decode_run("otp_tokeninfo","(optionals NULL)","30 07 80 05 00 00 00 00 00",decode_krb5_otp_tokeninfo,ktest_equal_otp_tokeninfo,k5_free_otp_tokeninfo);
+        ktest_empty_otp_tokeninfo(&ref);
+    }
+    {
+        setup(krb5_otp_tokeninfo,ktest_make_maximal_otp_tokeninfo);
+        decode_run("otp_tokeninfo","","30 72 80 05 00 77 00 00 00 81 0B 45 78 61 6D 70 6C 65 63 6F 72 70 82 05 68 61 72 6B 21 83 01 0A 84 01 02 85 09 79 6F 75 72 74 6F 6B 65 6E 86 28 75 72 6E 3A 69 65 74 66 3A 70 61 72 61 6D 73 3A 78 6D 6C 3A 6E 73 3A 6B 65 79 70 72 6F 76 3A 70 73 6B 63 3A 68 6F 74 70 A7 16 30 0B 06 09 60 86 48 01 65 03 04 02 01 30 07 06 05 2B 0E 03 02 1A 88 02 03 E8",decode_krb5_otp_tokeninfo,ktest_equal_otp_tokeninfo,k5_free_otp_tokeninfo);
+        ktest_empty_otp_tokeninfo(&ref);
+    }
+
+    /****************************************************************/
+    /* decode_krb5_pa_otp_challenge */
+    {
+        setup(krb5_pa_otp_challenge,ktest_make_minimal_pa_otp_challenge);
+        decode_run("pa_otp_challenge","(optionals NULL)","30 15 80 08 6D 69 6E 6E 6F 6E 63 65 A2 09 30 07 80 05 00 00 00 00 00",decode_krb5_pa_otp_challenge,ktest_equal_pa_otp_challenge,k5_free_pa_otp_challenge);
+        ktest_empty_pa_otp_challenge(&ref);
+    }
+    {
+        setup(krb5_pa_otp_challenge,ktest_make_maximal_pa_otp_challenge);
+        decode_run("pa_otp_challenge","","30 81 A5 80 08 6D 61 78 6E 6F 6E 63 65 81 0B 74 65 73 74 73 65 72 76 69 63 65 A2 7D 30 07 80 05 00 00 00 00 00 30 72 80 05 00 77 00 00 00 81 0B 45 78 61 6D 70 6C 65 63 6F 72 70 82 05 68 61 72 6B 21 83 01 0A 84 01 02 85 09 79 6F 75 72 74 6F 6B 65 6E 86 28 75 72 6E 3A 69 65 74 66 3A 70 61 72 61 6D 73 3A 78 6D 6C 3A 6E 73 3A 6B 65 79 70 72 6F 76 3A 70 73 6B 63 3A 68 6F 74 70 A7 16 30 0B 06 09 60 86 48 01 65 03 04 02 01 30 07 06 05 2B 0E 03 02 1A 88 02 03 E8 83 07 6B 65 79 73 61 6C 74 84 04 31 32 33 34",decode_krb5_pa_otp_challenge,ktest_equal_pa_otp_challenge,k5_free_pa_otp_challenge);
+        ktest_empty_pa_otp_challenge(&ref);
+    }
+
+    /****************************************************************/
+    /* decode_krb5_pa_otp_req */
+    {
+        setup(krb5_pa_otp_req,ktest_make_minimal_pa_otp_req);
+        decode_run("pa_otp_req","(optionals NULL)","30 2C 80 05 00 00 00 00 00 A2 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_pa_otp_req,ktest_equal_pa_otp_req,k5_free_pa_otp_req);
+        ktest_empty_pa_otp_req(&ref);
+    }
+    {
+        setup(krb5_pa_otp_req,ktest_make_maximal_pa_otp_req);
+        decode_run("pa_otp_req","","30 81 B9 80 05 00 60 00 00 00 81 05 6E 6F 6E 63 65 A2 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A3 0B 06 09 60 86 48 01 65 03 04 02 01 84 02 03 E8 85 05 66 72 6F 67 73 86 0A 6D 79 66 69 72 73 74 70 69 6E 87 05 68 61 72 6B 21 88 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 89 03 33 34 36 8A 01 02 8B 09 79 6F 75 72 74 6F 6B 65 6E 8C 28 75 72 6E 3A 69 65 74 66 3A 70 61 72 61 6D 73 3A 78 6D 6C 3A 6E 73 3A 6B 65 79 70 72 6F 76 3A 70 73 6B 63 3A 68 6F 74 70 8D 0B 45 78 61 6D 70 6C 65 63 6F 72 70",decode_krb5_pa_otp_req,ktest_equal_pa_otp_req,k5_free_pa_otp_req);
+        ktest_empty_pa_otp_req(&ref);
+    }
+
+    /****************************************************************/
+    /* decode_krb5_pa_otp_enc_req */
+    {
+        setup(krb5_data,ktest_make_sample_data);
+        decode_run("pa_otp_enc_req","","30 0A 80 08 6B 72 62 35 64 61 74 61",decode_krb5_pa_otp_enc_req,ktest_equal_data,krb5_free_data);
+        ktest_empty_data(&ref);
+    }
+
 #ifndef DISABLE_PKINIT
 
     /****************************************************************/
diff --git a/src/tests/asn.1/krb5_encode_test.c b/src/tests/asn.1/krb5_encode_test.c
index df2d101..638f6fe 100644
--- a/src/tests/asn.1/krb5_encode_test.c
+++ b/src/tests/asn.1/krb5_encode_test.c
@@ -690,6 +690,50 @@ main(argc, argv)
                    encode_krb5_pa_fx_fast_reply);
         ktest_destroy_enc_data(&enc_data);
     }
+    /****************************************************************/
+    /* encode_krb5_otp_tokeninfo */
+    {
+        krb5_otp_tokeninfo ti;
+        ktest_make_minimal_otp_tokeninfo(&ti);
+        encode_run(ti, "otp_tokeninfo", "(optionals NULL)",
+                   encode_krb5_otp_tokeninfo);
+        ktest_empty_otp_tokeninfo(&ti);
+        ktest_make_maximal_otp_tokeninfo(&ti);
+        encode_run(ti, "otp_tokeninfo", "", encode_krb5_otp_tokeninfo);
+        ktest_empty_otp_tokeninfo(&ti);
+    }
+    /****************************************************************/
+    /* encode_krb5_pa_otp_challenge */
+    {
+        krb5_pa_otp_challenge ch;
+        ktest_make_minimal_pa_otp_challenge(&ch);
+        encode_run(ch, "pa_otp_challenge", "(optionals NULL)",
+                   encode_krb5_pa_otp_challenge);
+        ktest_empty_pa_otp_challenge(&ch);
+        ktest_make_maximal_pa_otp_challenge(&ch);
+        encode_run(ch, "pa_otp_challenge", "", encode_krb5_pa_otp_challenge);
+        ktest_empty_pa_otp_challenge(&ch);
+    }
+    /****************************************************************/
+    /* encode_krb5_pa_otp_req */
+    {
+        krb5_pa_otp_req req;
+        ktest_make_minimal_pa_otp_req(&req);
+        encode_run(req, "pa_otp_req", "(optionals NULL)",
+                   encode_krb5_pa_otp_req);
+        ktest_empty_pa_otp_req(&req);
+        ktest_make_maximal_pa_otp_req(&req);
+        encode_run(req, "pa_otp_req", "", encode_krb5_pa_otp_req);
+        ktest_empty_pa_otp_req(&req);
+    }
+    /****************************************************************/
+    /* encode_krb5_pa_otp_enc_request */
+    {
+        krb5_data d;
+        ktest_make_sample_data(&d);
+        encode_run(d, "pa_otp_enc_req", "", encode_krb5_pa_otp_enc_req);
+        ktest_empty_data(&d);
+    }
 #ifndef DISABLE_PKINIT
     /****************************************************************/
     /* encode_krb5_pa_pk_as_req */
diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
index 6de0cb0..e734aeb 100644
--- a/src/tests/asn.1/ktest.c
+++ b/src/tests/asn.1/ktest.c
@@ -615,6 +615,105 @@ ktest_make_sample_fast_response(krb5_fast_response *p)
     p->nonce = SAMPLE_NONCE;
 }
 
+void
+ktest_make_sha256_alg(krb5_algorithm_identifier *p)
+{
+    /* { 2 16 840 1 101 3 4 2 1 } */
+    krb5_data_parse(&p->algorithm, "\x60\x86\x48\x01\x65\x03\x04\x02\x01");
+    p->parameters = empty_data();
+}
+
+void
+ktest_make_sha1_alg(krb5_algorithm_identifier *p)
+{
+    /* { 1 3 14 3 2 26 } */
+    krb5_data_parse(&p->algorithm, "\x2b\x0e\x03\x02\x1a");
+    p->parameters = empty_data();
+}
+
+void
+ktest_make_minimal_otp_tokeninfo(krb5_otp_tokeninfo *p)
+{
+    memset(p, 0, sizeof(*p));
+    p->length = p->format = p->iteration_count = -1;
+}
+
+void
+ktest_make_maximal_otp_tokeninfo(krb5_otp_tokeninfo *p)
+{
+    p->flags = KRB5_OTP_FLAG_NEXTOTP | KRB5_OTP_FLAG_COMBINE |
+        KRB5_OTP_FLAG_COLLECT_PIN | KRB5_OTP_FLAG_ENCRYPT_NONCE |
+        KRB5_OTP_FLAG_SEPARATE_PIN | KRB5_OTP_FLAG_CHECK_DIGIT;
+    krb5_data_parse(&p->vendor, "Examplecorp");
+    krb5_data_parse(&p->challenge, "hark!");
+    p->length = 10;
+    p->format = 2;
+    krb5_data_parse(&p->token_id, "yourtoken");
+    krb5_data_parse(&p->alg_id, "urn:ietf:params:xml:ns:keyprov:pskc:hotp");
+    p->supported_hash_alg = ealloc(3 * sizeof(*p->supported_hash_alg));
+    p->supported_hash_alg[0] = ealloc(sizeof(*p->supported_hash_alg[0]));
+    ktest_make_sha256_alg(p->supported_hash_alg[0]);
+    p->supported_hash_alg[1] = ealloc(sizeof(*p->supported_hash_alg[1]));
+    ktest_make_sha1_alg(p->supported_hash_alg[1]);
+    p->supported_hash_alg[2] = NULL;
+    p->iteration_count = 1000;
+}
+
+void
+ktest_make_minimal_pa_otp_challenge(krb5_pa_otp_challenge *p)
+{
+    memset(p, 0, sizeof(*p));
+    krb5_data_parse(&p->nonce, "minnonce");
+    p->tokeninfo = ealloc(2 * sizeof(*p->tokeninfo));
+    p->tokeninfo[0] = ealloc(sizeof(*p->tokeninfo[0]));
+    ktest_make_minimal_otp_tokeninfo(p->tokeninfo[0]);
+    p->tokeninfo[1] = NULL;
+}
+
+void
+ktest_make_maximal_pa_otp_challenge(krb5_pa_otp_challenge *p)
+{
+    krb5_data_parse(&p->nonce, "maxnonce");
+    krb5_data_parse(&p->service, "testservice");
+    p->tokeninfo = ealloc(3 * sizeof(*p->tokeninfo));
+    p->tokeninfo[0] = ealloc(sizeof(*p->tokeninfo[0]));
+    ktest_make_minimal_otp_tokeninfo(p->tokeninfo[0]);
+    p->tokeninfo[1] = ealloc(sizeof(*p->tokeninfo[1]));
+    ktest_make_maximal_otp_tokeninfo(p->tokeninfo[1]);
+    p->tokeninfo[2] = NULL;
+    krb5_data_parse(&p->salt, "keysalt");
+    krb5_data_parse(&p->s2kparams, "1234");
+}
+
+void
+ktest_make_minimal_pa_otp_req(krb5_pa_otp_req *p)
+{
+    memset(p, 0, sizeof(*p));
+    p->iteration_count = -1;
+    p->format = -1;
+    ktest_make_sample_enc_data(&p->enc_data);
+}
+
+void
+ktest_make_maximal_pa_otp_req(krb5_pa_otp_req *p)
+{
+    p->flags = KRB5_OTP_FLAG_NEXTOTP | KRB5_OTP_FLAG_COMBINE;
+    krb5_data_parse(&p->nonce, "nonce");
+    ktest_make_sample_enc_data(&p->enc_data);
+    p->hash_alg = ealloc(sizeof(*p->hash_alg));
+    ktest_make_sha256_alg(p->hash_alg);
+    p->iteration_count = 1000;
+    krb5_data_parse(&p->otp_value, "frogs");
+    krb5_data_parse(&p->pin, "myfirstpin");
+    krb5_data_parse(&p->challenge, "hark!");
+    p->time = SAMPLE_TIME;
+    krb5_data_parse(&p->counter, "346");
+    p->format = 2;
+    krb5_data_parse(&p->token_id, "yourtoken");
+    krb5_data_parse(&p->alg_id, "urn:ietf:params:xml:ns:keyprov:pskc:hotp");
+    krb5_data_parse(&p->vendor, "Examplecorp");
+}
+
 #ifndef DISABLE_PKINIT
 
 static void
@@ -1396,6 +1495,71 @@ ktest_empty_fast_response(krb5_fast_response *p)
     }
 }
 
+static void
+ktest_empty_algorithm_identifier(krb5_algorithm_identifier *p)
+{
+    ktest_empty_data(&p->algorithm);
+    ktest_empty_data(&p->parameters);
+}
+
+void
+ktest_empty_otp_tokeninfo(krb5_otp_tokeninfo *p)
+{
+    krb5_algorithm_identifier **alg;
+
+    p->flags = 0;
+    krb5_free_data_contents(NULL, &p->vendor);
+    krb5_free_data_contents(NULL, &p->challenge);
+    krb5_free_data_contents(NULL, &p->token_id);
+    krb5_free_data_contents(NULL, &p->alg_id);
+    for (alg = p->supported_hash_alg; alg != NULL && *alg != NULL; alg++) {
+        ktest_empty_algorithm_identifier(*alg);
+        free(*alg);
+    }
+    free(p->supported_hash_alg);
+    p->supported_hash_alg = NULL;
+    p->length = p->format = p->iteration_count = -1;
+}
+
+void
+ktest_empty_pa_otp_challenge(krb5_pa_otp_challenge *p)
+{
+    krb5_otp_tokeninfo **ti;
+
+    krb5_free_data_contents(NULL, &p->nonce);
+    krb5_free_data_contents(NULL, &p->service);
+    for (ti = p->tokeninfo; *ti != NULL; ti++) {
+        ktest_empty_otp_tokeninfo(*ti);
+        free(*ti);
+    }
+    free(p->tokeninfo);
+    p->tokeninfo = NULL;
+    krb5_free_data_contents(NULL, &p->salt);
+    krb5_free_data_contents(NULL, &p->s2kparams);
+}
+
+void
+ktest_empty_pa_otp_req(krb5_pa_otp_req *p)
+{
+    p->flags = 0;
+    krb5_free_data_contents(NULL, &p->nonce);
+    ktest_destroy_enc_data(&p->enc_data);
+    if (p->hash_alg != NULL)
+        ktest_empty_algorithm_identifier(p->hash_alg);
+    free(p->hash_alg);
+    p->hash_alg = NULL;
+    p->iteration_count = -1;
+    krb5_free_data_contents(NULL, &p->otp_value);
+    krb5_free_data_contents(NULL, &p->pin);
+    krb5_free_data_contents(NULL, &p->challenge);
+    p->time = 0;
+    krb5_free_data_contents(NULL, &p->counter);
+    p->format = -1;
+    krb5_free_data_contents(NULL, &p->token_id);
+    krb5_free_data_contents(NULL, &p->alg_id);
+    krb5_free_data_contents(NULL, &p->vendor);
+}
+
 #ifndef DISABLE_PKINIT
 
 static void
@@ -1412,13 +1576,6 @@ ktest_empty_pk_authenticator_draft9(krb5_pk_authenticator_draft9 *p)
 }
 
 static void
-ktest_empty_algorithm_identifier(krb5_algorithm_identifier *p)
-{
-    ktest_empty_data(&p->algorithm);
-    ktest_empty_data(&p->parameters);
-}
-
-static void
 ktest_empty_subject_pk_info(krb5_subject_pk_info *p)
 {
     ktest_empty_algorithm_identifier(&p->algorithm);
diff --git a/src/tests/asn.1/ktest.h b/src/tests/asn.1/ktest.h
index 8b81131..67a6c69 100644
--- a/src/tests/asn.1/ktest.h
+++ b/src/tests/asn.1/ktest.h
@@ -89,6 +89,14 @@ void ktest_make_sample_ad_signedpath(krb5_ad_signedpath *p);
 void ktest_make_sample_iakerb_header(krb5_iakerb_header *p);
 void ktest_make_sample_iakerb_finished(krb5_iakerb_finished *p);
 void ktest_make_sample_fast_response(krb5_fast_response *p);
+void ktest_make_sha256_alg(krb5_algorithm_identifier *p);
+void ktest_make_sha1_alg(krb5_algorithm_identifier *p);
+void ktest_make_minimal_otp_tokeninfo(krb5_otp_tokeninfo *p);
+void ktest_make_maximal_otp_tokeninfo(krb5_otp_tokeninfo *p);
+void ktest_make_minimal_pa_otp_challenge(krb5_pa_otp_challenge *p);
+void ktest_make_maximal_pa_otp_challenge(krb5_pa_otp_challenge *p);
+void ktest_make_minimal_pa_otp_req(krb5_pa_otp_req *p);
+void ktest_make_maximal_pa_otp_req(krb5_pa_otp_req *p);
 
 #ifndef DISABLE_PKINIT
 void ktest_make_sample_pa_pk_as_req(krb5_pa_pk_as_req *p);
@@ -170,6 +178,9 @@ void ktest_empty_ad_signedpath(krb5_ad_signedpath *p);
 void ktest_empty_iakerb_header(krb5_iakerb_header *p);
 void ktest_empty_iakerb_finished(krb5_iakerb_finished *p);
 void ktest_empty_fast_response(krb5_fast_response *p);
+void ktest_empty_otp_tokeninfo(krb5_otp_tokeninfo *p);
+void ktest_empty_pa_otp_challenge(krb5_pa_otp_challenge *p);
+void ktest_empty_pa_otp_req(krb5_pa_otp_req *p);
 
 #ifndef DISABLE_PKINIT
 void ktest_empty_pa_pk_as_req(krb5_pa_pk_as_req *p);
diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c
index 6953708..4e71242 100644
--- a/src/tests/asn.1/ktest_equal.c
+++ b/src/tests/asn.1/ktest_equal.c
@@ -613,6 +613,75 @@ ktest_equal_fast_response(krb5_fast_response *ref, krb5_fast_response *var)
     return p;
 }
 
+static int
+ktest_equal_algorithm_identifier(krb5_algorithm_identifier *ref,
+                                 krb5_algorithm_identifier *var)
+{
+    int p = TRUE;
+    if (ref == var) return TRUE;
+    else if (ref == NULL || var == NULL) return FALSE;
+    p = p && equal_str(algorithm);
+    p = p && equal_str(parameters);
+    return p;
+}
+
+int
+ktest_equal_otp_tokeninfo(krb5_otp_tokeninfo *ref, krb5_otp_tokeninfo *var)
+{
+    int p = TRUE;
+    if (ref == var) return TRUE;
+    else if (ref == NULL || var == NULL) return FALSE;
+    p = p && scalar_equal(flags);
+    p = p && equal_str(vendor);
+    p = p && equal_str(challenge);
+    p = p && scalar_equal(length);
+    p = p && scalar_equal(format);
+    p = p && equal_str(token_id);
+    p = p && equal_str(alg_id);
+    p = p && ptr_equal(supported_hash_alg,
+                       ktest_equal_sequence_of_algorithm_identifier);
+    p = p && scalar_equal(iteration_count);
+    return p;
+}
+
+int
+ktest_equal_pa_otp_challenge(krb5_pa_otp_challenge *ref,
+                             krb5_pa_otp_challenge *var)
+{
+    int p = TRUE;
+    if (ref == var) return TRUE;
+    else if (ref == NULL || var == NULL) return FALSE;
+    p = p && equal_str(nonce);
+    p = p && equal_str(service);
+    p = p && ptr_equal(tokeninfo, ktest_equal_sequence_of_otp_tokeninfo);
+    p = p && equal_str(salt);
+    p = p && equal_str(s2kparams);
+    return p;
+}
+
+int
+ktest_equal_pa_otp_req(krb5_pa_otp_req *ref, krb5_pa_otp_req *var)
+{
+    int p = TRUE;
+    if (ref == var) return TRUE;
+    else if (ref == NULL || var == NULL) return FALSE;
+    p = p && scalar_equal(flags);
+    p = p && equal_str(nonce);
+    p = p && struct_equal(enc_data, ktest_equal_enc_data);
+    p = p && ptr_equal(hash_alg, ktest_equal_algorithm_identifier);
+    p = p && scalar_equal(iteration_count);
+    p = p && equal_str(otp_value);
+    p = p && equal_str(pin);
+    p = p && equal_str(challenge);
+    p = p && scalar_equal(time);
+    p = p && equal_str(counter);
+    p = p && scalar_equal(format);
+    p = p && equal_str(token_id);
+    p = p && equal_str(alg_id);
+    p = p && equal_str(vendor);
+    return p;
+}
+
 #ifdef ENABLE_LDAP
 static int
 equal_key_data(krb5_key_data *ref, krb5_key_data *var)
@@ -770,6 +839,20 @@ ktest_equal_sequence_of_checksum(krb5_checksum **ref, krb5_checksum **var)
     array_compare(ktest_equal_checksum);
 }
 
+int
+ktest_equal_sequence_of_algorithm_identifier(krb5_algorithm_identifier **ref,
+                                             krb5_algorithm_identifier **var)
+{
+    array_compare(ktest_equal_algorithm_identifier);
+}
+
+int
+ktest_equal_sequence_of_otp_tokeninfo(krb5_otp_tokeninfo **ref,
+                                      krb5_otp_tokeninfo **var)
+{
+    array_compare(ktest_equal_otp_tokeninfo);
+}
+
 #ifndef DISABLE_PKINIT
 
 static int
@@ -801,25 +884,6 @@ ktest_equal_pk_authenticator_draft9(krb5_pk_authenticator_draft9 *ref,
 }
 
 static int
-ktest_equal_algorithm_identifier(krb5_algorithm_identifier *ref,
-                                 krb5_algorithm_identifier *var)
-{
-    int p = TRUE;
-    if (ref == var) return TRUE;
-    else if (ref == NULL || var == NULL) return FALSE;
-    p = p && equal_str(algorithm);
-    p = p && equal_str(parameters);
-    return p;
-}
-
-static int
-ktest_equal_sequence_of_algorithm_identifier(krb5_algorithm_identifier **ref,
-                                             krb5_algorithm_identifier **var)
-{
-    array_compare(ktest_equal_algorithm_identifier);
-}
-
-static int
 ktest_equal_subject_pk_info(krb5_subject_pk_info *ref,
                             krb5_subject_pk_info *var)
 {
diff --git a/src/tests/asn.1/ktest_equal.h b/src/tests/asn.1/ktest_equal.h
index ab31e29..e75f86a 100644
--- a/src/tests/asn.1/ktest_equal.h
+++ b/src/tests/asn.1/ktest_equal.h
@@ -92,6 +92,11 @@ int ktest_equal_sequence_of_cred_info(krb5_cred_info **ref,
 int ktest_equal_sequence_of_principal(krb5_principal *ref,
                                       krb5_principal *var);
 int ktest_equal_sequence_of_checksum(krb5_checksum **ref, krb5_checksum **var);
+int
+ktest_equal_sequence_of_algorithm_identifier(krb5_algorithm_identifier **ref,
+                                             krb5_algorithm_identifier **var);
+int ktest_equal_sequence_of_otp_tokeninfo(krb5_otp_tokeninfo **ref,
+                                          krb5_otp_tokeninfo **var);
 
 len_array(ktest_equal_array_of_enctype,krb5_enctype);
 len_array(ktest_equal_array_of_data,krb5_data);
@@ -120,6 +125,11 @@ int ktest_equal_iakerb_finished(krb5_iakerb_finished *ref,
                                 krb5_iakerb_finished *var);
 int ktest_equal_fast_response(krb5_fast_response *ref,
                               krb5_fast_response *var);
+int ktest_equal_otp_tokeninfo(krb5_otp_tokeninfo *ref,
+                              krb5_otp_tokeninfo *var);
+int ktest_equal_pa_otp_challenge(krb5_pa_otp_challenge *ref,
+                                 krb5_pa_otp_challenge *var);
+int ktest_equal_pa_otp_req(krb5_pa_otp_req *ref, krb5_pa_otp_req *var);
 
 int ktest_equal_ldap_sequence_of_keys(ldap_seqof_key_data *ref,
                                       ldap_seqof_key_data *var);
diff --git a/src/tests/asn.1/make-vectors.c b/src/tests/asn.1/make-vectors.c
new file mode 100644
index 0000000..fd7bd48
--- /dev/null
+++ b/src/tests/asn.1/make-vectors.c
@@ -0,0 +1,170 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* tests/asn.1/make-vectors.c - Generate ASN.1 test vectors using asn1c */
+/*
+ * Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * This program generates test vectors using asn1c, to be included in other
+ * test programs which exercise the krb5 ASN.1 encoder and decoder functions.
+ * It is intended to be used via "make test-vectors".  Currently, test vectors
+ * are only generated for OTP preauth objects.
+ */
+
+#include <OTP-TOKENINFO.h>
+#include <PA-OTP-CHALLENGE.h>
+#include <PA-OTP-REQUEST.h>
+#include <PA-OTP-ENC-REQUEST.h>
+
+static unsigned char buf[8192];
+static size_t buf_pos;
+
+/* Minimal OTP-TOKENINFO */
+static OTP_TOKENINFO_t token_info_1 = { { "\0\0\0\0", 4, 0 } };
+
+/* Maximal OTP-TOKENINFO */
+static UTF8String_t vendor = { "Examplecorp", 11 };
+static OCTET_STRING_t challenge = { "hark!", 5 };
+static Int32_t otp_length = 10;
+static OTPFormat_t otp_format; /* Initialized to 2 in main(). */
+static OCTET_STRING_t token_id = { "yourtoken", 9 };
+static AnyURI_t otp_alg = { "urn:ietf:params:xml:ns:keyprov:pskc:hotp", 40 };
+static unsigned int sha256_arcs[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
+static unsigned int sha1_arcs[] = { 1, 3, 14, 3, 2, 26 };
+static AlgorithmIdentifier_t alg_sha256, alg_sha1; /* Initialized in main(). */
+static AlgorithmIdentifier_t *algs[] = { &alg_sha256, &alg_sha1 };
+static struct supportedHashAlg hash_algs = { algs, 2, 2 };
+static Int32_t iter_count = 1000;
+/* Flags are nextOTP | combine | collect-pin | must-encrypt-nonce |
+ * separate-pin-required | check-digit */
+static OTP_TOKENINFO_t token_info_2 = { { "\x77\0\0\0", 4, 0 }, &vendor,
+                                        &challenge, &otp_length, &otp_format,
+                                        &token_id, &otp_alg, &hash_algs,
+                                        &iter_count };
+
+/* Minimal PA-OTP-CHALLENGE */
+static OTP_TOKENINFO_t *tinfo_1[] = { &token_info_1 };
+static PA_OTP_CHALLENGE_t challenge_1 = { { "minnonce", 8 }, NULL,
+                                          { { tinfo_1, 1, 1 } } };
+
+/* Maximal PA-OTP-CHALLENGE */
+static OTP_TOKENINFO_t *tinfo_2[] = { &token_info_1, &token_info_2 };
+static UTF8String_t service = { "testservice", 11 };
+static KerberosString_t salt = { "keysalt", 7 };
+static OCTET_STRING_t s2kparams = { "1234", 4 };
+static PA_OTP_CHALLENGE_t challenge_2 = { { "maxnonce", 8 }, &service,
+                                          { { tinfo_2, 2, 2 } }, &salt,
+                                          &s2kparams };
+
+/* Minimal PA-OTP-REQUEST */
+static UInt32_t kvno;           /* Initialized to 5 in main(). */
+static PA_OTP_REQUEST_t request_1 = { { "\0\0\0\0", 4, 0 }, NULL,
+                                      { 0, &kvno,
+                                        { "krbASN.1 test message", 21 } } };
+
+/* Maximal PA-OTP-REQUEST */
+/* Flags are nextOTP | combine */
+static OCTET_STRING_t nonce = { "nonce", 5 };
+static OCTET_STRING_t otp_value = { "frogs", 5 };
+static UTF8String_t otp_pin = { "myfirstpin", 10 };
+/* Corresponds to Unix time 771228197 */
+static KerberosTime_t otp_time = { "19940610060317Z", 15 };
+static OCTET_STRING_t counter = { "346", 3 };
+static PA_OTP_REQUEST_t request_2 = { { "\x60\0\0\0", 4, 0 }, &nonce,
+                                      { 0, &kvno,
+                                        { "krbASN.1 test message", 21 } },
+                                      &alg_sha256, &iter_count, &otp_value,
+                                      &otp_pin, &challenge, &otp_time,
+                                      &counter, &otp_format, &token_id,
+                                      &otp_alg, &vendor };
+
+/* PA-OTP-ENC-REQUEST */
+static PA_OTP_ENC_REQUEST_t enc_request = { { "krb5data", 8 } };
+
+static int
+consume(const void *data, size_t size, void *dummy)
+{
+    memcpy(buf + buf_pos, data, size);
+    buf_pos += size;
+    return 0;
+}
+
+/* Display a C string literal representing the contents of buf, and
+ * reinitialize buf_pos for the next encoding operation. */
+static void
+printbuf(void)
+{
+    size_t i;
+
+    for (i = 0; i < buf_pos; i++) {
+        printf("%02X", buf[i]);
+        if (i + 1 < buf_pos)
+            printf(" ");
+    }
+    buf_pos = 0;
+}
+
+int
+main()
+{
+    /* Initialize values which can't use static initializers. */
+    asn_long2INTEGER(&otp_format, 2);  /* Alphanumeric */
+    asn_long2INTEGER(&kvno, 5);
+    OBJECT_IDENTIFIER_set_arcs(&alg_sha256.algorithm, sha256_arcs,
+                               sizeof(*sha256_arcs),
+                               sizeof(sha256_arcs) / sizeof(*sha256_arcs));
+    OBJECT_IDENTIFIER_set_arcs(&alg_sha1.algorithm, sha1_arcs,
+                               sizeof(*sha1_arcs),
+                               sizeof(sha1_arcs) / sizeof(*sha1_arcs));
+
+    printf("Minimal OTP-TOKEN-INFO:\n");
+    der_encode(&asn_DEF_OTP_TOKENINFO, &token_info_1, consume, NULL);
+    printbuf();
+
+    printf("\nMaximal OTP-TOKEN-INFO:\n");
+    der_encode(&asn_DEF_OTP_TOKENINFO, &token_info_2, consume, NULL);
+    printbuf();
+
+    printf("\nMinimal PA-OTP-CHALLENGE:\n");
+    der_encode(&asn_DEF_PA_OTP_CHALLENGE, &challenge_1, consume, NULL);
+    printbuf();
+
+    printf("\nMaximal PA-OTP-CHALLENGE:\n");
+    der_encode(&asn_DEF_PA_OTP_CHALLENGE, &challenge_2, consume, NULL);
+    printbuf();
+
+    printf("\nMinimal PA-OTP-REQUEST:\n");
+    der_encode(&asn_DEF_PA_OTP_REQUEST, &request_1, consume, NULL);
+    printbuf();
+
+    printf("\nMaximal PA-OTP-REQUEST:\n");
+    der_encode(&asn_DEF_PA_OTP_REQUEST, &request_2, consume, NULL);
+    printbuf();
+
+    printf("\nPA-OTP-ENC-REQUEST:\n");
+    der_encode(&asn_DEF_PA_OTP_ENC_REQUEST, &enc_request, consume, NULL);
+    printbuf();
+
+    printf("\n");
+    return 0;
+}
diff --git a/src/tests/asn.1/otp.asn1 b/src/tests/asn.1/otp.asn1
new file mode 100644
index 0000000..2e32432
--- /dev/null
+++ b/src/tests/asn.1/otp.asn1
@@ -0,0 +1,109 @@
+   OTPKerberos
+   DEFINITIONS IMPLICIT TAGS ::=
+   BEGIN
+
+   IMPORTS
+
+       KerberosTime, KerberosFlags, EncryptionKey, Int32,
+       EncryptedData, LastReq, KerberosString
+       FROM KerberosV5Spec2 {iso(1) identified-organization(3)
+                             dod(6) internet(1) security(5)
+                             kerberosV5(2) modules(4) krb5spec2(2)}
+                             -- as defined in RFC 4120.
+       AlgorithmIdentifier
+       FROM PKIX1Explicit88 { iso (1) identified-organization (3)
+                              dod (6) internet (1)
+                              security (5) mechanisms (5) pkix (7)
+                              id-mod (0) id-pkix1-explicit (18) };
+                              -- As defined in RFC 5280.
+
+       PA-OTP-CHALLENGE ::= SEQUENCE {
+         nonce            [0] OCTET STRING,
+         otp-service      [1] UTF8String               OPTIONAL,
+         otp-tokenInfo    [2] SEQUENCE (SIZE(1..MAX)) OF
+                                                  OTP-TOKENINFO,
+         salt             [3] KerberosString           OPTIONAL,
+         s2kparams        [4] OCTET STRING             OPTIONAL,
+         ...
+       }
+
+       OTP-TOKENINFO ::= SEQUENCE {
+         flags            [0] OTPFlags,
+         otp-vendor       [1] UTF8String               OPTIONAL,
+         otp-challenge    [2] OCTET STRING (SIZE(1..MAX))
+                                                       OPTIONAL,
+         otp-length       [3] Int32                    OPTIONAL,
+         otp-format       [4] OTPFormat                OPTIONAL,
+         otp-tokenID      [5] OCTET STRING             OPTIONAL,
+         otp-algID        [6] AnyURI                   OPTIONAL,
+         supportedHashAlg [7] SEQUENCE OF AlgorithmIdentifier
+                                                       OPTIONAL,
+         iterationCount   [8] Int32                    OPTIONAL,
+         ...
+       }
+
+       OTPFormat ::= INTEGER {
+         decimal(0),
+         hexadecimal(1),
+         alphanumeric(2),
+         binary(3),
+         base64(4)
+       }
+
+       OTPFlags ::= KerberosFlags
+       -- reserved(0),
+       -- nextOTP(1),
+       -- combine(2),
+       -- collect-pin(3),
+       -- do-not-collect-pin(4),
+       -- must-encrypt-nonce (5),
+       -- separate-pin-required (6),
+       -- check-digit (7)
+
+       PA-OTP-REQUEST ::= SEQUENCE {
+         flags          [0]  OTPFlags,
+         nonce          [1]  OCTET STRING                OPTIONAL,
+         encData        [2]  EncryptedData,
+                            -- PA-OTP-ENC-REQUEST or PA-ENC-TS-ENC
+                            -- Key usage of KEY_USAGE_OTP_REQUEST
+         hashAlg        [3]  AlgorithmIdentifier         OPTIONAL,
+         iterationCount [4]  Int32                       OPTIONAL,
+         otp-value      [5]  OCTET STRING                OPTIONAL,
+         otp-pin        [6]  UTF8String                  OPTIONAL,
+         otp-challenge  [7]  OCTET STRING (SIZE(1..MAX)) OPTIONAL,
+         otp-time       [8]  KerberosTime                OPTIONAL,
+         otp-counter    [9]  OCTET STRING                OPTIONAL,
+         otp-format     [10] OTPFormat                   OPTIONAL,
+         otp-tokenID    [11] OCTET STRING                OPTIONAL,
+         otp-algID      [12] AnyURI                      OPTIONAL,
+         otp-vendor     [13] UTF8String                  OPTIONAL,
+         ...
+       }
+
+       PA-OTP-ENC-REQUEST ::= SEQUENCE {
+         nonce     [0] OCTET STRING,
+         ...
+       }
+
+
+       PA-OTP-PIN-CHANGE ::= SEQUENCE {
+         flags     [0] PinFlags,
+         pin       [1] UTF8String OPTIONAL,
+         minLength [2] INTEGER    OPTIONAL,
+         maxLength [3] INTEGER    OPTIONAL,
+         last-req  [4] LastReq    OPTIONAL,
+         format    [5] OTPFormat  OPTIONAL,
+         ...
+       }
+
+       PinFlags ::= KerberosFlags
+       -- reserved(0),
+       -- systemSetPin(1),
+       -- mandatory(2)
+
+       AnyURI ::= UTF8String
+          (CONSTRAINED BY {
+          -- MUST be a valid URI in accordance with IETF RFC 2396
+          })
+
+   END
diff --git a/src/tests/asn.1/pkix.asn1 b/src/tests/asn.1/pkix.asn1
new file mode 100644
index 0000000..0398188
--- /dev/null
+++ b/src/tests/asn.1/pkix.asn1
@@ -0,0 +1,654 @@
+PKIX1Explicit88 { iso(1) identified-organization(3) dod(6) internet(1)
+  security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-explicit(18) }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- EXPORTS ALL --
+
+-- IMPORTS NONE --
+
+-- UNIVERSAL Types defined in 1993 and 1998 ASN.1
+-- and required by this specification
+-- (Commented out for krb5 source tree)
+
+-- UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING
+        -- UniversalString is defined in ASN.1:1993
+
+-- BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING
+      -- BMPString is the subtype of UniversalString and models
+      -- the Basic Multilingual Plane of ISO/IEC 10646
+
+--UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING
+      -- The content of this type conforms to RFC 3629.
+
+-- PKIX specific OIDs
+
+id-pkix  OBJECT IDENTIFIER  ::=
+         { iso(1) identified-organization(3) dod(6) internet(1)
+                    security(5) mechanisms(5) pkix(7) }
+
+-- PKIX arcs
+
+id-pe OBJECT IDENTIFIER ::= { id-pkix 1 }
+        -- arc for private certificate extensions
+id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
+        -- arc for policy qualifier types
+id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+        -- arc for extended key purpose OIDS
+id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+        -- arc for access descriptors
+
+-- policyQualifierIds for Internet policy qualifiers
+
+id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+      -- OID for CPS qualifier
+id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+      -- OID for user notice qualifier
+
+-- access descriptor definitions
+
+id-ad-ocsp         OBJECT IDENTIFIER ::= { id-ad 1 }
+id-ad-caIssuers    OBJECT IDENTIFIER ::= { id-ad 2 }
+id-ad-timeStamping OBJECT IDENTIFIER ::= { id-ad 3 }
+id-ad-caRepository OBJECT IDENTIFIER ::= { id-ad 5 }
+
+-- attribute data types
+
+Attribute               ::= SEQUENCE {
+      type             AttributeType,
+      values    SET OF AttributeValue }
+            -- at least one value is required
+
+AttributeType           ::= OBJECT IDENTIFIER
+
+AttributeValue          ::= ANY -- DEFINED BY AttributeType
+
+AttributeTypeAndValue   ::= SEQUENCE {
+        type    AttributeType,
+        value   AttributeValue }
+
+-- suggested naming attributes: Definition of the following
+--   information object set may be augmented to meet local
+--   requirements.  Note that deleting members of the set may
+--   prevent interoperability with conforming implementations.
+-- presented in pairs: the AttributeType followed by the
+--   type definition for the corresponding AttributeValue
+
+-- Arc for standard naming attributes
+
+id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 }
+
+-- Naming attributes of type X520name
+
+id-at-name                AttributeType ::= { id-at 41 }
+id-at-surname             AttributeType ::= { id-at  4 }
+id-at-givenName           AttributeType ::= { id-at 42 }
+id-at-initials            AttributeType ::= { id-at 43 }
+id-at-generationQualifier AttributeType ::= { id-at 44 }
+
+-- Naming attributes of type X520Name:
+--   X520name ::= DirectoryString (SIZE (1..ub-name))
+--
+-- Expanded to avoid parameterized type:
+X520name ::= CHOICE {
+      teletexString     TeletexString   (SIZE (1..ub-name)),
+      printableString   PrintableString (SIZE (1..ub-name)),
+      universalString   UniversalString (SIZE (1..ub-name)),
+      utf8String        UTF8String      (SIZE (1..ub-name)),
+      bmpString         BMPString       (SIZE (1..ub-name)) }
+
+-- Naming attributes of type X520CommonName
+
+id-at-commonName        AttributeType ::= { id-at 3 }
+
+-- Naming attributes of type X520CommonName:
+--   X520CommonName ::= DirectoryName (SIZE (1..ub-common-name))
+--
+-- Expanded to avoid parameterized type:
+X520CommonName ::= CHOICE {
+      teletexString     TeletexString   (SIZE (1..ub-common-name)),
+      printableString   PrintableString (SIZE (1..ub-common-name)),
+      universalString   UniversalString (SIZE (1..ub-common-name)),
+      utf8String        UTF8String      (SIZE (1..ub-common-name)),
+      bmpString         BMPString       (SIZE (1..ub-common-name)) }
+
+-- Naming attributes of type X520LocalityName
+
+id-at-localityName      AttributeType ::= { id-at 7 }
+
+-- Naming attributes of type X520LocalityName:
+--   X520LocalityName ::= DirectoryName (SIZE (1..ub-locality-name))
+--
+-- Expanded to avoid parameterized type:
+X520LocalityName ::= CHOICE {
+      teletexString     TeletexString   (SIZE (1..ub-locality-name)),
+      printableString   PrintableString (SIZE (1..ub-locality-name)),
+      universalString   UniversalString (SIZE (1..ub-locality-name)),
+      utf8String        UTF8String      (SIZE (1..ub-locality-name)),
+      bmpString         BMPString       (SIZE (1..ub-locality-name)) }
+
+-- Naming attributes of type X520StateOrProvinceName
+
+id-at-stateOrProvinceName AttributeType ::= { id-at 8 }
+
+-- Naming attributes of type X520StateOrProvinceName:
+--   X520StateOrProvinceName ::= DirectoryName (SIZE (1..ub-state-name))
+--
+-- Expanded to avoid parameterized type:
+X520StateOrProvinceName ::= CHOICE {
+      teletexString     TeletexString   (SIZE (1..ub-state-name)),
+      printableString   PrintableString (SIZE (1..ub-state-name)),
+      universalString   UniversalString (SIZE (1..ub-state-name)),
+      utf8String        UTF8String      (SIZE (1..ub-state-name)),
+      bmpString         BMPString       (SIZE (1..ub-state-name)) }
+
+-- Naming attributes of type X520OrganizationName
+
+id-at-organizationName  AttributeType ::= { id-at 10 }
+
+-- Naming attributes of type X520OrganizationName:
+--   X520OrganizationName ::=
+--          DirectoryName (SIZE (1..ub-organization-name))
+--
+-- Expanded to avoid parameterized type:
+X520OrganizationName ::= CHOICE {
+      teletexString     TeletexString
+                          (SIZE (1..ub-organization-name)),
+      printableString   PrintableString
+                          (SIZE (1..ub-organization-name)),
+      universalString   UniversalString
+                          (SIZE (1..ub-organization-name)),
+      utf8String        UTF8String
+                          (SIZE (1..ub-organization-name)),
+      bmpString         BMPString
+                          (SIZE (1..ub-organization-name))  }
+
+-- Naming attributes of type X520OrganizationalUnitName
+
+id-at-organizationalUnitName AttributeType ::= { id-at 11 }
+
+-- Naming attributes of type X520OrganizationalUnitName:
+--   X520OrganizationalUnitName ::=
+--          DirectoryName (SIZE (1..ub-organizational-unit-name))
+--
+-- Expanded to avoid parameterized type:
+X520OrganizationalUnitName ::= CHOICE {
+      teletexString     TeletexString
+                          (SIZE (1..ub-organizational-unit-name)),
+      printableString   PrintableString
+                          (SIZE (1..ub-organizational-unit-name)),
+      universalString   UniversalString
+                          (SIZE (1..ub-organizational-unit-name)),
+      utf8String        UTF8String
+                          (SIZE (1..ub-organizational-unit-name)),
+      bmpString         BMPString
+                          (SIZE (1..ub-organizational-unit-name)) }
+
+-- Naming attributes of type X520Title
+
+id-at-title             AttributeType ::= { id-at 12 }
+
+-- Naming attributes of type X520Title:
+--   X520Title ::= DirectoryName (SIZE (1..ub-title))
+--
+-- Expanded to avoid parameterized type:
+X520Title ::= CHOICE {
+      teletexString     TeletexString   (SIZE (1..ub-title)),
+      printableString   PrintableString (SIZE (1..ub-title)),
+      universalString   UniversalString (SIZE (1..ub-title)),
+      utf8String        UTF8String      (SIZE (1..ub-title)),
+      bmpString         BMPString       (SIZE (1..ub-title)) }
+
+-- Naming attributes of type X520dnQualifier
+
+id-at-dnQualifier       AttributeType ::= { id-at 46 }
+
+X520dnQualifier ::=     PrintableString
+
+-- Naming attributes of type X520countryName (digraph from IS 3166)
+
+id-at-countryName       AttributeType ::= { id-at 6 }
+
+X520countryName ::=     PrintableString (SIZE (2))
+
+-- Naming attributes of type X520SerialNumber
+
+id-at-serialNumber      AttributeType ::= { id-at 5 }
+
+X520SerialNumber ::=    PrintableString (SIZE (1..ub-serial-number))
+
+-- Naming attributes of type X520Pseudonym
+
+id-at-pseudonym         AttributeType ::= { id-at 65 }
+
+-- Naming attributes of type X520Pseudonym:
+--   X520Pseudonym ::= DirectoryName (SIZE (1..ub-pseudonym))
+--
+-- Expanded to avoid parameterized type:
+X520Pseudonym ::= CHOICE {
+   teletexString     TeletexString   (SIZE (1..ub-pseudonym)),
+   printableString   PrintableString (SIZE (1..ub-pseudonym)),
+   universalString   UniversalString (SIZE (1..ub-pseudonym)),
+   utf8String        UTF8String      (SIZE (1..ub-pseudonym)),
+   bmpString         BMPString       (SIZE (1..ub-pseudonym)) }
+
+-- Naming attributes of type DomainComponent (from RFC 4519)
+
+id-domainComponent   AttributeType ::= { 0 9 2342 19200300 100 1 25 }
+
+DomainComponent ::=  IA5String
+
+-- Legacy attributes
+
+pkcs-9 OBJECT IDENTIFIER ::=
+       { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+
+id-emailAddress      AttributeType ::= { pkcs-9 1 }
+
+EmailAddress ::=     IA5String (SIZE (1..ub-emailaddress-length))
+
+-- naming data types --
+
+Name ::= CHOICE { -- only one possibility for now --
+      rdnSequence  RDNSequence }
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+DistinguishedName ::=   RDNSequence
+
+RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+
+-- Directory string type --
+
+DirectoryString ::= CHOICE {
+      teletexString       TeletexString   (SIZE (1..MAX)),
+      printableString     PrintableString (SIZE (1..MAX)),
+      universalString     UniversalString (SIZE (1..MAX)),
+      utf8String          UTF8String      (SIZE (1..MAX)),
+      bmpString           BMPString       (SIZE (1..MAX)) }
+
+-- certificate and CRL specific structures begin here
+
+Certificate  ::=  SEQUENCE  {
+     tbsCertificate       TBSCertificate,
+     signatureAlgorithm   AlgorithmIdentifier,
+     signature            BIT STRING  }
+
+TBSCertificate  ::=  SEQUENCE  {
+     version         [0]  Version DEFAULT v1,
+     serialNumber         CertificateSerialNumber,
+     signature            AlgorithmIdentifier,
+     issuer               Name,
+     validity             Validity,
+     subject              Name,
+     subjectPublicKeyInfo SubjectPublicKeyInfo,
+     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
+                          -- If present, version MUST be v2 or v3
+     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
+                          -- If present, version MUST be v2 or v3
+     extensions      [3]  Extensions OPTIONAL
+                          -- If present, version MUST be v3 --  }
+
+Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+
+CertificateSerialNumber  ::=  INTEGER
+
+Validity ::= SEQUENCE {
+     notBefore      Time,
+     notAfter       Time  }
+
+Time ::= CHOICE {
+     utcTime        UTCTime,
+     generalTime    GeneralizedTime }
+
+UniqueIdentifier  ::=  BIT STRING
+
+SubjectPublicKeyInfo  ::=  SEQUENCE  {
+     algorithm            AlgorithmIdentifier,
+     subjectPublicKey     BIT STRING  }
+
+Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+
+Extension  ::=  SEQUENCE  {
+     extnID      OBJECT IDENTIFIER,
+     critical    BOOLEAN DEFAULT FALSE,
+     extnValue   OCTET STRING
+                 -- contains the DER encoding of an ASN.1 value
+                 -- corresponding to the extension type identified
+                 -- by extnID
+     }
+
+-- CRL structures
+
+CertificateList  ::=  SEQUENCE  {
+     tbsCertList          TBSCertList,
+     signatureAlgorithm   AlgorithmIdentifier,
+     signature            BIT STRING  }
+
+TBSCertList  ::=  SEQUENCE  {
+     version                 Version OPTIONAL,
+                                   -- if present, MUST be v2
+     signature               AlgorithmIdentifier,
+     issuer                  Name,
+     thisUpdate              Time,
+     nextUpdate              Time OPTIONAL,
+     revokedCertificates     SEQUENCE OF SEQUENCE  {
+          userCertificate         CertificateSerialNumber,
+          revocationDate          Time,
+          crlEntryExtensions      Extensions OPTIONAL
+                                   -- if present, version MUST be v2
+                               }  OPTIONAL,
+     crlExtensions           [0] Extensions OPTIONAL }
+                                   -- if present, version MUST be v2
+
+-- Version, Time, CertificateSerialNumber, and Extensions were
+-- defined earlier for use in the certificate structure
+
+AlgorithmIdentifier  ::=  SEQUENCE  {
+     algorithm               OBJECT IDENTIFIER,
+     parameters              ANY DEFINED BY algorithm OPTIONAL  }
+                                -- contains a value of the type
+                                -- registered for use with the
+                                -- algorithm object identifier value
+
+-- X.400 address syntax starts here
+
+ORAddress ::= SEQUENCE {
+   built-in-standard-attributes BuiltInStandardAttributes,
+   built-in-domain-defined-attributes
+                   BuiltInDomainDefinedAttributes OPTIONAL,
+   -- see also teletex-domain-defined-attributes
+   extension-attributes ExtensionAttributes OPTIONAL }
+
+-- Built-in Standard Attributes
+
+BuiltInStandardAttributes ::= SEQUENCE {
+   country-name                  CountryName OPTIONAL,
+   administration-domain-name    AdministrationDomainName OPTIONAL,
+   network-address           [0] IMPLICIT NetworkAddress OPTIONAL,
+     -- see also extended-network-address
+   terminal-identifier       [1] IMPLICIT TerminalIdentifier OPTIONAL,
+   private-domain-name       [2] PrivateDomainName OPTIONAL,
+   organization-name         [3] IMPLICIT OrganizationName OPTIONAL,
+     -- see also teletex-organization-name
+   numeric-user-identifier   [4] IMPLICIT NumericUserIdentifier
+                                 OPTIONAL,
+   personal-name             [5] IMPLICIT PersonalName OPTIONAL,
+     -- see also teletex-personal-name
+   organizational-unit-names [6] IMPLICIT OrganizationalUnitNames
+                                 OPTIONAL }
+     -- see also teletex-organizational-unit-names
+
+CountryName ::= [APPLICATION 1] CHOICE {
+   x121-dcc-code         NumericString
+                           (SIZE (ub-country-name-numeric-length)),
+   iso-3166-alpha2-code  PrintableString
+                           (SIZE (ub-country-name-alpha-length)) }
+
+AdministrationDomainName ::= [APPLICATION 2] CHOICE {
+   numeric   NumericString   (SIZE (0..ub-domain-name-length)),
+   printable PrintableString (SIZE (0..ub-domain-name-length)) }
+
+NetworkAddress ::= X121Address  -- see also extended-network-address
+
+X121Address ::= NumericString (SIZE (1..ub-x121-address-length))
+
+TerminalIdentifier ::= PrintableString (SIZE (1..ub-terminal-id-length))
+
+PrivateDomainName ::= CHOICE {
+   numeric   NumericString   (SIZE (1..ub-domain-name-length)),
+   printable PrintableString (SIZE (1..ub-domain-name-length)) }
+
+OrganizationName ::= PrintableString
+                            (SIZE (1..ub-organization-name-length))
+  -- see also teletex-organization-name
+
+NumericUserIdentifier ::= NumericString
+                            (SIZE (1..ub-numeric-user-id-length))
+
+PersonalName ::= SET {
+   surname     [0] IMPLICIT PrintableString
+                    (SIZE (1..ub-surname-length)),
+   given-name  [1] IMPLICIT PrintableString
+                    (SIZE (1..ub-given-name-length)) OPTIONAL,
+   initials    [2] IMPLICIT PrintableString
+                    (SIZE (1..ub-initials-length)) OPTIONAL,
+   generation-qualifier [3] IMPLICIT PrintableString
+                    (SIZE (1..ub-generation-qualifier-length))
+                    OPTIONAL }
+  -- see also teletex-personal-name
+
+OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units)
+                             OF OrganizationalUnitName
+  -- see also teletex-organizational-unit-names
+
+OrganizationalUnitName ::= PrintableString (SIZE
+                    (1..ub-organizational-unit-name-length))
+
+-- Built-in Domain-defined Attributes
+
+BuiltInDomainDefinedAttributes ::= SEQUENCE SIZE
+                    (1..ub-domain-defined-attributes) OF
+                    BuiltInDomainDefinedAttribute
+
+BuiltInDomainDefinedAttribute ::= SEQUENCE {
+   type PrintableString (SIZE
+                   (1..ub-domain-defined-attribute-type-length)),
+   value PrintableString (SIZE
+                   (1..ub-domain-defined-attribute-value-length)) }
+
+-- Extension Attributes
+
+ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) OF
+               ExtensionAttribute
+
+ExtensionAttribute ::=  SEQUENCE {
+   extension-attribute-type [0] IMPLICIT INTEGER
+                   (0..ub-extension-attributes),
+   extension-attribute-value [1]
+                   ANY DEFINED BY extension-attribute-type }
+
+-- Extension types and attribute values
+
+common-name INTEGER ::= 1
+
+CommonName ::= PrintableString (SIZE (1..ub-common-name-length))
+
+teletex-common-name INTEGER ::= 2
+
+TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length))
+
+teletex-organization-name INTEGER ::= 3
+
+TeletexOrganizationName ::=
+                TeletexString (SIZE (1..ub-organization-name-length))
+
+teletex-personal-name INTEGER ::= 4
+
+TeletexPersonalName ::= SET {
+   surname     [0] IMPLICIT TeletexString
+                    (SIZE (1..ub-surname-length)),
+   given-name  [1] IMPLICIT TeletexString
+                    (SIZE (1..ub-given-name-length)) OPTIONAL,
+   initials    [2] IMPLICIT TeletexString
+                    (SIZE (1..ub-initials-length)) OPTIONAL,
+   generation-qualifier [3] IMPLICIT TeletexString
+                    (SIZE (1..ub-generation-qualifier-length))
+                    OPTIONAL }
+
+teletex-organizational-unit-names INTEGER ::= 5
+
+TeletexOrganizationalUnitNames ::= SEQUENCE SIZE
+      (1..ub-organizational-units) OF TeletexOrganizationalUnitName
+
+TeletexOrganizationalUnitName ::= TeletexString
+                  (SIZE (1..ub-organizational-unit-name-length))
+
+pds-name INTEGER ::= 7
+
+PDSName ::= PrintableString (SIZE (1..ub-pds-name-length))
+
+physical-delivery-country-name INTEGER ::= 8
+
+PhysicalDeliveryCountryName ::= CHOICE {
+   x121-dcc-code NumericString (SIZE (ub-country-name-numeric-length)),
+   iso-3166-alpha2-code PrintableString
+                               (SIZE (ub-country-name-alpha-length)) }
+
+postal-code INTEGER ::= 9
+
+PostalCode ::= CHOICE {
+   numeric-code   NumericString (SIZE (1..ub-postal-code-length)),
+   printable-code PrintableString (SIZE (1..ub-postal-code-length)) }
+
+physical-delivery-office-name INTEGER ::= 10
+PhysicalDeliveryOfficeName ::= PDSParameter
+
+physical-delivery-office-number INTEGER ::= 11
+
+PhysicalDeliveryOfficeNumber ::= PDSParameter
+
+extension-OR-address-components INTEGER ::= 12
+
+ExtensionORAddressComponents ::= PDSParameter
+
+physical-delivery-personal-name INTEGER ::= 13
+
+PhysicalDeliveryPersonalName ::= PDSParameter
+
+physical-delivery-organization-name INTEGER ::= 14
+
+PhysicalDeliveryOrganizationName ::= PDSParameter
+
+extension-physical-delivery-address-components INTEGER ::= 15
+
+ExtensionPhysicalDeliveryAddressComponents ::= PDSParameter
+
+unformatted-postal-address INTEGER ::= 16
+
+UnformattedPostalAddress ::= SET {
+   printable-address SEQUENCE SIZE (1..ub-pds-physical-address-lines)
+        OF PrintableString (SIZE (1..ub-pds-parameter-length)) OPTIONAL,
+   teletex-string TeletexString
+        (SIZE (1..ub-unformatted-address-length)) OPTIONAL }
+
+street-address INTEGER ::= 17
+
+StreetAddress ::= PDSParameter
+
+post-office-box-address INTEGER ::= 18
+
+PostOfficeBoxAddress ::= PDSParameter
+
+poste-restante-address INTEGER ::= 19
+
+PosteRestanteAddress ::= PDSParameter
+
+unique-postal-name INTEGER ::= 20
+
+UniquePostalName ::= PDSParameter
+
+local-postal-attributes INTEGER ::= 21
+
+LocalPostalAttributes ::= PDSParameter
+
+PDSParameter ::= SET {
+   printable-string PrintableString
+                (SIZE(1..ub-pds-parameter-length)) OPTIONAL,
+   teletex-string TeletexString
+                (SIZE(1..ub-pds-parameter-length)) OPTIONAL }
+
+extended-network-address INTEGER ::= 22
+
+ExtendedNetworkAddress ::= CHOICE {
+   e163-4-address SEQUENCE {
+      number      [0] IMPLICIT NumericString
+                       (SIZE (1..ub-e163-4-number-length)),
+      sub-address [1] IMPLICIT NumericString
+                       (SIZE (1..ub-e163-4-sub-address-length))
+                       OPTIONAL },
+   psap-address   [0] IMPLICIT PresentationAddress }
+
+PresentationAddress ::= SEQUENCE {
+    pSelector     [0] EXPLICIT OCTET STRING OPTIONAL,
+    sSelector     [1] EXPLICIT OCTET STRING OPTIONAL,
+    tSelector     [2] EXPLICIT OCTET STRING OPTIONAL,
+    nAddresses    [3] EXPLICIT SET SIZE (1..MAX) OF OCTET STRING }
+
+terminal-type  INTEGER ::= 23
+
+TerminalType ::= INTEGER {
+   telex        (3),
+   teletex      (4),
+   g3-facsimile (5),
+   g4-facsimile (6),
+   ia5-terminal (7),
+   videotex     (8) } (0..ub-integer-options)
+
+-- Extension Domain-defined Attributes
+
+teletex-domain-defined-attributes INTEGER ::= 6
+
+TeletexDomainDefinedAttributes ::= SEQUENCE SIZE
+   (1..ub-domain-defined-attributes) OF TeletexDomainDefinedAttribute
+
+TeletexDomainDefinedAttribute ::= SEQUENCE {
+        type TeletexString
+               (SIZE (1..ub-domain-defined-attribute-type-length)),
+        value TeletexString
+               (SIZE (1..ub-domain-defined-attribute-value-length)) }
+
+--  specifications of Upper Bounds MUST be regarded as mandatory
+--  from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
+--  Upper Bounds
+
+-- Upper Bounds
+ub-name INTEGER ::= 32768
+ub-common-name INTEGER ::= 64
+ub-locality-name INTEGER ::= 128
+ub-state-name INTEGER ::= 128
+ub-organization-name INTEGER ::= 64
+ub-organizational-unit-name INTEGER ::= 64
+ub-title INTEGER ::= 64
+ub-serial-number INTEGER ::= 64
+ub-match INTEGER ::= 128
+ub-emailaddress-length INTEGER ::= 255
+ub-common-name-length INTEGER ::= 64
+ub-country-name-alpha-length INTEGER ::= 2
+ub-country-name-numeric-length INTEGER ::= 3
+ub-domain-defined-attributes INTEGER ::= 4
+ub-domain-defined-attribute-type-length INTEGER ::= 8
+ub-domain-defined-attribute-value-length INTEGER ::= 128
+ub-domain-name-length INTEGER ::= 16
+ub-extension-attributes INTEGER ::= 256
+ub-e163-4-number-length INTEGER ::= 15
+ub-e163-4-sub-address-length INTEGER ::= 40
+ub-generation-qualifier-length INTEGER ::= 3
+ub-given-name-length INTEGER ::= 16
+ub-initials-length INTEGER ::= 5
+ub-integer-options INTEGER ::= 256
+ub-numeric-user-id-length INTEGER ::= 32
+ub-organization-name-length INTEGER ::= 64
+ub-organizational-unit-name-length INTEGER ::= 32
+ub-organizational-units INTEGER ::= 4
+ub-pds-name-length INTEGER ::= 16
+ub-pds-parameter-length INTEGER ::= 30
+ub-pds-physical-address-lines INTEGER ::= 6
+ub-postal-code-length INTEGER ::= 16
+ub-pseudonym INTEGER ::= 128
+ub-surname-length INTEGER ::= 40
+ub-terminal-id-length INTEGER ::= 24
+ub-unformatted-address-length INTEGER ::= 180
+ub-x121-address-length INTEGER ::= 16
+
+-- Note - upper bounds on string types, such as TeletexString, are
+-- measured in characters.  Excepting PrintableString or IA5String, a
+-- significantly greater number of octets will be required to hold
+-- such a value.  As a minimum, 16 octets, or twice the specified
+-- upper bound, whichever is the larger, should be allowed for
+-- TeletexString.  For UTF8String or UniversalString at least four
+-- times the upper bound should be allowed.
+
+END
diff --git a/src/tests/asn.1/reference_encode.out b/src/tests/asn.1/reference_encode.out
index 1a9c3d6..315e25b 100644
--- a/src/tests/asn.1/reference_encode.out
+++ b/src/tests/asn.1/reference_encode.out
@@ -61,3 +61,10 @@ encode_krb5_iakerb_header: 30 18 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0A 04 08
 encode_krb5_iakerb_finished: 30 11 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
 encode_krb5_fast_response: 30 81 9F A0 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 5B 30 59 A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 03 02 01 2A
 encode_krb5_pa_fx_fast_reply: A0 29 30 27 A0 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_otp_tokeninfo(optionals NULL): 30 07 80 05 00 00 00 00 00
+encode_krb5_otp_tokeninfo: 30 72 80 05 00 77 00 00 00 81 0B 45 78 61 6D 70 6C 65 63 6F 72 70 82 05 68 61 72 6B 21 83 01 0A 84 01 02 85 09 79 6F 75 72 74 6F 6B 65 6E 86 28 75 72 6E 3A 69 65 74 66 3A 70 61 72 61 6D 73 3A 78 6D 6C 3A 6E 73 3A 6B 65 79 70 72 6F 76 3A 70 73 6B 63 3A 68 6F 74 70 A7 16 30 0B 06 09 60 86 48 01 65 03 04 02 01 30 07 06 05 2B 0E 03 02 1A 88 02 03 E8
+encode_krb5_pa_otp_challenge(optionals NULL): 30 15 80 08 6D 69 6E 6E 6F 6E 63 65 A2 09 30 07 80 05 00 00 00 00 00
+encode_krb5_pa_otp_challenge: 30 81 A5 80 08 6D 61 78 6E 6F 6E 63 65 81 0B 74 65 73 74 73 65 72 76 69 63 65 A2 7D 30 07 80 05 00 00 00 00 00 30 72 80 05 00 77 00 00 00 81 0B 45 78 61 6D 70 6C 65 63 6F 72 70 82 05 68 61 72 6B 21 83 01 0A 84 01 02 85 09 79 6F 75 72 74 6F 6B 65 6E 86 28 75 72 6E 3A 69 65 74 66 3A 70 61 72 61 6D 73 3A 78 6D 6C 3A 6E 73 3A 6B 65 79 70 72 6F 76 3A 70 73 6B 63 3A 68 6F 74 70 A7 16 30 0B 06 09 60 86 48 01 65 03 04 02 01 30 07 06 05 2B 0E 03 02 1A 88 02 03 E8 83 07 6B 65 79 73 61 6C 74 84 04 31 32 33 34
+encode_krb5_pa_otp_req(optionals NULL): 30 2C 80 05 00 00 00 00 00 A2 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_pa_otp_req: 30 81 B9 80 05 00 60 00 00 00 81 05 6E 6F 6E 63 65 A2 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A3 0B 06 09 60 86 48 01 65 03 04 02 01 84 02 03 E8 85 05 66 72 6F 67 73 86 0A 6D 79 66 69 72 73 74 70 69 6E 87 05 68 61 72 6B 21 88 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 89 03 33 34 36 8A 01 02 8B 09 79 6F 75 72 74 6F 6B 65 6E 8C 28 75 72 6E 3A 69 65 74 66 3A 70 61 72 61 6D 73 3A 78 6D 6C 3A 6E 73 3A 6B 65 79 70 72 6F 76 3A 70 73 6B 63 3A 68 6F 74 70 8D 0B 45 78 61 6D 70 6C 65 63 6F 72 70
+encode_krb5_pa_otp_enc_req: 30 0A 80 08 6B 72 62 35 64 61 74 61
diff --git a/src/tests/asn.1/trval_reference.out b/src/tests/asn.1/trval_reference.out
index f1fec5f..461021e 100644
--- a/src/tests/asn.1/trval_reference.out
+++ b/src/tests/asn.1/trval_reference.out
@@ -1348,3 +1348,133 @@ encode_krb5_pa_fx_fast_reply:
 .  .  .  [0] [Integer] 0
 .  .  .  [1] [Integer] 5
 .  .  .  [2] [Octet String] "krbASN.1 test message"
+
+encode_krb5_otp_tokeninfo(optionals NULL):
+
+[Sequence/Sequence Of]
+.  [0] <5>
+      00 00 00 00 00                                      .....
+
+encode_krb5_otp_tokeninfo:
+
+[Sequence/Sequence Of]
+.  [0] <5>
+      00 77 00 00 00                                      .w...
+.  [1] <11>
+      45 78 61 6d 70 6c 65 63 6f 72 70                    Examplecorp
+.  [2] <5>
+      68 61 72 6b 21                                      hark!
+.  [3] 0x0 (10 unused bits)
+.  [4] <1>
+      02                                                  .
+.  [5] <9>
+      79 6f 75 72 74 6f 6b 65 6e                          yourtoken
+.  [6] <40>
+      75 72 6e 3a 69 65 74 66 3a 70 61 72 61 6d 73 3a     urn:ietf:params:
+      78 6d 6c 3a 6e 73 3a 6b 65 79 70 72 6f 76 3a 70     xml:ns:keyprov:p
+      73 6b 63 3a 68 6f 74 70                             skc:hotp
+.  [7] [Sequence/Sequence Of]
+.  .  [Object Identifier] <9>
+         60 86 48 01 65 03 04 02 01                       `.H.e....
+.  [Sequence/Sequence Of]
+.  .  [Object Identifier] <5>
+         2b 0e 03 02 1a                                   +....
+.  [8] <2>
+      03 e8                                               ..
+
+encode_krb5_pa_otp_challenge(optionals NULL):
+
+[Sequence/Sequence Of]
+.  [0] <8>
+      6d 69 6e 6e 6f 6e 63 65                             minnonce
+.  [2] [Sequence/Sequence Of]
+.  .  [0] <5>
+         00 00 00 00 00                                   .....
+
+encode_krb5_pa_otp_challenge:
+
+[Sequence/Sequence Of]
+.  [0] <8>
+      6d 61 78 6e 6f 6e 63 65                             maxnonce
+.  [1] <11>
+      74 65 73 74 73 65 72 76 69 63 65                    testservice
+.  [2] [Sequence/Sequence Of]
+.  .  [0] <5>
+         00 00 00 00 00                                   .....
+.  [Sequence/Sequence Of]
+.  .  [0] <5>
+         00 77 00 00 00                                   .w...
+.  .  [1] <11>
+         45 78 61 6d 70 6c 65 63 6f 72 70                 Examplecorp
+.  .  [2] <5>
+         68 61 72 6b 21                                   hark!
+.  .  [3] 0x0 (10 unused bits)
+.  .  [4] <1>
+         02                                               .
+.  .  [5] <9>
+         79 6f 75 72 74 6f 6b 65 6e                       yourtoken
+.  .  [6] <40>
+         75 72 6e 3a 69 65 74 66 3a 70 61 72 61 6d 73     urn:ietf:params
+         3a 78 6d 6c 3a 6e 73 3a 6b 65 79 70 72 6f 76     :xml:ns:keyprov
+         3a 70 73 6b 63 3a 68 6f 74 70                    :pskc:hotp
+.  .  [7] [Sequence/Sequence Of]
+.  .  .  [Object Identifier] <9>
+            60 86 48 01 65 03 04 02 01                       `.H.e....
+.  .  [Sequence/Sequence Of]
+.  .  .  [Object Identifier] <5>
+            2b 0e 03 02 1a                                   +....
+.  .  [8] <2>
+         03 e8                                            ..
+.  [3] <7>
+      6b 65 79 73 61 6c 74                                keysalt
+.  [4] "1234"
+
+encode_krb5_pa_otp_req(optionals NULL):
+
+[Sequence/Sequence Of]
+.  [0] <5>
+      00 00 00 00 00                                      .....
+.  [2] [0] [Integer] 0
+.  [1] [Integer] 5
+.  [2] [Octet String] "krbASN.1 test message"
+
+encode_krb5_pa_otp_req:
+
+[Sequence/Sequence Of]
+.  [0] <5>
+      00 60 00 00 00                                      .`...
+.  [1] <5>
+      6e 6f 6e 63 65                                      nonce
+.  [2] [0] [Integer] 0
+.  [1] [Integer] 5
+.  [2] [Octet String] "krbASN.1 test message"
+.  [3] [Object Identifier] <9>
+      60 86 48 01 65 03 04 02 01                          `.H.e....
+.  [4] <2>
+      03 e8                                               ..
+.  [5] <5>
+      66 72 6f 67 73                                      frogs
+.  [6] <10>
+      6d 79 66 69 72 73 74 70 69 6e                       myfirstpin
+.  [7] <5>
+      68 61 72 6b 21                                      hark!
+.  [8] <15>
+      31 39 39 34 30 36 31 30 30 36 30 33 31 37 5a        19940610060317Z
+.  [9] <3>
+      33 34 36                                            346
+.  [10] <1>
+      02                                                  .
+.  [11] <9>
+      79 6f 75 72 74 6f 6b 65 6e                          yourtoken
+.  [12] <40>
+      75 72 6e 3a 69 65 74 66 3a 70 61 72 61 6d 73 3a     urn:ietf:params:
+      78 6d 6c 3a 6e 73 3a 6b 65 79 70 72 6f 76 3a 70     xml:ns:keyprov:p
+      73 6b 63 3a 68 6f 74 70                             skc:hotp
+.  [13] <11>
+      45 78 61 6d 70 6c 65 63 6f 72 70                    Examplecorp
+
+encode_krb5_pa_otp_enc_req:
+
+[Sequence/Sequence Of]
+.  [0] <8>
+      6b 72 62 35 64 61 74 61                             krb5data


More information about the cvs-krb5 mailing list