From 7f1cfb0396b9976d019c2f8dc29a7c94b7e6b412 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Thu, 31 Dec 2020 15:59:05 -0600 Subject: [PATCH] asn1: Add sample from X.690 Appendix A This helped find a bug fixed in the preceding commit. This also depends on the earlier fixes to IMPLICT tagging support, thus implementing a test of that using a test vector from a standard. --- lib/asn1/Makefile.am | 14 +++- lib/asn1/NTMakefile | 131 +++++++++++++++++-------------- lib/asn1/check-gen.c | 66 ++++++++++++++++ lib/asn1/libasn1-exports.def | 25 ++++++ lib/asn1/x690sample.asn1 | 146 +++++++++++++++++++++++++++++++++++ 5 files changed, 322 insertions(+), 60 deletions(-) create mode 100644 lib/asn1/x690sample.asn1 diff --git a/lib/asn1/Makefile.am b/lib/asn1/Makefile.am index cb529b8ec..10ec6a35e 100644 --- a/lib/asn1/Makefile.am +++ b/lib/asn1/Makefile.am @@ -35,7 +35,8 @@ BUILT_SOURCES = \ $(gen_files_pkcs10:.x=.c) \ $(gen_files_pkcs12:.x=.c) \ $(gen_files_digest:.x=.c) \ - $(gen_files_kx509:.x=.c) + $(gen_files_kx509:.x=.c) \ + $(gen_files_x690sample:.x=.c) gen_files_krb5 = asn1_krb5_asn1.x gen_files_cms = asn1_cms_asn1.x @@ -54,7 +55,7 @@ gen_files_test_template = test_template_asn1-template.x gen_files_test = asn1_test_asn1.x gen_files_digest = asn1_digest_asn1.x gen_files_kx509 = asn1_kx509_asn1.x -gen_files_tcg = asn1_tcg_asn1.x +gen_files_x690sample = asn1_x690sample_asn1.x oid_resolution.lo: $(BUILT_SOURCES) @@ -159,6 +160,7 @@ CLEANFILES = \ $(gen_files_pkcs12) \ $(gen_files_digest) \ $(gen_files_kx509) \ + $(gen_files_x690sample) \ $(gen_files_test) \ $(gen_files_test_template) \ $(nodist_check_gen_SOURCES) \ @@ -179,6 +181,7 @@ CLEANFILES = \ pkcs12_asn1_files pkcs12_asn1*.h* pkcs12_asn1*.x \ digest_asn1_files digest_asn1*.h* digest_asn1*.x \ kx509_asn1_files kx509_asn1*.h* kx509_asn1*.x \ + x690sample_asn1_files x690sample_asn1*.h* x690sample_asn1*.x \ test_asn1_files test_asn1*.h* test_asn1*.x \ test_template_asn1* \ asn1_*.x @@ -203,6 +206,7 @@ nodist_include_HEADERS += pkcs10_asn1.h nodist_include_HEADERS += pkcs12_asn1.h nodist_include_HEADERS += digest_asn1.h nodist_include_HEADERS += kx509_asn1.h +nodist_include_HEADERS += x690sample_asn1.h priv_headers = krb5_asn1-priv.h priv_headers += pkinit_asn1-priv.h @@ -219,6 +223,7 @@ priv_headers += pkcs10_asn1-priv.h priv_headers += pkcs12_asn1-priv.h priv_headers += digest_asn1-priv.h priv_headers += kx509_asn1-priv.h +priv_headers += x690sample_asn1-priv.h priv_headers += test_template_asn1.h test_template_asn1-priv.h priv_headers += test_asn1.h test_asn1-priv.h @@ -248,6 +253,7 @@ $(gen_files_rfc4108) rfc4108_asn1.hx rfc4108_asn1-priv.hx: rfc4108_asn1_files $(gen_files_tcg) tcg_asn1.hx tcg_asn1-priv.hx: tcg_asn1_files $(gen_files_cms) cms_asn1.hx cms_asn1-priv.hx: cms_asn1_files $(gen_files_crmf) crmf_asn1.hx crmf_asn1-priv.hx: crmf_asn1_files +$(gen_files_x690sample) x690sample_asn1.hx x690sample_asn1-priv.hx: x690sample_asn1_files $(gen_files_test) test_asn1.hx test_asn1-priv.hx: test_asn1_files $(gen_files_test_template) test_template_asn1.hx test_template_asn1-priv.hx: test_template_asn1_files @@ -296,6 +302,9 @@ digest_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 kx509_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 $(ASN1_COMPILE) --one-code-file $(srcdir)/kx509.asn1 kx509_asn1 || (rm -f kx509_asn1_files ; exit 1) +x690sample_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 + $(ASN1_COMPILE) --one-code-file $(srcdir)/x690sample.asn1 x690sample_asn1 || (rm -f x690sample_asn1_files ; exit 1) + test_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 $(ASN1_COMPILE) --template --sequence=TESTSeqOf $(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1) @@ -329,6 +338,7 @@ EXTRA_DIST = \ rfc4108.asn1 \ tcg.asn1 \ setchgpw2.asn1 \ + x690sample.asn1 \ test.asn1 \ test.gen \ version-script.map diff --git a/lib/asn1/NTMakefile b/lib/asn1/NTMakefile index 4fae2453e..9efe2325b 100644 --- a/lib/asn1/NTMakefile +++ b/lib/asn1/NTMakefile @@ -67,6 +67,8 @@ gen_files_digest = $(OBJ)\asn1_digest_asn1.x gen_files_kx509 = $(OBJ)\asn1_kx509_asn1.x +gen_files_x690sample = $(OBJ)\asn1_x690sample_asn1.x + ASN1_BINARIES = \ $(LIBEXECDIR)\asn1_compile.exe @@ -112,31 +114,32 @@ $(BINDIR)\asn1_gen.exe: $(OBJ)\asn1_gen.obj $(LIBHEIMDAL) $(EXEPREP) LIBASN1_OBJS= \ - $(OBJ)\der.obj \ - $(OBJ)\der_get.obj \ - $(OBJ)\der_put.obj \ - $(OBJ)\der_free.obj \ - $(OBJ)\der_length.obj \ - $(OBJ)\der_copy.obj \ - $(OBJ)\der_cmp.obj \ - $(OBJ)\der_format.obj \ - $(OBJ)\extra.obj \ - $(OBJ)\timegm.obj \ - $(gen_files_rfc2459:.x=.obj) \ - $(gen_files_rfc4043:.x=.obj) \ - $(gen_files_rfc4108:.x=.obj) \ - $(gen_files_tcg:.x=.obj) \ - $(gen_files_cms:.x=.obj) \ - $(gen_files_crmf:.x=.obj) \ - $(gen_files_krb5:.x=.obj) \ - $(gen_files_ocsp:.x=.obj) \ - $(gen_files_pkinit:.x=.obj) \ - $(gen_files_pkcs8:.x=.obj) \ - $(gen_files_pkcs9:.x=.obj) \ - $(gen_files_pkcs10:.x=.obj) \ - $(gen_files_pkcs12:.x=.obj) \ - $(gen_files_digest:.x=.obj) \ - $(gen_files_kx509:.x=.obj) \ + $(OBJ)\der.obj \ + $(OBJ)\der_get.obj \ + $(OBJ)\der_put.obj \ + $(OBJ)\der_free.obj \ + $(OBJ)\der_length.obj \ + $(OBJ)\der_copy.obj \ + $(OBJ)\der_cmp.obj \ + $(OBJ)\der_format.obj \ + $(OBJ)\extra.obj \ + $(OBJ)\timegm.obj \ + $(gen_files_rfc2459:.x=.obj) \ + $(gen_files_rfc4043:.x=.obj) \ + $(gen_files_rfc4108:.x=.obj) \ + $(gen_files_tcg:.x=.obj) \ + $(gen_files_cms:.x=.obj) \ + $(gen_files_crmf:.x=.obj) \ + $(gen_files_krb5:.x=.obj) \ + $(gen_files_ocsp:.x=.obj) \ + $(gen_files_pkinit:.x=.obj) \ + $(gen_files_pkcs8:.x=.obj) \ + $(gen_files_pkcs9:.x=.obj) \ + $(gen_files_pkcs10:.x=.obj) \ + $(gen_files_pkcs12:.x=.obj) \ + $(gen_files_digest:.x=.obj) \ + $(gen_files_kx509:.x=.obj) \ + $(gen_files_x690sample:.x=.obj) \ $(OBJ)\asn1_err.obj $(OBJ)\oid_resolution.obj: $(LIBASN1_OBJS) @@ -194,6 +197,8 @@ $(gen_files_cms:.x=.c) : $$(@R).x $(gen_files_crmf:.x=.c) : $$(@R).x +$(gen_files_x690sample:.x=.c) : $$(@R).x + $(gen_files_test:.x=.c) : $$(@R).x $(gen_files_krb5) $(OBJ)\krb5_asn1.hx: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5.opt @@ -310,6 +315,14 @@ $(gen_files_crmf) $(OBJ)\crmf_asn1.hx: $(BINDIR)\asn1_compile.exe crmf.asn1 crmf || ($(RM) $(OBJ)\crmf_asn1.h ; exit /b 1) cd $(SRCDIR) +$(gen_files_x690sample) $(OBJ)\x690sample_asn1.hx: $(BINDIR)\asn1_compile.exe x690sample.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --one-code-file \ + $(SRCDIR)\x690sample.asn1 x690sample_asn1 \ + || ($(RM) $(OBJ)\x690sample_asn1.h ; exit /b 1) + cd $(SRCDIR) + $(gen_files_test) $(OBJ)\test_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ @@ -329,39 +342,41 @@ INCFILES= \ $(INCDIR)\der-protos.h: $(OBJ)\der-protos.h -GENINCFILES= \ - $(INCDIR)\asn1_err.h \ - $(INCDIR)\cms_asn1.h \ - $(INCDIR)\crmf_asn1.h \ - $(INCDIR)\digest_asn1.h \ - $(INCDIR)\krb5_asn1.h \ - $(INCDIR)\kx509_asn1.h \ - $(INCDIR)\ocsp_asn1.h \ - $(INCDIR)\pkcs12_asn1.h \ - $(INCDIR)\pkcs8_asn1.h \ - $(INCDIR)\pkcs9_asn1.h \ - $(INCDIR)\pkcs10_asn1.h \ - $(INCDIR)\pkinit_asn1.h \ - $(INCDIR)\rfc2459_asn1.h \ - $(INCDIR)\rfc4043_asn1.h \ - $(INCDIR)\rfc4108_asn1.h \ - $(INCDIR)\tcg_asn1.h \ - $(OBJ)\krb5_asn1-priv.h \ - $(OBJ)\ocsp_asn1-priv.h \ - $(OBJ)\pkinit_asn1-priv.h \ - $(OBJ)\cms_asn1-priv.h \ - $(OBJ)\crmf_asn1-priv.h \ - $(OBJ)\rfc2459_asn1-priv.h \ - $(OBJ)\rfc4043_asn1-priv.h \ - $(OBJ)\rfc4108_asn1-priv.h \ - $(OBJ)\tcg_asn1-priv.h \ - $(OBJ)\pkcs8_asn1-priv.h \ - $(OBJ)\pkcs9_asn1-priv.h \ - $(OBJ)\pkcs10_asn1-priv.h \ - $(OBJ)\pkcs12_asn1-priv.h \ - $(OBJ)\digest_asn1-priv.h \ - $(OBJ)\kx509_asn1-priv.h \ - $(OBJ)\test_asn1.h \ +GENINCFILES= \ + $(INCDIR)\asn1_err.h \ + $(INCDIR)\cms_asn1.h \ + $(INCDIR)\crmf_asn1.h \ + $(INCDIR)\digest_asn1.h \ + $(INCDIR)\krb5_asn1.h \ + $(INCDIR)\kx509_asn1.h \ + $(INCDIR)\ocsp_asn1.h \ + $(INCDIR)\pkcs12_asn1.h \ + $(INCDIR)\pkcs8_asn1.h \ + $(INCDIR)\pkcs9_asn1.h \ + $(INCDIR)\pkcs10_asn1.h \ + $(INCDIR)\pkinit_asn1.h \ + $(INCDIR)\rfc2459_asn1.h \ + $(INCDIR)\rfc4043_asn1.h \ + $(INCDIR)\rfc4108_asn1.h \ + $(INCDIR)\tcg_asn1.h \ + $(INCDIR)\x690sample_asn1.h \ + $(OBJ)\krb5_asn1-priv.h \ + $(OBJ)\ocsp_asn1-priv.h \ + $(OBJ)\pkinit_asn1-priv.h \ + $(OBJ)\cms_asn1-priv.h \ + $(OBJ)\crmf_asn1-priv.h \ + $(OBJ)\rfc2459_asn1-priv.h \ + $(OBJ)\rfc4043_asn1-priv.h \ + $(OBJ)\rfc4108_asn1-priv.h \ + $(OBJ)\tcg_asn1-priv.h \ + $(OBJ)\x690sample_asn1-priv.h \ + $(OBJ)\pkcs8_asn1-priv.h \ + $(OBJ)\pkcs9_asn1-priv.h \ + $(OBJ)\pkcs10_asn1-priv.h \ + $(OBJ)\pkcs12_asn1-priv.h \ + $(OBJ)\digest_asn1-priv.h \ + $(OBJ)\kx509_asn1-priv.h \ + $(OBJ)\test_asn1.h \ $(OBJ)\test_asn1-priv.h libasn1_base_SOURCES= \ diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index bf2da8e75..b5d8dbd44 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -1497,6 +1498,7 @@ check_TESTMechTypeList(void) errx(1, "TESTMechTypeList: %d", ret); if (len != size) abort(); + free(ptr); return 0; } @@ -1770,6 +1772,68 @@ test_seqof5(void) return ret; } +static int +test_x690sample(void) +{ + /* Taken from X.690, Appendix A */ + X690SamplePersonnelRecord r; + heim_octet_string os; + unsigned char encoded_sample[] = { + 0x60, 0x81, 0x85, 0x61, 0x10, 0x1a, 0x04, 0x4a, 0x6f, 0x68, 0x6e, 0x1a, + 0x01, 0x50, 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x1a, + 0x08, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x01, 0x33, + 0xa1, 0x0a, 0x43, 0x08, 0x31, 0x39, 0x37, 0x31, 0x30, 0x39, 0x31, 0x37, + 0xa2, 0x12, 0x61, 0x10, 0x1a, 0x04, 0x4d, 0x61, 0x72, 0x79, 0x1a, 0x01, + 0x54, 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa3, 0x42, 0x31, 0x1f, + 0x61, 0x11, 0x1a, 0x05, 0x52, 0x61, 0x6c, 0x70, 0x68, 0x1a, 0x01, 0x54, + 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x43, 0x08, 0x31, + 0x39, 0x35, 0x37, 0x31, 0x31, 0x31, 0x31, 0x31, 0x1f, 0x61, 0x11, 0x1a, + 0x05, 0x53, 0x75, 0x73, 0x61, 0x6e, 0x1a, 0x01, 0x42, 0x1a, 0x05, 0x53, + 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x43, 0x08, 0x31, 0x39, 0x35, 0x39, + 0x30, 0x37, 0x31, 0x37 + }; + size_t sz = 0; + int ret; + + memset(&r, 0, sizeof(r)); + if (decode_X690SamplePersonnelRecord(encoded_sample, sizeof(encoded_sample), &r, &sz)) + return 1; + if (sz != sizeof(encoded_sample)) + return 1; + free_X690SamplePersonnelRecord(&r); + memset(&r, 0, sizeof(r)); + + r.name.givenName = strdup("John"); + r.name.initial = strdup("P"); + r.name.familyName = strdup("Smith"); + r.title = strdup("Director"); + r.dateOfHire = strdup("19710917"); + r.number = 51; + r.nameOfSpouse.givenName = strdup("Mary"); + r.nameOfSpouse.initial = strdup("T"); + r.nameOfSpouse.familyName = strdup("Smith"); + r.children.val = calloc(2, sizeof(r.children.val[0])); + r.children.len = 2; + r.children.val[0].name.givenName = strdup("Ralph"); + r.children.val[0].name.initial = strdup("T"); + r.children.val[0].name.familyName = strdup("Smith"); + r.children.val[0].dateOfBirth = strdup("19571111"); + r.children.val[1].name.givenName = strdup("Susan"); + r.children.val[1].name.initial = strdup("B"); + r.children.val[1].name.familyName = strdup("Smith"); + r.children.val[1].dateOfBirth = strdup("19590717"); + os.length = 0; + os.data = 0; + ASN1_MALLOC_ENCODE(X690SamplePersonnelRecord, os.data, os.length, &r, &sz, + ret); + if (ret || sz != sizeof(encoded_sample) || sz != os.length || + memcmp(encoded_sample, os.data, sz) != 0) + return 1; + free_X690SamplePersonnelRecord(&r); + free(os.data); + return 0; +} + int main(int argc, char **argv) { @@ -1808,5 +1872,7 @@ main(int argc, char **argv) ret += test_seq4(); ret += test_seqof5(); + ret += test_x690sample(); + return ret; } diff --git a/lib/asn1/libasn1-exports.def b/lib/asn1/libasn1-exports.def index 52f1be4c1..3a3fb032c 100644 --- a/lib/asn1/libasn1-exports.def +++ b/lib/asn1/libasn1-exports.def @@ -594,6 +594,11 @@ EXPORTS copy_VendorLoadErrorCode copy_Version copy_WrappedFirmwareKey + copy_X690SampleChildInformation + copy_X690SampleDate + copy_X690SampleEmployeeNumber + copy_X690SampleName + copy_X690SamplePersonnelRecord decode_AccessDescription decode_AD_AND_OR decode_AD_IF_RELEVANT @@ -927,6 +932,11 @@ EXPORTS decode_VendorLoadErrorCode decode_Version decode_WrappedFirmwareKey + decode_X690SampleChildInformation + decode_X690SampleDate + decode_X690SampleEmployeeNumber + decode_X690SampleName + decode_X690SamplePersonnelRecord der_copy_bit_string der_copy_bmp_string der_copy_generalized_time @@ -1388,6 +1398,11 @@ EXPORTS encode_VendorLoadErrorCode encode_Version encode_WrappedFirmwareKey + encode_X690SampleChildInformation + encode_X690SampleDate + encode_X690SampleEmployeeNumber + encode_X690SampleName + encode_X690SamplePersonnelRecord FastOptions2int free_AccessDescription free_AD_AND_OR @@ -1722,6 +1737,11 @@ EXPORTS free_VendorLoadErrorCode free_Version free_WrappedFirmwareKey + free_X690SampleChildInformation + free_X690SampleDate + free_X690SampleEmployeeNumber + free_X690SampleName + free_X690SamplePersonnelRecord heim_any_cmp _heim_der_set_sort _heim_fix_dce @@ -2077,6 +2097,11 @@ EXPORTS length_VendorLoadErrorCode length_Version length_WrappedFirmwareKey + length_X690SampleChildInformation + length_X690SampleDate + length_X690SampleEmployeeNumber + length_X690SampleName + length_X690SamplePersonnelRecord remove_AttributeValues remove_AuthorizationData remove_CertificatePolicies diff --git a/lib/asn1/x690sample.asn1 b/lib/asn1/x690sample.asn1 new file mode 100644 index 000000000..e4d7e07a5 --- /dev/null +++ b/lib/asn1/x690sample.asn1 @@ -0,0 +1,146 @@ +x690sample DEFINITIONS ::= BEGIN + +IMPORTS heim_any, + heim_any_set FROM heim; + +-- This is taken from Appendix A of X.690. +-- +-- This doesn't exercise every feature, like OPTIONAL, not really DEFAULT, not +-- EXPLICIT tagging, extensibility markers, etc., but it exercises some hard +-- ones like SET and IMPLICIT tagging. +-- +-- Because we don't yet have an option to add a namespace prefix to generated +-- symbols, to avoid conflicts with rfc2459's Name we're prefixing the type +-- names here manually. + +X690SamplePersonnelRecord ::= [APPLICATION 0] IMPLICIT SET { + name X690SampleName, + title [0] VisibleString, + number X690SampleEmployeeNumber, + dateOfHire [1] X690SampleDate, + nameOfSpouse [2] X690SampleName, + -- Heimdal's ASN.1 compiler doesn't handle DEFAULT values for types for + -- which it doesn't support literal values. + children [3] IMPLICIT SEQUENCE OF X690SampleChildInformation -- DEFAULT {} +} + +X690SampleChildInformation ::= SET { + name X690SampleName, + dateOfBirth [0] X690SampleDate +} + +X690SampleName ::= [APPLICATION 1] IMPLICIT SEQUENCE { + givenName VisibleString, + initial VisibleString, + familyName VisibleString +} + +-- Range added for test convenience. +X690SampleEmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) + +X690SampleDate::= [APPLICATION 3] IMPLICIT VisibleString --YYYYMMDD + +-- The following is value syntax for the above, but Heimdal's ASN.1 compiler +-- does not yet support value syntax for anything other than OIDs, booleans, +-- integers, and UTF-8 strings: +-- +-- { name { givenName "John", initial "P", familyName "Smith" }, +-- title "Director", +-- number 51, +-- dateOfHire "19710917", +-- nameOfSpouse {givenName "Mary", initial "T", familyName "Smith" }, +-- children { +-- {name {givenName "Ralph", initial "T", familyName "Smith" }, +-- dateOfBirth "19571111"}, +-- {name {givenName "Susan", initial "B", familyName "Jones" }, +-- I dateOfBirth "19590717"} +-- } +-- } +-- +-- The encoding of this value is supposed to be (all hex) (adapted from X.690 +-- Appendix A): +-- +-- 60818561101A044A6F686E1A01501A05536D697468A00A1A084469726563746F +-- 72420133A10A43083139373130393137A21261101A044D6172791A01541A0553 +-- 6D697468A342311F61111A0552616C70681A01541A05536D697468A00A430831 +-- 39353731313131311F61111A05537573616E1A01421A05536D697468A00A4308 +-- 3139353930373137 +-- +-- And a rough visualization of this is (adapted from X.690 Appendix A): +-- +-- T L +-- 60 8185 # 3 +-- Name +-- T L +-- 61 10 # 2 +-- T L "John" +-- 1A 04 4A6F686E # 6 +-- T L "P" +-- 1A 01 50 # 3 +-- T L "Smith" +-- 1A 05 536D697468 # 7 +-- Title +-- T L T L "Director" +-- A0 0A 1A 08 4469726563746F72 #12 +-- Emp. # +-- 42 01 33 # 3 +-- Date of hire +-- A1 0A 43 08 3139373130393137 #12 +-- Spouse +-- A2 12 # 2 +-- Name +-- 61 10 # 2 +-- 1A 04 4D617279 # 6 +-- 1A 01 54 # 3 +-- 1A 05 536D697468 # 7 +-- Children +-- A3 42 # 2 +-- 31 1F # 2 +-- Name +-- 61 11 1A 05 52616C7068 # 9 +-- 1A 01 54 # 3 +-- 1A 05 536D697468 # 7 +-- DoB +-- A0 0A 43 08 3139353731313131 #12 +-- 31 1F # 2 bytes +-- 61 11 1A 05 537573616E # 9 bytes +-- 1A 01 42 # 3 bytes +-- 1A 05 536D697468 # 7 bytes +-- A0 0A 43 08 3139353930373137 #12 bytes +-- +-- Our asn1_print program dumps this as follows, which looks correct: +-- +-- APPL CONS tag 0 = 133 bytes [0] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "John" +-- UNIV PRIM VisibleString = "P" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- UNIV PRIM VisibleString = "Director" +-- APPL PRIM tag 2 = 1 bytes [2] IMPLICIT content +-- CONTEXT CONS tag 1 = 10 bytes [1] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- CONTEXT CONS tag 2 = 18 bytes [2] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "Mary" +-- UNIV PRIM VisibleString = "T" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 3 = 66 bytes [3] +-- UNIV CONS Set = 31 bytes { +-- APPL CONS tag 1 = 17 bytes [1] +-- UNIV PRIM VisibleString = "Ralph" +-- UNIV PRIM VisibleString = "T" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- } +-- UNIV CONS Set = 31 bytes { +-- APPL CONS tag 1 = 17 bytes [1] +-- UNIV PRIM VisibleString = "Susan" +-- UNIV PRIM VisibleString = "B" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- } + +END