diff --git a/lib/asn1/Makefile.am b/lib/asn1/Makefile.am index c86eaf0fb..8a75ae970 100644 --- a/lib/asn1/Makefile.am +++ b/lib/asn1/Makefile.am @@ -7,34 +7,44 @@ YFLAGS = -d -t lib_LTLIBRARIES = libasn1.la libasn1_la_LDFLAGS = -version-info 8:0:0 +noinst_LTLIBRARIES = libasn1base.la + if versionscript libasn1_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map endif libasn1_la_LIBADD = \ + libasn1base.la \ @LIB_com_err@ \ $(LIBADD_roken) BUILT_SOURCES = \ $(gen_files_rfc2459:.x=.c) \ + rfc2459_asn1-template.c \ $(gen_files_cms:.x=.c) \ - $(gen_files_k5:.x=.c) \ + cms_asn1-template.c \ + $(gen_files_krb5:.x=.c) \ + krb5_asn1-template.c \ $(gen_files_pkinit:.x=.c) \ + pkinit_asn1-template.c \ $(gen_files_pkcs8:.x=.c) \ + pkcs8_asn1-template.c \ $(gen_files_pkcs9:.x=.c) \ + pkcs9_asn1-template.c \ $(gen_files_pkcs12:.x=.c) \ + pkcs12_asn1-template.c \ $(gen_files_digest:.x=.c) \ + digest_asn1-template.c \ $(gen_files_kx509:.x=.c) \ - asn1_err.h \ - asn1_err.c + kx509_asn1-template.c -gen_files_k5 = \ +gen_files_krb5 = \ asn1_AD_AND_OR.x \ asn1_AD_IF_RELEVANT.x \ asn1_AD_KDCIssued.x \ - asn1_AD_MANDATORY_FOR_KDC.x \ asn1_AD_LoginAlias.x \ + asn1_AD_MANDATORY_FOR_KDC.x \ asn1_APOptions.x \ asn1_AP_REP.x \ asn1_AP_REQ.x \ @@ -62,12 +72,15 @@ gen_files_k5 = \ asn1_EncryptedData.x \ asn1_EncryptionKey.x \ asn1_EtypeList.x \ + asn1_FastOptions.x \ asn1_HostAddress.x \ asn1_HostAddresses.x \ asn1_KDCOptions.x \ asn1_KDC_REP.x \ asn1_KDC_REQ.x \ asn1_KDC_REQ_BODY.x \ + asn1_KRB5SignedPath.x \ + asn1_KRB5SignedPathData.x \ asn1_KRB_CRED.x \ asn1_KRB_ERROR.x \ asn1_KRB_PRIV.x \ @@ -76,12 +89,22 @@ gen_files_k5 = \ asn1_KerberosString.x \ asn1_KerberosTime.x \ asn1_KrbCredInfo.x \ + asn1_KrbFastArmor.x \ + asn1_KrbFastArmoredRep.x \ + asn1_KrbFastArmoredReq.x \ + asn1_KrbFastFinished.x \ + asn1_KrbFastReq.x \ + asn1_KrbFastResponse.x \ asn1_LR_TYPE.x \ asn1_LastReq.x \ asn1_MESSAGE_TYPE.x \ asn1_METHOD_DATA.x \ asn1_NAME_TYPE.x \ + asn1_PA_FX_FAST_REPLY.x \ + asn1_PA_FX_FAST_REQUEST.x \ asn1_PADATA_TYPE.x \ + asn1_PA_ClientCanonicalized.x \ + asn1_PA_ClientCanonicalizedNames.x \ asn1_PA_DATA.x \ asn1_PA_ENC_SAM_RESPONSE_ENC.x \ asn1_PA_ENC_TS_ENC.x \ @@ -92,11 +115,9 @@ gen_files_k5 = \ asn1_PA_SAM_REDIRECT.x \ asn1_PA_SAM_RESPONSE_2.x \ asn1_PA_SAM_TYPE.x \ - asn1_PA_ClientCanonicalized.x \ - asn1_PA_ClientCanonicalizedNames.x \ - asn1_PA_SvrReferralData.x \ - asn1_PA_ServerReferralData.x \ asn1_PA_SERVER_REFERRAL_DATA.x \ + asn1_PA_ServerReferralData.x \ + asn1_PA_SvrReferralData.x \ asn1_PROV_SRV_LOCATION.x \ asn1_Principal.x \ asn1_PrincipalName.x \ @@ -111,18 +132,7 @@ gen_files_k5 = \ asn1_TransitedEncoding.x \ asn1_TypedData.x \ asn1_krb5int32.x \ - asn1_krb5uint32.x \ - asn1_KRB5SignedPathData.x \ - asn1_KRB5SignedPath.x \ - asn1_FastOptions.x \ - asn1_KrbFastArmor.x \ - asn1_KrbFastArmoredRep.x \ - asn1_KrbFastArmoredReq.x \ - asn1_KrbFastFinished.x \ - asn1_KrbFastReq.x \ - asn1_KrbFastResponse.x \ - asn1_PA_FX_FAST_REPLY.x \ - asn1_PA_FX_FAST_REQUEST.x + asn1_krb5uint32.x gen_files_cms = \ asn1_CMSAttributes.x \ @@ -430,8 +440,10 @@ gen_files_pkcs9 = \ asn1_PKCS9_friendlyName.x gen_files_test = \ + asn1_TESTOptional.x \ asn1_TESTAlloc.x \ asn1_TESTAllocInner.x \ + asn1_TESTBitString.x \ asn1_TESTCONTAINING.x \ asn1_TESTCONTAININGENCODEDBY.x \ asn1_TESTCONTAININGENCODEDBY2.x \ @@ -445,14 +457,21 @@ gen_files_test = \ asn1_TESTInteger2.x \ asn1_TESTInteger3.x \ asn1_TESTLargeTag.x \ - asn1_TESTSeq.x \ - asn1_TESTUSERCONSTRAINED.x \ - asn1_TESTSeqOf.x \ asn1_TESTOSSize1.x \ + asn1_TESTPreserve.x \ + asn1_TESTSeq.x \ + asn1_TESTSeqOf.x \ + asn1_TESTSeqOf2.x \ + asn1_TESTSeqOf3.x \ + asn1_TESTSeqOfSeq.x \ + asn1_TESTSeqOfSeq2.x \ + asn1_TESTSeqOfSeq3.x \ asn1_TESTSeqSizeOf1.x \ asn1_TESTSeqSizeOf2.x \ asn1_TESTSeqSizeOf3.x \ - asn1_TESTSeqSizeOf4.x + asn1_TESTSeqSizeOf4.x \ + asn1_TESTUSERCONSTRAINED.x \ + asn1_TESTuint32.x gen_files_digest = \ asn1_DigestError.x \ @@ -479,15 +498,20 @@ noinst_PROGRAMS = asn1_gen libexec_heimdal_PROGRAMS = asn1_compile asn1_print -TESTS = check-der check-gen check-timegm check-ber +TESTS = check-der check-gen check-timegm check-ber check-template check_PROGRAMS = $(TESTS) asn1_gen_SOURCES = asn1_gen.c asn1_print_SOURCES = asn1_print.c check_der_SOURCES = check-der.c check-common.c check-common.h +check_template_SOURCES = check-template.c check-common.c check-common.h +nodist_check_template_SOURCES = $(gen_files_test:.x=.c) test_asn1-template.c + dist_check_gen_SOURCES = check-gen.c check-common.c check-common.h -nodist_check_gen_SOURCES = $(gen_files_test:.x=.c) +nodist_check_gen_SOURCES = $(gen_files_test:.x=.c) test_asn1-template.c + +build_HEADERZ = asn1-template.h asn1_compile_SOURCES = \ asn1-common.h \ @@ -503,16 +527,17 @@ asn1_compile_SOURCES = \ gen_length.c \ gen_locl.h \ gen_seq.c \ + gen_template.c \ hash.c \ hash.h \ lex.l \ lex.h \ main.c \ + asn1-template.h \ symbol.c \ symbol.h -dist_libasn1_la_SOURCES = \ - der-protos.h \ +dist_libasn1base_la_SOURCES = \ der_locl.h \ der.c \ der.h \ @@ -525,28 +550,38 @@ dist_libasn1_la_SOURCES = \ der_format.c \ heim_asn1.h \ extra.c \ + template.c \ timegm.c +nodist_libasn1base_la_SOURCES = \ + asn1_err.h \ + asn1_err.c + nodist_libasn1_la_SOURCES = $(BUILT_SOURCES) asn1_compile_LDADD = \ $(LIB_roken) $(LEXLIB) check_der_LDADD = \ + libasn1base.la \ + $(LIB_roken) + +check_template_LDADD = $(check_der_LDADD) +asn1_print_LDADD = $(check_der_LDADD) $(LIB_com_err) +asn1_gen_LDADD = $(check_der_LDADD) +check_timegm_LDADD = $(check_der_LDADD) + +check_gen_LDADD = \ libasn1.la \ $(LIB_roken) -check_gen_LDADD = $(check_der_LDADD) -check_ber_LDADD = $(check_der_LDADD) -asn1_print_LDADD = $(check_der_LDADD) -asn1_gen_LDADD = $(check_der_LDADD) -check_timegm_LDADD = $(check_der_LDADD) +check_ber_LDADD = $(check_gen_LDADD) CLEANFILES = \ $(BUILT_SOURCES) \ $(gen_files_rfc2459) \ $(gen_files_cms) \ - $(gen_files_k5) \ + $(gen_files_krb5) \ $(gen_files_pkinit) \ $(gen_files_pkcs8) \ $(gen_files_pkcs9) \ @@ -554,6 +589,7 @@ CLEANFILES = \ $(gen_files_digest) \ $(gen_files_kx509) \ $(gen_files_test) $(nodist_check_gen_SOURCES) \ + test_asn1-template.c \ rfc2459_asn1_files rfc2459_asn1.h* \ cms_asn1_files cms_asn1.h* \ krb5_asn1_files krb5_asn1.h* \ @@ -565,7 +601,7 @@ CLEANFILES = \ kx509_asn1_files kx509_asn1.h* \ test_asn1_files test_asn1.h* -dist_include_HEADERS = der.h heim_asn1.h der-protos.h +dist_include_HEADERS = der.h heim_asn1.h der-protos.h der-private.h nodist_include_HEADERS = asn1_err.h nodist_include_HEADERS += krb5_asn1.h @@ -578,14 +614,28 @@ nodist_include_HEADERS += pkcs12_asn1.h nodist_include_HEADERS += digest_asn1.h nodist_include_HEADERS += kx509_asn1.h -$(asn1_compile_OBJECTS): asn1parse.h asn1parse.c $(srcdir)/der-protos.h -$(libasn1_la_OBJECTS): $(nodist_include_HEADERS) $(srcdir)/der-protos.h +priv_headers = krb5_asn1-priv.h +priv_headers += pkinit_asn1-priv.h +priv_headers += cms_asn1-priv.h +priv_headers += rfc2459_asn1-priv.h +priv_headers += pkcs8_asn1-priv.h +priv_headers += pkcs9_asn1-priv.h +priv_headers += pkcs12_asn1-priv.h +priv_headers += digest_asn1-priv.h +priv_headers += kx509_asn1-priv.h + + + +$(asn1_compile_OBJECTS): asn1parse.h asn1parse.c $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1_la_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1base_la_OBJECTS): asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h $(check_gen_OBJECTS): test_asn1.h +$(check_template_OBJECTS): test_asn1_files $(asn1_print_OBJECTS): krb5_asn1.h asn1parse.h: asn1parse.c -$(gen_files_k5) krb5_asn1.hx: krb5_asn1_files +$(gen_files_krb5) krb5_asn1.hx: krb5_asn1_files $(gen_files_pkinit) pkinit_asn1.hx: pkinit_asn1_files $(gen_files_pkcs8) pkcs8_asn1.hx: pkcs8_asn1_files $(gen_files_pkcs9) pkcs9_asn1.hx: pkcs9_asn1_files @@ -626,6 +676,7 @@ kx509_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 test_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 $(ASN1_COMPILE) --sequence=TESTSeqOf $(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1) + EXTRA_DIST = \ cms.asn1 \ cms.opt \ @@ -646,4 +697,7 @@ EXTRA_DIST = \ version-script.map $(srcdir)/der-protos.h: - cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -o der-protos.h $(dist_libasn1_la_SOURCES) || rm -f der-protos.h + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -o der-protos.h $(dist_libasn1base_la_SOURCES) || rm -f der-protos.h + +$(srcdir)/der-private.h: + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p der-private.h $(dist_libasn1base_la_SOURCES) || rm -f der-private.h diff --git a/lib/asn1/README.template b/lib/asn1/README.template new file mode 100644 index 000000000..874c8fb0b --- /dev/null +++ b/lib/asn1/README.template @@ -0,0 +1,131 @@ +#!/bin/sh + +size .libs/libasn1.dylib +size .libs/libasn1base.a | awk '{sum += $1} END {print sum}' | sed 's/^/TEXT baselib: /' +size .libs/asn1_*.o | awk '{sum += $1} END {print sum}' | sed 's/^/generated code stubs: /' +size *_asn1-template.o | awk '{sum += $1} END {print sum}' | sed 's/^/TEXT stubs: /' + +exit 0 + +Notes about the template parser: + +- assumption: code is large, tables smaller + +- how to generate template based stubs: + + make check asn1_compile_FLAGS=--template > log + +- pretty much the same as the generate code, except uses tables instead of code + +TODO: + - Make hdb work + + - Fuzzing tests + + - Performance testing + + - ASN1_MALLOC_ENCODE() as a function, replaces encode_ and length_ + + - Fix SIZE constraits + + - Compact types that only contain on entry to not having a header. + + +SIZE - Futher down is later generations of the template parser + + code: + ================== + __TEXT __DATA __OBJC others dec hex + 462848 12288 0 323584 798720 c3000 (O2) + + trivial types: + ================== + __TEXT __DATA __OBJC others dec hex + 446464 12288 0 323584 782336 bf000 (O2) + + OPTIONAL + ================== + __TEXT __DATA __OBJC others dec hex + 425984 16384 0 323584 765952 bb000 (O2) + + SEQ OF + ================== + __TEXT __DATA __OBJC others dec hex + 368640 32768 0 327680 729088 b2000 (O2) + 348160 32768 0 327680 708608 ad000 (Os) + + BOOLEAN + ================== + 339968 32768 0 327680 700416 ab000 (Os) + + TYPE_EXTERNAL: + ================== + 331776 32768 0 327680 692224 a9000 (Os) + + SET OF + ================== + 327680 32768 0 327680 688128 a8000 (Os) + + TYPE_EXTERNAL everywhere + ================== + __TEXT __DATA __OBJC others dec hex + 167936 69632 0 327680 565248 8a000 (Os) + + TAG uses ->ptr (header and trailer) + ================== + 229376 102400 0 421888 753664 b8000 (O0) + + TAG uses ->ptr (header only) + ================== + 221184 77824 0 421888 720896 b0000 (O0) + + BER support for octet string (not working) + ================== + 180224 73728 0 417792 671744 a4000 (O2) + + CHOICE and BIT STRING missign + ================== + __TEXT __DATA __OBJC others dec hex + 172032 73728 0 417792 663552 a2000 (Os) + + No accessor functions to global variable + ================== + __TEXT __DATA __OBJC others dec hex + 159744 73728 0 393216 626688 99000 (Os) + + All types tables (except choice) (id still objects) + ================== + __TEXT __DATA __OBJC others dec hex + 167936 77824 0 421888 667648 a3000 + base lib: 22820 + + __TEXT __DATA __OBJC others dec hex + ================== + 167936 77824 0 421888 667648 a3000 (Os) + baselib: 22820 + generated code stubs: 41472 + TEXT stubs: 112560 + + All types, id still objects + ================== + __TEXT __DATA __OBJC others dec hex + 155648 81920 0 430080 667648 a3000 (Os) + TEXT baselib: 23166 + generated code stubs: 20796 + TEXT stubs: 119891 + + All types, id still objects, dup compression + ================== + __TEXT __DATA __OBJC others dec hex + 143360 65536 0 376832 585728 8f000 (Os) + TEXT baselib: 23166 + generated code stubs: 20796 + TEXT stubs: 107147 + + All types, dup compression, id vars + ================== + __TEXT __DATA __OBJC others dec hex + 131072 65536 0 352256 548864 86000 + TEXT baselib: 23166 + generated code stubs: 7536 + TEXT stubs: 107147 diff --git a/lib/asn1/asn1-template.h b/lib/asn1/asn1-template.h new file mode 100644 index 000000000..107706ce8 --- /dev/null +++ b/lib/asn1/asn1-template.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* asn1 templates */ + +#ifndef __TEMPLATE_H__ +#define __TEMPLATE_H__ + +/* tag: + * 0..20 tag + * 21 type + * 22..23 class + * 24..27 flags + * 28..31 op + */ + +/* parse: + * 0..11 type + * 12..23 unused + * 24..27 flags + * 28..31 op + */ + +#define A1_OP_MASK (0xf0000000) +#define A1_OP_TYPE (0x10000000) +#define A1_OP_TYPE_EXTERN (0x20000000) +#define A1_OP_TAG (0x30000000) +#define A1_OP_PARSE (0x40000000) +#define A1_OP_SEQOF (0x50000000) +#define A1_OP_SETOF (0x60000000) +#define A1_OP_BMEMBER (0x70000000) +#define A1_OP_CHOICE (0x80000000) + +#define A1_FLAG_MASK (0x0f000000) +#define A1_FLAG_OPTIONAL (0x01000000) +#define A1_FLAG_IMPLICIT (0x02000000) + +#define A1_TAG_T(CLASS,TYPE,TAG) ((A1_OP_TAG) | (((CLASS) << 22) | ((TYPE) << 21) | (TAG))) +#define A1_TAG_CLASS(x) (((x) >> 22) & 0x3) +#define A1_TAG_TYPE(x) (((x) >> 21) & 0x1) +#define A1_TAG_TAG(x) ((x) & 0x1fffff) + +#define A1_TAG_LEN(t) ((uintptr_t)(t)->ptr) +#define A1_HEADER_LEN(t) ((uintptr_t)(t)->ptr) + +#define A1_PARSE_T(type) ((A1_OP_PARSE) | (type)) +#define A1_PARSE_TYPE_MASK 0xfff +#define A1_PARSE_TYPE(x) (A1_PARSE_TYPE_MASK & (x)) + +#define A1_PF_INDEFINTE 0x1 +#define A1_PF_ALLOW_BER 0x2 + +#define A1_HF_PRESERVE 0x1 +#define A1_HF_ELLIPSIS 0x2 + +#define A1_HBF_RFC1510 0x1 + + +struct asn1_template { + uint32_t tt; + size_t offset; + const void *ptr; +}; + +typedef int (*asn1_type_decode)(const unsigned char *, size_t, void *, size_t *); +typedef int (*asn1_type_encode)(unsigned char *, size_t, const void *, size_t *); +typedef size_t (*asn1_type_length)(const void *); +typedef void (*asn1_type_release)(void *); +typedef int (*asn1_type_copy)(const void *, void *); + +struct asn1_type_func { + asn1_type_encode encode; + asn1_type_decode decode; + asn1_type_length length; + asn1_type_copy copy; + asn1_type_release release; + size_t size; +}; + +struct template_of { + unsigned int len; + void *val; +}; + +enum template_types { + A1T_IMEMBER = 0, + A1T_HEIM_INTEGER, + A1T_INTEGER, + A1T_UNSIGNED, + A1T_GENERAL_STRING, + A1T_OCTET_STRING, + A1T_OCTET_STRING_BER, + A1T_IA5_STRING, + A1T_BMP_STRING, + A1T_UNIVERSAL_STRING, + A1T_PRINTABLE_STRING, + A1T_VISIBLE_STRING, + A1T_UTF8_STRING, + A1T_GENERALIZED_TIME, + A1T_UTC_TIME, + A1T_HEIM_BIT_STRING, + A1T_BOOLEAN, + A1T_OID, + A1T_TELETEX_STRING, + A1T_NULL +}; + + +#endif diff --git a/lib/asn1/asn1_err.et b/lib/asn1/asn1_err.et index f1a653b1f..ac7a9ebaa 100644 --- a/lib/asn1/asn1_err.et +++ b/lib/asn1/asn1_err.et @@ -24,4 +24,6 @@ error_code MAX_CONSTRAINT, "ASN.1 too many elements" error_code EXACT_CONSTRAINT, "ASN.1 wrong number of elements" error_code INDEF_OVERRUN, "ASN.1 BER indefinte encoding overrun" error_code INDEF_UNDERRUN, "ASN.1 BER indefinte encoding underun" +error_code GOT_BER, "ASN.1 got BER encoded when expected DER" +error_code INDEF_EXTRA_DATA, "ASN.1 EoC tag contained data" end diff --git a/lib/asn1/asn1_print.c b/lib/asn1/asn1_print.c index 258fd4d87..a95485bfe 100644 --- a/lib/asn1/asn1_print.c +++ b/lib/asn1/asn1_print.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -182,7 +184,9 @@ loop (unsigned char *buf, size_t len, int indent) case UT_GeneralizedTime : case UT_GeneralString : case UT_PrintableString : - case UT_VisibleString : { + case UT_VisibleString : + case UT_IA5String : + case UT_UTF8String : { heim_general_string str; ret = der_get_general_string (buf, length, &str, NULL); diff --git a/lib/asn1/asn1parse.y b/lib/asn1/asn1parse.y index 3835744bb..13b86b17c 100644 --- a/lib/asn1/asn1parse.y +++ b/lib/asn1/asn1parse.y @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -250,7 +252,7 @@ ExtensionDefault: kw_EXTENSIBILITY kw_IMPLIED | /* empty */ ; -ModuleBody : /* Exports */ Imports AssignmentList +ModuleBody : Exports Imports AssignmentList | /* empty */ ; @@ -272,11 +274,22 @@ SymbolsFromModule: referencenames kw_FROM IDENTIFIER objid_opt for(sl = $1; sl != NULL; sl = sl->next) { Symbol *s = addsym(sl->string); s->stype = Stype; + gen_template_import(s); } add_import($3); } ; +Exports : kw_EXPORTS referencenames ';' + { + struct string_list *sl; + for(sl = $2; sl != NULL; sl = sl->next) + add_export(sl->string); + } + | kw_EXPORTS kw_ALL + | /* empty */ + ; + AssignmentList : Assignment | Assignment AssignmentList ; diff --git a/lib/asn1/check-common.c b/lib/asn1/check-common.c index b39690383..15b3869bc 100644 --- a/lib/asn1/check-common.c +++ b/lib/asn1/check-common.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -197,7 +199,8 @@ generic_test (const struct test_case *tests, int (*length)(void *), int (*decode)(unsigned char *, size_t, void *, size_t *), int (*free_data)(void *), - int (*cmp)(void *a, void *b)) + int (*cmp)(void *a, void *b), + int (*copy)(const void *from, void *to)) { unsigned char *buf, *buf2; int i; @@ -210,6 +213,7 @@ generic_test (const struct test_case *tests, for (i = 0; i < ntests; ++i) { int ret; size_t sz, consumed_sz, length_sz, buf_sz; + void *to = NULL; current_test = tests[i].name; @@ -261,6 +265,11 @@ generic_test (const struct test_case *tests, printf ("\nactual: "); print_bytes (buf, sz); printf ("\n"); +#if 0 + rk_dumpdata("correct", tests[i].bytes, tests[i].byte_len); + rk_dumpdata("actual", buf, sz); + exit (1); +#endif ++failures; continue; } @@ -287,9 +296,33 @@ generic_test (const struct test_case *tests, ++failures; continue; } + + current_state = "copy"; + if (copy) { + to = emalloc(data_size); + ret = (*copy)(data, to); + if (ret != 0) { + printf ("copy of %s failed %d\n", tests[i].name, ret); + ++failures; + continue; + } + + current_state = "cmp-copy"; + if ((*cmp)(data, to) != 0) { + printf ("%s: copy comparison failed\n", tests[i].name); + ++failures; + continue; + } + } + current_state = "free"; - if (free_data) + if (free_data) { (*free_data)(data); + if (to) { + (*free_data)(to); + free(to); + } + } current_state = "free"; map_free(buf_map, tests[i].name, "encode"); diff --git a/lib/asn1/check-common.h b/lib/asn1/check-common.h index 6adf0818d..9a36dbcc1 100644 --- a/lib/asn1/check-common.h +++ b/lib/asn1/check-common.h @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,6 +44,7 @@ typedef int (*generic_encode)(unsigned char *, size_t, void *, size_t *); typedef int (*generic_length)(void *); typedef int (*generic_decode)(unsigned char *, size_t, void *, size_t *); typedef int (*generic_free)(void *); +typedef int (*generic_copy)(const void *, void *); int generic_test (const struct test_case *tests, @@ -51,7 +54,8 @@ generic_test (const struct test_case *tests, int (*length)(void *), int (*decode)(unsigned char *, size_t, void *, size_t *), int (*free_data)(void *), - int (*cmp)(void *a, void *b)); + int (*cmp)(void *a, void *b), + int (*copy)(const void *a, void *b)); int generic_decode_fail(const struct test_case *tests, diff --git a/lib/asn1/check-der.c b/lib/asn1/check-der.c index 5c46c7cc2..1bdec5d95 100644 --- a/lib/asn1/check-der.c +++ b/lib/asn1/check-der.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -82,10 +84,11 @@ test_integer (void) ret = generic_test (tests, ntests, sizeof(int), (generic_encode)der_put_integer, - (generic_length) der_length_integer, - (generic_decode)der_get_integer, - (generic_free)NULL, - cmp_integer); + (generic_length) der_length_integer, + (generic_decode)der_get_integer, + (generic_free)NULL, + cmp_integer, + NULL); for (i = 0; i < ntests; ++i) free (tests[i].name); @@ -207,7 +210,8 @@ test_unsigned (void) (generic_length)der_length_unsigned, (generic_decode)der_get_unsigned, (generic_free)NULL, - cmp_unsigned); + cmp_unsigned, + NULL); for (i = 0; i < ntests; ++i) free (tests[i].name); return ret; @@ -246,7 +250,8 @@ test_octet_string (void) (generic_length)der_length_octet_string, (generic_decode)der_get_octet_string, (generic_free)der_free_octet_string, - cmp_octet_string); + cmp_octet_string, + NULL); free(tests[0].name); return ret; } @@ -290,7 +295,8 @@ test_bmp_string (void) (generic_length)der_length_bmp_string, (generic_decode)der_get_bmp_string, (generic_free)der_free_bmp_string, - cmp_bmp_string); + cmp_bmp_string, + NULL); free(tests[0].name); free(tests[1].name); return ret; @@ -335,7 +341,8 @@ test_universal_string (void) (generic_length)der_length_universal_string, (generic_decode)der_get_universal_string, (generic_free)der_free_universal_string, - cmp_universal_string); + cmp_universal_string, + NULL); free(tests[0].name); free(tests[1].name); return ret; @@ -370,7 +377,8 @@ test_general_string (void) (generic_length)der_length_general_string, (generic_decode)der_get_general_string, (generic_free)der_free_general_string, - cmp_general_string); + cmp_general_string, + NULL); free(tests[0].name); return ret; } @@ -407,7 +415,8 @@ test_generalized_time (void) (generic_length)der_length_generalized_time, (generic_decode)der_get_generalized_time, (generic_free)NULL, - cmp_generalized_time); + cmp_generalized_time, + NULL); for (i = 0; i < ntests; ++i) free(tests[i].name); return ret; @@ -454,7 +463,8 @@ test_oid (void) (generic_length)der_length_oid, (generic_decode)der_get_oid, (generic_free)der_free_oid, - test_cmp_oid); + test_cmp_oid, + NULL); for (i = 0; i < ntests; ++i) free(tests[i].name); return ret; @@ -490,7 +500,8 @@ test_bit_string (void) (generic_length)der_length_bit_string, (generic_decode)der_get_bit_string, (generic_free)der_free_bit_string, - test_cmp_bit_string); + test_cmp_bit_string, + NULL); for (i = 0; i < ntests; ++i) free(tests[i].name); return ret; @@ -541,7 +552,8 @@ test_heim_integer (void) (generic_length)der_length_heim_integer, (generic_decode)der_get_heim_integer, (generic_free)der_free_heim_integer, - test_cmp_heim_integer); + test_cmp_heim_integer, + NULL); for (i = 0; i < ntests; ++i) free (tests[i].name); if (ret) @@ -590,7 +602,8 @@ test_boolean (void) (generic_length)der_length_boolean, (generic_decode)der_get_boolean, (generic_free)NULL, - test_cmp_boolean); + test_cmp_boolean, + NULL); for (i = 0; i < ntests; ++i) free (tests[i].name); if (ret) diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index 9adf4f3e0..20aacf28e 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -67,6 +69,8 @@ static char *nada_tgt_principal[] = { "krbtgt", "NADA.KTH.SE" }; do { if (strcmp((ac)->e, (bc)->e) != 0) return 1; } while(0) #define COMPARE_INTEGER(ac,bc,e) \ do { if ((ac)->e != (bc)->e) return 1; } while(0) +#define COMPARE_OPT_INTEGER(ac,bc,e) \ + do { if (*(ac)->e != *(bc)->e) return 1; } while(0) #define COMPARE_MEM(ac,bc,e,len) \ do { if (memcmp((ac)->e, (bc)->e,len) != 0) return 1; } while(0) @@ -128,7 +132,8 @@ test_principal (void) (generic_length)length_Principal, (generic_decode)decode_Principal, (generic_free)free_Principal, - cmp_principal); + cmp_principal, + NULL); for (i = 0; i < ntests; ++i) free (tests[i].name); @@ -194,7 +199,8 @@ test_authenticator (void) (generic_length)length_Authenticator, (generic_decode)decode_Authenticator, (generic_free)free_Authenticator, - cmp_authenticator); + cmp_authenticator, + (generic_copy)copy_Authenticator); for (i = 0; i < ntests; ++i) free(tests[i].name); @@ -288,7 +294,8 @@ test_krb_error (void) (generic_length)length_KRB_ERROR, (generic_decode)decode_KRB_ERROR, (generic_free)free_KRB_ERROR, - cmp_KRB_ERROR); + cmp_KRB_ERROR, + (generic_copy)copy_KRB_ERROR); } static int @@ -372,7 +379,8 @@ test_Name (void) (generic_length)length_Name, (generic_decode)decode_Name, (generic_free)free_Name, - cmp_Name); + cmp_Name, + (generic_copy)copy_Name); } static int @@ -431,9 +439,226 @@ test_bit_string (void) (generic_length)length_KeyUsage, (generic_decode)decode_KeyUsage, (generic_free)free_KeyUsage, - cmp_KeyUsage); + cmp_KeyUsage, + (generic_copy)copy_KeyUsage); } +static int +cmp_TicketFlags (void *a, void *b) +{ + TicketFlags *aa = a; + TicketFlags *ab = b; + + return TicketFlags2int(*aa) != TicketFlags2int(*ab); +} + +static int +test_bit_string_rfc1510 (void) +{ + struct test_case tests[] = { + { NULL, 7, + "\x03\x05\x00\x80\x00\x00\x00", + "TF bitstring 1" + }, + { NULL, 7, + "\x03\x05\x00\x40\x20\x00\x00", + "TF bitstring 2" + }, + { NULL, 7, + "\x03\x05\x00\x00\x20\x00\x00", + "TF bitstring 3" + }, + { NULL, 7, + "\x03\x05\x00\x00\x00\x00\x00", + "TF bitstring 4" + } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + TicketFlags tf1, tf2, tf3, tf4; + + memset(&tf1, 0, sizeof(tf1)); + tf1.reserved = 1; + tests[0].val = &tf1; + + memset(&tf2, 0, sizeof(tf2)); + tf2.forwardable = 1; + tf2.pre_authent = 1; + tests[1].val = &tf2; + + memset(&tf3, 0, sizeof(tf3)); + tf3.pre_authent = 1; + tests[2].val = &tf3; + + memset(&tf4, 0, sizeof(tf4)); + tests[3].val = &tf4; + + + return generic_test (tests, ntests, sizeof(TicketFlags), + (generic_encode)encode_TicketFlags, + (generic_length)length_TicketFlags, + (generic_decode)decode_TicketFlags, + (generic_free)free_TicketFlags, + cmp_TicketFlags, + (generic_copy)copy_TicketFlags); +} + +static int +cmp_KerberosTime (void *a, void *b) +{ + KerberosTime *aa = a; + KerberosTime *ab = b; + + return *aa != *ab; +} + +static int +test_time (void) +{ + struct test_case tests[] = { + { NULL, 17, + "\x18\x0f\x31\x39\x37\x30\x30\x31\x30\x31\x30\x31\x31\x38\x33\x31" + "\x5a", + "time 1" }, + { NULL, 17, + "\x18\x0f\x32\x30\x30\x39\x30\x35\x32\x34\x30\x32\x30\x32\x34\x30" + "\x5a" + "time 2" } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + KerberosTime times[] = { + 4711, + 1243130560 + }; + + tests[0].val = ×[0]; + tests[1].val = ×[1]; + + return generic_test (tests, ntests, sizeof(KerberosTime), + (generic_encode)encode_KerberosTime, + (generic_length)length_KerberosTime, + (generic_decode)decode_KerberosTime, + (generic_free)free_KerberosTime, + cmp_KerberosTime, + (generic_copy)copy_KerberosTime); +} + +struct { + const char *cert; + size_t len; +} certs[] = { + { + "\x30\x82\x02\x6c\x30\x82\x01\xd5\xa0\x03\x02\x01\x02\x02\x09\x00" + "\x99\x32\xde\x61\x0e\x40\x19\x8a\x30\x0d\x06\x09\x2a\x86\x48\x86" + "\xf7\x0d\x01\x01\x05\x05\x00\x30\x2a\x31\x1b\x30\x19\x06\x03\x55" + "\x04\x03\x0c\x12\x68\x78\x35\x30\x39\x20\x54\x65\x73\x74\x20\x52" + "\x6f\x6f\x74\x20\x43\x41\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13" + "\x02\x53\x45\x30\x1e\x17\x0d\x30\x39\x30\x34\x32\x36\x32\x30\x32" + "\x39\x34\x30\x5a\x17\x0d\x31\x39\x30\x34\x32\x34\x32\x30\x32\x39" + "\x34\x30\x5a\x30\x2a\x31\x1b\x30\x19\x06\x03\x55\x04\x03\x0c\x12" + "\x68\x78\x35\x30\x39\x20\x54\x65\x73\x74\x20\x52\x6f\x6f\x74\x20" + "\x43\x41\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x30" + "\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05" + "\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xb9\xd3\x1b\x67" + "\x1c\xf7\x5e\x26\x81\x3b\x82\xff\x03\xa4\x43\xb5\xb2\x63\x0b\x89" + "\x58\x43\xfe\x3d\xe0\x38\x7d\x93\x74\xbb\xad\x21\xa4\x29\xd9\x34" + "\x79\xf3\x1c\x8c\x5a\xd6\xb0\xd7\x19\xea\xcc\xaf\xe0\xa8\x40\x02" + "\x1d\x91\xf1\xac\x36\xb0\xfb\x08\xbd\xcc\x9a\xe1\xb7\x6e\xee\x0a" + "\x69\xbf\x6d\x2b\xee\x20\x82\x61\x06\xf2\x18\xcc\x89\x11\x64\x7e" + "\xb2\xff\x47\xd1\x3b\x52\x73\xeb\x5a\xc0\x03\xa6\x4b\xc7\x40\x7e" + "\xbc\xe1\x0e\x65\x44\x3f\x40\x8b\x02\x82\x54\x04\xd9\xcc\x2c\x67" + "\x01\xb6\x16\x82\xd8\x33\x53\x17\xd7\xde\x8d\x5d\x02\x03\x01\x00" + "\x01\xa3\x81\x99\x30\x81\x96\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16" + "\x04\x14\x6e\x48\x13\xdc\xbf\x8b\x95\x4c\x13\xf3\x1f\x97\x30\xdd" + "\x27\x96\x59\x9b\x0e\x68\x30\x5a\x06\x03\x55\x1d\x23\x04\x53\x30" + "\x51\x80\x14\x6e\x48\x13\xdc\xbf\x8b\x95\x4c\x13\xf3\x1f\x97\x30" + "\xdd\x27\x96\x59\x9b\x0e\x68\xa1\x2e\xa4\x2c\x30\x2a\x31\x1b\x30" + "\x19\x06\x03\x55\x04\x03\x0c\x12\x68\x78\x35\x30\x39\x20\x54\x65" + "\x73\x74\x20\x52\x6f\x6f\x74\x20\x43\x41\x31\x0b\x30\x09\x06\x03" + "\x55\x04\x06\x13\x02\x53\x45\x82\x09\x00\x99\x32\xde\x61\x0e\x40" + "\x19\x8a\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff" + "\x30\x0b\x06\x03\x55\x1d\x0f\x04\x04\x03\x02\x01\xe6\x30\x0d\x06" + "\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00" + "\x52\x9b\xe4\x0e\xee\xc2\x5d\xb7\xf1\xba\x47\xe3\xfe\xaf\x3d\x51" + "\x10\xfd\xe8\x0d\x14\x58\x05\x36\xa7\xeb\xd8\x05\xe5\x27\x6f\x51" + "\xb8\xec\x90\xd9\x03\xe1\xbc\x9c\x93\x38\x21\x5c\xaf\x4e\x6c\x7b" + "\x6c\x65\xa9\x92\xcd\x94\xef\xa8\xae\x90\x12\x14\x78\x2d\xa3\x15" + "\xaa\x42\xf1\xd9\x44\x64\x2c\x3c\xc0\xbd\x3a\x48\xd8\x80\x45\x8b" + "\xd1\x79\x82\xe0\x0f\xdf\x08\x3c\x60\x21\x6f\x31\x47\x98\xae\x2f" + "\xcb\xb1\xa1\xb9\xc1\xa3\x71\x5e\x4a\xc2\x67\xdf\x66\x0a\x51\xb5" + "\xad\x60\x05\xdb\x02\xd4\x1a\xd2\xb9\x4e\x01\x08\x2b\xc3\x57\xaf", + 624 }, + { + "\x30\x82\x02\x54\x30\x82\x01\xbd\xa0\x03\x02\x01\x02\x02\x01\x08" + "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30" + "\x2a\x31\x1b\x30\x19\x06\x03\x55\x04\x03\x0c\x12\x68\x78\x35\x30" + "\x39\x20\x54\x65\x73\x74\x20\x52\x6f\x6f\x74\x20\x43\x41\x31\x0b" + "\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x30\x1e\x17\x0d\x30" + "\x39\x30\x34\x32\x36\x32\x30\x32\x39\x34\x30\x5a\x17\x0d\x31\x39" + "\x30\x34\x32\x34\x32\x30\x32\x39\x34\x30\x5a\x30\x1b\x31\x0b\x30" + "\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x31\x0c\x30\x0a\x06\x03" + "\x55\x04\x03\x0c\x03\x6b\x64\x63\x30\x81\x9f\x30\x0d\x06\x09\x2a" + "\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81" + "\x89\x02\x81\x81\x00\xd2\x41\x7a\xf8\x4b\x55\xb2\xaf\x11\xf9\x43" + "\x9b\x43\x81\x09\x3b\x9a\x94\xcf\x00\xf4\x85\x75\x92\xd7\x2a\xa5" + "\x11\xf1\xa8\x50\x6e\xc6\x84\x74\x24\x17\xda\x84\xc8\x03\x37\xb2" + "\x20\xf3\xba\xb5\x59\x36\x21\x4d\xab\x70\xe2\xc3\x09\x93\x68\x14" + "\x12\x79\xc5\xbb\x9e\x1b\x4a\xf0\xc6\x24\x59\x25\xc3\x1c\xa8\x70" + "\x66\x5b\x3e\x41\x8e\xe3\x25\x71\x9a\x94\xa0\x5b\x46\x91\x6f\xdd" + "\x58\x14\xec\x89\xe5\x8c\x96\xc5\x38\x60\xe4\xab\xf2\x75\xee\x6e" + "\x62\xfc\xe1\xbd\x03\x47\xff\xc4\xbe\x0f\xca\x70\x73\xe3\x74\x58" + "\x3a\x2f\x04\x2d\x39\x02\x03\x01\x00\x01\xa3\x81\x98\x30\x81\x95" + "\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55" + "\x1d\x0f\x04\x04\x03\x02\x05\xe0\x30\x12\x06\x03\x55\x1d\x25\x04" + "\x0b\x30\x09\x06\x07\x2b\x06\x01\x05\x02\x03\x05\x30\x1d\x06\x03" + "\x55\x1d\x0e\x04\x16\x04\x14\x3a\xd3\x73\xff\xab\xdb\x7d\x8d\xc6" + "\x3a\xa2\x26\x3e\xae\x78\x95\x80\xc9\xe6\x31\x30\x48\x06\x03\x55" + "\x1d\x11\x04\x41\x30\x3f\xa0\x3d\x06\x06\x2b\x06\x01\x05\x02\x02" + "\xa0\x33\x30\x31\xa0\x0d\x1b\x0b\x54\x45\x53\x54\x2e\x48\x35\x4c" + "\x2e\x53\x45\xa1\x20\x30\x1e\xa0\x03\x02\x01\x01\xa1\x17\x30\x15" + "\x1b\x06\x6b\x72\x62\x74\x67\x74\x1b\x0b\x54\x45\x53\x54\x2e\x48" + "\x35\x4c\x2e\x53\x45\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01" + "\x01\x05\x05\x00\x03\x81\x81\x00\x83\xf4\x14\xa7\x6e\x59\xff\x80" + "\x64\xe7\xfa\xcf\x13\x80\x86\xe1\xed\x02\x38\xad\x96\x72\x25\xe5" + "\x06\x7a\x9a\xbc\x24\x74\xa9\x75\x55\xb2\x49\x80\x69\x45\x95\x4a" + "\x4c\x76\xa9\xe3\x4e\x49\xd3\xc2\x69\x5a\x95\x03\xeb\xba\x72\x23" + "\x9c\xfd\x3d\x8b\xc6\x07\x82\x3b\xf4\xf3\xef\x6c\x2e\x9e\x0b\xac" + "\x9e\x6c\xbb\x37\x4a\xa1\x9e\x73\xd1\xdc\x97\x61\xba\xfc\xd3\x49" + "\xa6\xc2\x4c\x55\x2e\x06\x37\x76\xb5\xef\x57\xe7\x57\x58\x8a\x71" + "\x63\xf3\xeb\xe7\x55\x68\x0d\xf6\x46\x4c\xfb\xf9\x43\xbb\x0c\x92" + "\x4f\x4e\x22\x7b\x63\xe8\x4f\x9c", + 600 + } +}; + +static int +test_cert(void) +{ + Certificate c, c2; + size_t size; + size_t i; + int ret; + + for (i = 0; i < sizeof(certs)/sizeof(certs[0]); i++) { + + ret = decode_Certificate((unsigned char *)certs[i].cert, + certs[i].len, &c, &size); + if (ret) + return ret; + + ret = copy_Certificate(&c, &c2); + free_Certificate(&c); + if (ret) + return ret; + + free_Certificate(&c2); + } + + return 0; +} + + static int cmp_TESTLargeTag (void *a, void *b) { @@ -441,6 +666,7 @@ cmp_TESTLargeTag (void *a, void *b) TESTLargeTag *ab = b; COMPARE_INTEGER(aa,ab,foo); + COMPARE_INTEGER(aa,ab,bar); return 0; } @@ -448,7 +674,7 @@ static int test_large_tag (void) { struct test_case tests[] = { - { NULL, 8, "\x30\x06\xbf\x7f\x03\x02\x01\x01", "large tag 1" } + { NULL, 15, "\x30\x0d\xbf\x7f\x03\x02\x01\x01\xbf\x81\x00\x03\x02\x01\x02", "large tag 1" } }; int ntests = sizeof(tests) / sizeof(*tests); @@ -456,6 +682,7 @@ test_large_tag (void) memset(<1, 0, sizeof(lt1)); lt1.foo = 1; + lt1.bar = 2; tests[0].val = <1; @@ -464,7 +691,8 @@ test_large_tag (void) (generic_length)length_TESTLargeTag, (generic_decode)decode_TESTLargeTag, (generic_free)free_TESTLargeTag, - cmp_TESTLargeTag); + cmp_TESTLargeTag, + (generic_copy)copy_TESTLargeTag); } struct test_data { @@ -490,9 +718,9 @@ check_tag_length(void) { 0, 5, 0, "\x02\xff\x7f\x02\x00"} }; size_t sz; - krb5uint32 values[] = {0, 127, 128, 256, 512, + TESTuint32 values[] = {0, 127, 128, 256, 512, 0, 127, 128, 256, 512 }; - krb5uint32 u; + TESTuint32 u; int i, ret, failed = 0; void *buf; @@ -501,7 +729,7 @@ check_tag_length(void) buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); - ret = decode_krb5uint32(buf, td[i].len, &u, &sz); + ret = decode_TESTuint32(buf, td[i].len, &u, &sz); if (ret) { if (td[i].ok) { printf("failed with tag len test %d\n", i); @@ -560,7 +788,8 @@ test_choice (void) (generic_length)length_TESTChoice1, (generic_decode)decode_TESTChoice1, (generic_free)free_TESTChoice1, - cmp_TESTChoice); + cmp_TESTChoice, + (generic_copy)copy_TESTChoice1); memset(&c2_2, 0, sizeof(c2_2)); c2_2.element = choice_TESTChoice2_asn1_ellipsis; @@ -573,7 +802,8 @@ test_choice (void) (generic_length)length_TESTChoice2, (generic_decode)decode_TESTChoice2, (generic_free)free_TESTChoice2, - cmp_TESTChoice); + cmp_TESTChoice, + (generic_copy)copy_TESTChoice2); return ret; } @@ -623,7 +853,8 @@ test_implicit (void) (generic_length)length_TESTImplicit, (generic_decode)decode_TESTImplicit, (generic_free)free_TESTImplicit, - cmp_TESTImplicit); + cmp_TESTImplicit, + (generic_copy)copy_TESTImplicit); #ifdef IMPLICIT_TAGGING_WORKS ret += generic_test (tests, ntests, sizeof(TESTImplicit2), @@ -631,7 +862,8 @@ test_implicit (void) (generic_length)length_TESTImplicit2, (generic_decode)decode_TESTImplicit2, (generic_free)free_TESTImplicit2, - cmp_TESTImplicit); + cmp_TESTImplicit, + NULL); #endif /* IMPLICIT_TAGGING_WORKS */ return ret; @@ -718,13 +950,95 @@ test_taglessalloc (void) (generic_length)length_TESTAlloc, (generic_decode)decode_TESTAlloc, (generic_free)free_TESTAlloc, - cmp_TESTAlloc); + cmp_TESTAlloc, + (generic_copy)copy_TESTAlloc); free(c1.tagless); return ret; } +static int +cmp_TESTOptional (void *a, void *b) +{ + TESTOptional *aa = a; + TESTOptional *ab = b; + + IF_OPT_COMPARE(aa,ab,zero) { + COMPARE_OPT_INTEGER(aa,ab,zero); + } + IF_OPT_COMPARE(aa,ab,one) { + COMPARE_OPT_INTEGER(aa,ab,one); + } + return 0; +} + +/* +UNIV CONS Sequence 5 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 00 + +UNIV CONS Sequence 5 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 03 + +UNIV CONS Sequence 10 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 00 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 01 + +*/ + +static int +test_optional (void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "optional 0" }, + { NULL, 7, + "\x30\x05\xa0\x03\x02\x01\x00", + "optional 1" }, + { NULL, 7, + "\x30\x05\xa1\x03\x02\x01\x01", + "optional 2" }, + { NULL, 12, + "\x30\x0a\xa0\x03\x02\x01\x00\xa1\x03\x02\x01\x01", + "optional 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTOptional c0, c1, c2, c3; + int zero = 0; + int one = 1; + + c0.zero = NULL; + c0.one = NULL; + tests[0].val = &c0; + + c1.zero = &zero; + c1.one = NULL; + tests[1].val = &c1; + + c2.zero = NULL; + c2.one = &one; + tests[2].val = &c2; + + c3.zero = &zero; + c3.one = &one; + tests[3].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTOptional), + (generic_encode)encode_TESTOptional, + (generic_length)length_TESTOptional, + (generic_decode)decode_TESTOptional, + (generic_free)free_TESTOptional, + cmp_TESTOptional, + (generic_copy)copy_TESTOptional); + + return ret; +} static int check_fail_largetag(void) @@ -793,10 +1107,10 @@ check_fail_choice(void) struct test_case tests[] = { {NULL, 6, "\xa1\x02\x02\x01\x01", - "one too short"}, + "choice one too short"}, {NULL, 6, "\xa1\x03\x02\x02\x01", - "one too short inner"} + "choice one too short inner"} }; int ntests = sizeof(tests) / sizeof(*tests); @@ -877,6 +1191,7 @@ out: static int check_seq_of_size(void) { +#if 0 /* template */ TESTInteger integers[4] = { 1, 2, 3, 4 }; int ret; @@ -920,12 +1235,10 @@ check_seq_of_size(void) test_seq_of(TESTSeqSizeOf4, 1, &ssof4ok3); test_seq_of(TESTSeqSizeOf4, 0, &ssof4f1); } - +#endif return 0; } - - int main(int argc, char **argv) { @@ -936,6 +1249,9 @@ main(int argc, char **argv) ret += test_krb_error(); ret += test_Name(); ret += test_bit_string(); + ret += test_bit_string_rfc1510(); + ret += test_time(); + ret += test_cert(); ret += check_tag_length(); ret += test_large_tag(); @@ -943,6 +1259,7 @@ main(int argc, char **argv) ret += test_implicit(); ret += test_taglessalloc(); + ret += test_optional(); ret += check_fail_largetag(); ret += check_fail_sequence(); diff --git a/lib/asn1/check-template.c b/lib/asn1/check-template.c new file mode 100644 index 000000000..44d50168a --- /dev/null +++ b/lib/asn1/check-template.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "check-common.h" + +static int +cmp_dummy (void *a, void *b) +{ + return 0; +} + +static int +test_seqofseq(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqofseq 0" }, + { NULL, 9, + "\x30\x07\x30\x05\xa0\x03\x02\x01\x00", + "seqofseq 1" }, + { NULL, 16, + "\x30\x0e\x30\x05\xa0\x03\x02\x01\x00\x30\x05\xa0\x03\x02\x01\x01", + "seqofseq 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOfSeq c0, c1, c2; + struct TESTSeqOfSeq_val i[2]; + + i[0].zero = 0; + i[1].zero = 1; + + c0.len = 0; + c0.val = NULL; + tests[0].val = &c0; + + c1.len = 1; + c1.val = i; + tests[1].val = &c1; + + c2.len = 2; + c2.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOfSeq), + (generic_encode)encode_TESTSeqOfSeq, + (generic_length)length_TESTSeqOfSeq, + (generic_decode)decode_TESTSeqOfSeq, + (generic_free)free_TESTSeqOfSeq, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqofseq2(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqofseq2 0" }, + { NULL, 11, + "\x30\x09\x30\x07\xa0\x05\x1b\x03\x65\x74\x74", + "seqofseq2 1" }, + { NULL, 21, + "\x30\x13\x30\x07\xa0\x05\x1b\x03\x65\x74\x74\x30\x08\xa0" + "\x06\x1b\x04\x74\x76\x61\x61", + "seqofseq2 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOfSeq2 c0, c1, c2; + struct TESTSeqOfSeq2_val i[2]; + + i[0].string = "ett"; + i[1].string = "tvaa"; + + c0.len = 0; + c0.val = NULL; + tests[0].val = &c0; + + c1.len = 1; + c1.val = i; + tests[1].val = &c1; + + c2.len = 2; + c2.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOfSeq2), + (generic_encode)encode_TESTSeqOfSeq2, + (generic_length)length_TESTSeqOfSeq2, + (generic_decode)decode_TESTSeqOfSeq2, + (generic_free)free_TESTSeqOfSeq2, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqof2(void) +{ + struct test_case tests[] = { + { NULL, 4, + "\x30\x02\x30\x00", + "seqof2 1" }, + { NULL, 9, + "\x30\x07\x30\x05\x1b\x03\x66\x6f\x6f", + "seqof2 2" }, + { NULL, 14, + "\x30\x0c\x30\x0a\x1b\x03\x66\x6f\x6f\x1b\x03\x62\x61\x72", + "seqof2 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf2 c0, c1, c2; + heim_general_string i[2]; + + i[0] = "foo"; + i[1] = "bar"; + + c0.strings.val = NULL; + c0.strings.len = 0; + tests[0].val = &c0; + + c1.strings.len = 1; + c1.strings.val = i; + tests[1].val = &c1; + + c2.strings.len = 2; + c2.strings.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf2), + (generic_encode)encode_TESTSeqOf2, + (generic_length)length_TESTSeqOf2, + (generic_decode)decode_TESTSeqOf2, + (generic_free)free_TESTSeqOf2, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqof3(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqof3 0" }, + { NULL, 4, + "\x30\x02\x30\x00", + "seqof3 1" }, + { NULL, 9, + "\x30\x07\x30\x05\x1b\x03\x66\x6f\x6f", + "seqof3 2" }, + { NULL, 14, + "\x30\x0c\x30\x0a\x1b\x03\x66\x6f\x6f\x1b\x03\x62\x61\x72", + "seqof3 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf3 c0, c1, c2, c3; + struct TESTSeqOf3_strings s1, s2, s3; + heim_general_string i[2]; + + i[0] = "foo"; + i[1] = "bar"; + + c0.strings = NULL; + tests[0].val = &c0; + + s1.val = NULL; + s1.len = 0; + c1.strings = &s1; + tests[1].val = &c1; + + s2.len = 1; + s2.val = i; + c2.strings = &s2; + tests[2].val = &c2; + + s3.len = 2; + s3.val = i; + c3.strings = &s3; + tests[3].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf3), + (generic_encode)encode_TESTSeqOf3, + (generic_length)length_TESTSeqOf3, + (generic_decode)decode_TESTSeqOf3, + (generic_free)free_TESTSeqOf3, + cmp_dummy, + NULL); + return ret; +} + + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_seqofseq(); + ret += test_seqofseq2(); + ret += test_seqof2(); + ret += test_seqof3(); + + return ret; +} diff --git a/lib/asn1/cms.asn1 b/lib/asn1/cms.asn1 index 1c13d5f38..ccbe68383 100644 --- a/lib/asn1/cms.asn1 +++ b/lib/asn1/cms.asn1 @@ -4,7 +4,7 @@ CMS DEFINITIONS ::= BEGIN IMPORTS CertificateSerialNumber, AlgorithmIdentifier, Name, - Attribute, Certificate, Name, SubjectKeyIdentifier FROM rfc2459 + Attribute, Certificate, SubjectKeyIdentifier FROM rfc2459 heim_any, heim_any_set FROM heim; id-pkcs7 OBJECT IDENTIFIER ::= { iso(1) member-body(2) diff --git a/lib/asn1/der.h b/lib/asn1/der.h index 5b24b917d..f20cdb83c 100644 --- a/lib/asn1/der.h +++ b/lib/asn1/der.h @@ -94,6 +94,8 @@ typedef struct heim_ber_time_t { int bt_zone; } heim_ber_time_t; +struct asn1_template; + #include int _heim_fix_dce(size_t reallen, size_t *len); diff --git a/lib/asn1/der_copy.c b/lib/asn1/der_copy.c index 51a2a0330..a80c851f9 100644 --- a/lib/asn1/der_copy.c +++ b/lib/asn1/der_copy.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -45,6 +47,34 @@ der_copy_general_string (const heim_general_string *from, return 0; } +int +der_copy_integer (const int *from, int *to) +{ + *to = *from; + return 0; +} + +int +der_copy_unsigned (const unsigned *from, unsigned *to) +{ + *to = *from; + return 0; +} + +int +der_copy_generalized_time (const time_t *from, time_t *to) +{ + *to = *from; + return 0; +} + +int +der_copy_utctime (const time_t *from, time_t *to) +{ + *to = *from; + return 0; +} + int der_copy_utf8string (const heim_utf8_string *from, heim_utf8_string *to) { diff --git a/lib/asn1/der_free.c b/lib/asn1/der_free.c index 743bb6c46..a16ddaed1 100644 --- a/lib/asn1/der_free.c +++ b/lib/asn1/der_free.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,6 +44,31 @@ der_free_general_string (heim_general_string *str) *str = NULL; } +void +der_free_integer (int *i) +{ + *i = 0; +} + +void +der_free_unsigned (unsigned *u) +{ + *u = 0; +} + +void +der_free_generalized_time(time_t *t) +{ + *t = 0; +} + +void +der_free_utctime(time_t *t) +{ + *t = 0; +} + + void der_free_utf8string (heim_utf8_string *str) { diff --git a/lib/asn1/der_get.c b/lib/asn1/der_get.c index 5a062fb33..aee565040 100644 --- a/lib/asn1/der_get.c +++ b/lib/asn1/der_get.c @@ -305,7 +305,7 @@ der_get_octet_string_ber (const unsigned char *p, size_t len, void *ptr; ptr = realloc(data->data, data->length + datalen); - if (ptr == NULL && data->length + datalen != 0) { + if (ptr == NULL) { e = ENOMEM; goto out; } @@ -354,23 +354,21 @@ der_get_heim_integer (const unsigned char *p, size_t len, p++; data->length--; } - if (data->length) { - data->data = malloc(data->length); - if (data->data == NULL) { - data->length = 0; - if (size) - *size = 0; - return ENOMEM; - } - q = &((unsigned char*)data->data)[data->length - 1]; - p += data->length - 1; - while (q >= (unsigned char*)data->data) { - *q = *p ^ 0xff; - if (carry) - carry = !++*q; - p--; - q--; - } + data->data = malloc(data->length); + if (data->data == NULL) { + data->length = 0; + if (size) + *size = 0; + return ENOMEM; + } + q = &((unsigned char*)data->data)[data->length - 1]; + p += data->length - 1; + while (q >= (unsigned char*)data->data) { + *q = *p ^ 0xff; + if (carry) + carry = !++*q; + p--; + q--; } } else { data->negative = 0; diff --git a/lib/asn1/der_length.c b/lib/asn1/der_length.c index 5ea3a8484..688e6ba81 100644 --- a/lib/asn1/der_length.c +++ b/lib/asn1/der_length.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -112,6 +114,20 @@ der_length_len (size_t len) } } +size_t +der_length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + size_t der_length_integer (const int *data) { diff --git a/lib/asn1/der_locl.h b/lib/asn1/der_locl.h index 1f27e7290..0f65c50a2 100644 --- a/lib/asn1/der_locl.h +++ b/lib/asn1/der_locl.h @@ -52,6 +52,8 @@ #include #include #include +#include +#include "asn1-template.h" time_t _der_timegm (struct tm *); size_t _heim_len_unsigned (unsigned); diff --git a/lib/asn1/digest.asn1 b/lib/asn1/digest.asn1 index 5ee5bd4a9..027402f1e 100644 --- a/lib/asn1/digest.asn1 +++ b/lib/asn1/digest.asn1 @@ -100,6 +100,21 @@ NTLMResponse ::= SEQUENCE { tickets [3] SEQUENCE OF OCTET STRING OPTIONAL } +NTLMRequest2 ::= SEQUENCE { + loginUserName [0] UTF8String, + loginDomainName [1] UTF8String, + flags [2] INTEGER (0..4294967295), + lmchallenge [3] OCTET STRING SIZE (8), + ntChallengeResponce [4] OCTET STRING, + lmChallengeResponce [5] OCTET STRING +} + +NTLMReply ::= SEQUENCE { + success [0] BOOLEAN, + flags [1] INTEGER (0..4294967295), + sessionkey [2] OCTET STRING OPTIONAL +} + DigestReqInner ::= CHOICE { init [0] DigestInit, digestRequest [1] DigestRequest, diff --git a/lib/asn1/extra.c b/lib/asn1/extra.c index b244dbb52..95780a789 100644 --- a/lib/asn1/extra.c +++ b/lib/asn1/extra.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -40,13 +42,7 @@ int encode_heim_any(unsigned char *p, size_t len, const heim_any *data, size_t *size) { - if (data->length > len) - return ASN1_OVERFLOW; - p -= data->length; - len -= data->length; - memcpy (p+1, data->data, data->length); - *size = data->length; - return 0; + return der_put_octet_string (p, len, data, size); } int @@ -91,8 +87,7 @@ decode_heim_any(const unsigned char *p, size_t len, void free_heim_any(heim_any *data) { - free(data->data); - data->data = NULL; + der_free_octet_string(data); } size_t @@ -104,58 +99,43 @@ length_heim_any(const heim_any *data) int copy_heim_any(const heim_any *from, heim_any *to) { - to->data = malloc(from->length); - if (to->data == NULL && from->length != 0) - return ENOMEM; - memcpy(to->data, from->data, from->length); - to->length = from->length; - return 0; + return der_copy_octet_string(from, to); } int encode_heim_any_set(unsigned char *p, size_t len, const heim_any_set *data, size_t *size) { - return encode_heim_any(p, len, data, size); + return der_put_octet_string (p, len, data, size); } - int decode_heim_any_set(const unsigned char *p, size_t len, heim_any_set *data, size_t *size) { - memset(data, 0, sizeof(*data)); - data->data = malloc(len); - if (data->data == NULL && len != 0) - return ENOMEM; - data->length = len; - memcpy(data->data, p, len); - if (size) *size = len; - return 0; + return der_get_octet_string(p, len, data, size); } void free_heim_any_set(heim_any_set *data) { - free_heim_any(data); + der_free_octet_string(data); } size_t length_heim_any_set(const heim_any *data) { - return length_heim_any(data); + return data->length; } int copy_heim_any_set(const heim_any_set *from, heim_any_set *to) { - return copy_heim_any(from, to); + return der_copy_octet_string(from, to); } int heim_any_cmp(const heim_any_set *p, const heim_any_set *q) { - if (p->length != q->length) - return p->length - q->length; - return memcmp(p->data, q->data, p->length); + return der_heim_octet_string_cmp(p, q); } diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index 780c18b36..eb182e76a 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,12 +37,12 @@ RCSID("$Id$"); -FILE *headerfile, *codefile, *logfile; +FILE *privheaderfile, *headerfile, *codefile, *logfile, *templatefile; #define STEM "asn1" static const char *orig_filename; -static char *header; +static char *privheader, *header, *template; static const char *headerbase = STEM; /* @@ -66,6 +68,45 @@ add_import (const char *module) fprintf (headerfile, "#include <%s_asn1.h>\n", module); } +/* + * List of all exported symbols + */ + +struct sexport { + const char *name; + int defined; + struct sexport *next; +}; + +static struct sexport *exports = NULL; + +void +add_export (const char *name) +{ + struct sexport *tmp = emalloc (sizeof(*tmp)); + + tmp->name = name; + tmp->next = exports; + exports = tmp; +} + +int +is_export(const char *name) +{ + struct sexport *tmp; + + if (exports == NULL) /* no export list, all exported */ + return 1; + + for (tmp = exports; tmp != NULL; tmp = tmp->next) { + if (strcmp(tmp->name, name) == 0) { + tmp->defined = 1; + return 1; + } + } + return 0; +} + const char * get_filename (void) { @@ -96,6 +137,23 @@ init_generate (const char *filename, const char *base) err (1, "open %s", fn); free(fn); + /* private header file */ + asprintf(&privheader, "%s-priv.h", headerbase); + if (privheader == NULL) + errx(1, "malloc"); + asprintf(&fn, "%s-priv.hx", headerbase); + if (fn == NULL) + errx(1, "malloc"); + privheaderfile = fopen (fn, "w"); + if (privheaderfile == NULL) + err (1, "open %s", fn); + free(fn); + + /* template file */ + asprintf(&template, "%s-template.c", headerbase); + if (template == NULL) + errx(1, "malloc"); + fprintf (headerfile, "/* Generated from %s */\n" "/* Do not edit */\n\n", @@ -182,6 +240,36 @@ init_generate (const char *filename, const char *base) logfile = fopen(fn, "w"); if (logfile == NULL) err (1, "open %s", fn); + + /* if one code file, write into the one codefile */ + if (one_code_file) + return; + + templatefile = fopen (template, "w"); + if (templatefile == NULL) + err (1, "open %s", template); + + fprintf (templatefile, + "/* Generated from %s */\n" + "/* Do not edit */\n\n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n", + filename); + + fprintf (templatefile, + "#include <%s>\n" + "#include <%s>\n" + "#include \n" + "#include \n" + "#include \n", + header, privheader); + + } void @@ -190,6 +278,8 @@ close_generate (void) fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase); fclose (headerfile); + fclose (privheaderfile); + fclose (templatefile); fprintf (logfile, "\n"); fclose (logfile); } @@ -265,11 +355,14 @@ generate_header_of_codefile(const char *name) orig_filename); fprintf (codefile, - "#include <%s.h>\n", - headerbase); + "#include <%s>\n" + "#include <%s>\n", + header, privheader); fprintf (codefile, "#include \n" "#include \n" + "#include \n" + "#include \n" "#include \n\n"); } @@ -328,8 +421,6 @@ generate_constant (const Symbol *s) } fprintf (headerfile, "} */\n"); - fprintf (headerfile, "const heim_oid *oid_%s(void);\n", - s->gen_name); fprintf (headerfile, "extern const heim_oid asn1_oid_%s;\n\n", s->gen_name); @@ -346,12 +437,6 @@ generate_constant (const Symbol *s) "{ %d, oid_%s_variable_num };\n\n", s->gen_name, len, s->gen_name); - fprintf (codefile, "const heim_oid *oid_%s(void)\n" - "{\n" - "return &asn1_oid_%s;\n" - "}\n\n", - s->gen_name, s->gen_name); - free(list); if (!one_code_file) @@ -364,6 +449,33 @@ generate_constant (const Symbol *s) } } +int +is_primitive_type(int type) +{ + switch(type) { + case TInteger: + case TBoolean: + case TOctetString: + case TBitString: + case TEnumerated: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TOID: + case TUTCTime: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TNull: + return 1; + default: + return 0; + } +} + static void space(int level) { @@ -550,8 +662,24 @@ define_asn1 (int level, Type *t) } static void -define_type (int level, const char *name, Type *t, int typedefp, int preservep) +getnewbasename(char **newbasename, int typedefp, const char *basename, const char *name) { + if (typedefp) + *newbasename = strdup(name); + else { + if (name[0] == '*') + name++; + asprintf(newbasename, "%s_%s", basename, name); + } + if (*newbasename == NULL) + err(1, "malloc"); +} + +static void +define_type (int level, const char *name, const char *basename, Type *t, int typedefp, int preservep) +{ + char *newbasename = NULL; + switch (t->type) { case TType: space(level); @@ -602,16 +730,37 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) if(ASN1_TAILQ_EMPTY(t->members)) fprintf (headerfile, "heim_bit_string %s;\n", name); else { - fprintf (headerfile, "struct %s {\n", typedefp ? name : ""); + int pos = 0; + getnewbasename(&newbasename, typedefp, basename, name); + + fprintf (headerfile, "struct %s {\n", newbasename); ASN1_TAILQ_FOREACH(m, t->members, members) { char *n; + /* pad unused */ + while (pos < m->val) { + asprintf (&n, "_unused%d:1;", pos); + define_type (level + 1, n, newbasename, &i, FALSE, FALSE); + free(n); + pos++; + } + asprintf (&n, "%s:1", m->gen_name); if (n == NULL) errx(1, "malloc"); - define_type (level + 1, n, &i, FALSE, FALSE); + define_type (level + 1, n, newbasename, &i, FALSE, FALSE); free (n); + pos++; } + /* pad to 32 elements */ + while (pos < 32) { + char *n; + asprintf (&n, "_unused%d:1;", pos); + define_type (level + 1, n, newbasename, &i, FALSE, FALSE); + free(n); + pos++; + } + space(level); fprintf (headerfile, "} %s;\n\n", name); } @@ -638,8 +787,10 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) case TSequence: { Member *m; + getnewbasename(&newbasename, typedefp, basename, name); + space(level); - fprintf (headerfile, "struct %s {\n", typedefp ? name : ""); + fprintf (headerfile, "struct %s {\n", newbasename); if (t->type == TSequence && preservep) { space(level + 1); fprintf(headerfile, "heim_octet_string _save;\n"); @@ -653,10 +804,10 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) asprintf (&n, "*%s", m->gen_name); if (n == NULL) errx(1, "malloc"); - define_type (level + 1, n, m->type, FALSE, FALSE); + define_type (level + 1, n, newbasename, m->type, FALSE, FALSE); free (n); } else - define_type (level + 1, m->gen_name, m->type, FALSE, FALSE); + define_type (level + 1, m->gen_name, newbasename, m->type, FALSE, FALSE); } space(level); fprintf (headerfile, "} %s;\n", name); @@ -667,15 +818,17 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) Type i; struct range range = { 0, INT_MAX }; + getnewbasename(&newbasename, typedefp, basename, name); + i.type = TInteger; i.range = ⦥ i.members = NULL; i.constraint = NULL; space(level); - fprintf (headerfile, "struct %s {\n", typedefp ? name : ""); - define_type (level + 1, "len", &i, FALSE, FALSE); - define_type (level + 1, "*val", t->subtype, FALSE, FALSE); + fprintf (headerfile, "struct %s {\n", newbasename); + define_type (level + 1, "len", newbasename, &i, FALSE, FALSE); + define_type (level + 1, "*val", newbasename, t->subtype, FALSE, FALSE); space(level); fprintf (headerfile, "} %s;\n", name); break; @@ -693,14 +846,16 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) fprintf (headerfile, "heim_general_string %s;\n", name); break; case TTag: - define_type (level, name, t->subtype, typedefp, preservep); + define_type (level, name, basename, t->subtype, typedefp, preservep); break; case TChoice: { int first = 1; Member *m; + getnewbasename(&newbasename, typedefp, basename, name); + space(level); - fprintf (headerfile, "struct %s {\n", typedefp ? name : ""); + fprintf (headerfile, "struct %s {\n", newbasename); if (preservep) { space(level + 1); fprintf(headerfile, "heim_octet_string _save;\n"); @@ -737,10 +892,10 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) asprintf (&n, "*%s", m->gen_name); if (n == NULL) errx(1, "malloc"); - define_type (level + 2, n, m->type, FALSE, FALSE); + define_type (level + 2, n, newbasename, m->type, FALSE, FALSE); free (n); } else - define_type (level + 2, m->gen_name, m->type, FALSE, FALSE); + define_type (level + 2, m->gen_name, newbasename, m->type, FALSE, FALSE); } space(level + 1); fprintf (headerfile, "} u;\n"); @@ -787,6 +942,8 @@ define_type (int level, const char *name, Type *t, int typedefp, int preservep) default: abort (); } + if (newbasename) + free(newbasename); } static void @@ -800,27 +957,61 @@ generate_type_header (const Symbol *s) fprintf (headerfile, "\n*/\n\n"); fprintf (headerfile, "typedef "); - define_type (0, s->gen_name, s->type, TRUE, preservep); + define_type (0, s->gen_name, s->gen_name, s->type, TRUE, preservep); fprintf (headerfile, "\n"); } - void generate_type (const Symbol *s) { + FILE *h; + if (!one_code_file) generate_header_of_codefile(s->gen_name); generate_type_header (s); - generate_type_encode (s); - generate_type_decode (s); - generate_type_free (s); - generate_type_length (s); - generate_type_copy (s); + + if (template_flag) + generate_template(s); + + if (template_flag == 0 || is_template_compat(s) == 0) { + generate_type_encode (s); + generate_type_decode (s); + generate_type_free (s); + generate_type_length (s); + generate_type_copy (s); + } generate_type_seq (s); generate_glue (s->type, s->gen_name); - fprintf(headerfile, "\n\n"); + + /* generate prototypes */ + + if (is_export(s->name)) + h = headerfile; + else + h = privheaderfile; + + fprintf (h, + "int " + "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n", + s->gen_name, s->gen_name); + fprintf (h, + "int " + "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n", + s->gen_name, s->gen_name); + fprintf (h, + "size_t length_%s(const %s *);\n", + s->gen_name, s->gen_name); + fprintf (h, + "int copy_%s (const %s *, %s *);\n", + s->gen_name, s->gen_name, s->gen_name); + fprintf (h, + "void free_%s (%s *);\n", + s->gen_name, s->gen_name); + + + fprintf(h, "\n\n"); if (!one_code_file) { fprintf(codefile, "\n\n"); diff --git a/lib/asn1/gen_copy.c b/lib/asn1/gen_copy.c index f28647d19..5e228d0e6 100644 --- a/lib/asn1/gen_copy.c +++ b/lib/asn1/gen_copy.c @@ -228,10 +228,6 @@ generate_type_copy (const Symbol *s) used_fail = 0; - fprintf (headerfile, - "int copy_%s (const %s *, %s *);\n", - s->gen_name, s->gen_name, s->gen_name); - fprintf (codefile, "int\n" "copy_%s(const %s *from, %s *to)\n" "{\n" diff --git a/lib/asn1/gen_decode.c b/lib/asn1/gen_decode.c index 327de4c98..043cfac2d 100644 --- a/lib/asn1/gen_decode.c +++ b/lib/asn1/gen_decode.c @@ -56,33 +56,6 @@ decode_primitive (const char *typename, const char *name, const char *forwstr) #endif } -static int -is_primitive_type(int type) -{ - switch(type) { - case TInteger: - case TBoolean: - case TOctetString: - case TBitString: - case TEnumerated: - case TGeneralizedTime: - case TGeneralString: - case TTeletexString: - case TOID: - case TUTCTime: - case TUTF8String: - case TPrintableString: - case TIA5String: - case TBMPString: - case TUniversalString: - case TVisibleString: - case TNull: - return 1; - default: - return 0; - } -} - static void find_tag (const Type *t, Der_class *cl, Der_type *ty, unsigned *tag) @@ -630,7 +603,7 @@ decode_type (const char *name, const Type *t, int optional, fprintf(codefile, "else {\n" "(%s)->u.%s.data = calloc(1, len);\n" - "if ((%s)->u.%s.data == NULL && len != 0) {\n" + "if ((%s)->u.%s.data == NULL) {\n" "e = ENOMEM; %s;\n" "}\n" "(%s)->u.%s.length = len;\n" @@ -694,11 +667,6 @@ generate_type_decode (const Symbol *s) { int preserve = preserve_type(s->name) ? TRUE : FALSE; - fprintf (headerfile, - "int " - "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n", - s->gen_name, s->gen_name); - fprintf (codefile, "int\n" "decode_%s(const unsigned char *p," " size_t len, %s *data, size_t *size)\n" @@ -744,7 +712,7 @@ generate_type_decode (const Symbol *s) if (preserve) fprintf (codefile, "data->_save.data = calloc(1, ret);\n" - "if (data->_save.data == NULL && ret != 0) { \n" + "if (data->_save.data == NULL) { \n" "e = ENOMEM; goto fail; \n" "}\n" "data->_save.length = ret;\n" diff --git a/lib/asn1/gen_encode.c b/lib/asn1/gen_encode.c index 012d4677f..e9b4e7cd1 100644 --- a/lib/asn1/gen_encode.c +++ b/lib/asn1/gen_encode.c @@ -508,11 +508,6 @@ encode_type (const char *name, const Type *t, const char *tmpstr) void generate_type_encode (const Symbol *s) { - fprintf (headerfile, - "int " - "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n", - s->gen_name, s->gen_name); - fprintf (codefile, "int\n" "encode_%s(unsigned char *p, size_t len," " const %s *data, size_t *size)\n" diff --git a/lib/asn1/gen_free.c b/lib/asn1/gen_free.c index 48fe8cd78..dc612074a 100644 --- a/lib/asn1/gen_free.c +++ b/lib/asn1/gen_free.c @@ -180,18 +180,14 @@ free_type (const char *name, const Type *t, int preserve) void generate_type_free (const Symbol *s) { - int preserve = preserve_type(s->name) ? TRUE : FALSE; - - fprintf (headerfile, - "void free_%s (%s *);\n", - s->gen_name, s->gen_name); - - fprintf (codefile, "void\n" - "free_%s(%s *data)\n" - "{\n", - s->gen_name, s->gen_name); - - free_type ("data", s->type, preserve); - fprintf (codefile, "}\n\n"); + int preserve = preserve_type(s->name) ? TRUE : FALSE; + + fprintf (codefile, "void\n" + "free_%s(%s *data)\n" + "{\n", + s->gen_name, s->gen_name); + + free_type ("data", s->type, preserve); + fprintf (codefile, "}\n\n"); } diff --git a/lib/asn1/gen_glue.c b/lib/asn1/gen_glue.c index 9f7eca45e..32680cef4 100644 --- a/lib/asn1/gen_glue.c +++ b/lib/asn1/gen_glue.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -70,7 +72,8 @@ generate_int2 (const Type *t, const char *gen_name) fprintf (codefile, "%s int2%s(unsigned n)\n" "{\n" - "\t%s flags;\n\n", + "\t%s flags;\n\n" + "\tmemset(&flags, 0, sizeof(flags));\n\n", gen_name, gen_name, gen_name); if(t->members) { @@ -92,9 +95,17 @@ generate_units (const Type *t, const char *gen_name) { Member *m; - fprintf (headerfile, - "const struct units * asn1_%s_units(void);", - gen_name); + if (template_flag) { + fprintf (headerfile, + "extern const struct units *asn1_%s_table_units;\n", + gen_name); + fprintf (headerfile, "#define asn1_%s_units() (asn1_%s_table_units)\n", + gen_name, gen_name); + } else { + fprintf (headerfile, + "const struct units * asn1_%s_units(void);", + gen_name); + } fprintf (codefile, "static struct units %s_units[] = {\n", @@ -111,11 +122,16 @@ generate_units (const Type *t, const char *gen_name) "\t{NULL,\t0}\n" "};\n\n"); - fprintf (codefile, - "const struct units * asn1_%s_units(void){\n" - "return %s_units;\n" - "}\n\n", - gen_name, gen_name); + if (template_flag) + fprintf (codefile, + "const struct units * asn1_%s_table_units = %s_units;\n", + gen_name, gen_name); + else + fprintf (codefile, + "const struct units * asn1_%s_units(void){\n" + "return %s_units;\n" + "}\n\n", + gen_name, gen_name); } diff --git a/lib/asn1/gen_length.c b/lib/asn1/gen_length.c index e1f045c4c..da6d26e37 100644 --- a/lib/asn1/gen_length.c +++ b/lib/asn1/gen_length.c @@ -43,6 +43,7 @@ length_primitive (const char *typename, fprintf (codefile, "%s += der_length_%s(%s);\n", variable, typename, name); } +/* XXX same as der_length_tag */ static size_t length_tag(unsigned int tag) { @@ -269,10 +270,6 @@ length_type (const char *name, const Type *t, void generate_type_length (const Symbol *s) { - fprintf (headerfile, - "size_t length_%s(const %s *);\n", - s->gen_name, s->gen_name); - fprintf (codefile, "size_t\n" "length_%s(const %s *data)\n" diff --git a/lib/asn1/gen_locl.h b/lib/asn1/gen_locl.h index 2bb64b5a3..9e87b0c57 100644 --- a/lib/asn1/gen_locl.h +++ b/lib/asn1/gen_locl.h @@ -52,6 +52,7 @@ #include "symbol.h" #include "asn1-common.h" #include "der.h" +#include "der-private.h" void generate_type (const Symbol *); void generate_constant (const Symbol *); @@ -74,7 +75,10 @@ void init_generate (const char *, const char *); const char *get_filename (void); void close_generate(void); void add_import(const char *); +void add_export(const char *); +int is_export(const char *); int yyparse(void); +int is_primitive_type(int); int preserve_type(const char *); int seq_type(const char *); @@ -82,9 +86,14 @@ int seq_type(const char *); void generate_header_of_codefile(const char *); void close_codefile(void); +int is_template_compat (const Symbol *); +void generate_template(const Symbol *); +void gen_template_import(const Symbol *); -extern FILE *headerfile, *codefile, *logfile; + +extern FILE *privheaderfile, *headerfile, *codefile, *logfile, *templatefile; extern int support_ber; +extern int template_flag; extern int rfc1510_bitstring; extern int one_code_file; diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c new file mode 100644 index 000000000..8d4d9b49c --- /dev/null +++ b/lib/asn1/gen_template.c @@ -0,0 +1,894 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +static const char *symbol_name(const char *, const Type *); +static void generate_template_type(const char *, const char **, const char *, const char *, const char *, + Type *, int, int, int); + +static const char * +ttype_symbol(const char *basename, const Type *t) +{ + return t->symbol->gen_name; +} + +static const char * +integer_symbol(const char *basename, const Type *t) +{ + if (t->members) + return "int"; /* XXX enum foo */ + else if (t->range == NULL) + return "heim_integer"; + else if (t->range->min == INT_MIN && t->range->max == INT_MAX) + return "int"; + else if (t->range->min == 0 && t->range->max == UINT_MAX) + return "unsigned"; + else if (t->range->min == 0 && t->range->max == INT_MAX) + return "unsigned"; + else + abort(); +} + +static const char * +boolean_symbol(const char *basename, const Type *t) +{ + return "int"; +} + + +static const char * +octetstring_symbol(const char *basename, const Type *t) +{ + return "heim_octet_string"; +} + +static const char * +sequence_symbol(const char *basename, const Type *t) +{ + return basename; +} + +static const char * +time_symbol(const char *basename, const Type *t) +{ + return "time_t"; +} + +static const char * +tag_symbol(const char *basename, const Type *t) +{ + return symbol_name(basename, t->subtype); +} + +static const char * +generalstring_symbol(const char *basename, const Type *t) +{ + return "heim_general_string"; +} + +static const char * +printablestring_symbol(const char *basename, const Type *t) +{ + return "heim_printable_string"; +} + +static const char * +ia5string_symbol(const char *basename, const Type *t) +{ + return "heim_ia5_string"; +} + +static const char * +visiblestring_symbol(const char *basename, const Type *t) +{ + return "heim_visible_string"; +} + +static const char * +utf8string_symbol(const char *basename, const Type *t) +{ + return "heim_utf8_string"; +} + +static const char * +bmpstring_symbol(const char *basename, const Type *t) +{ + return "heim_bmp_string"; +} + +static const char * +universalstring_symbol(const char *basename, const Type *t) +{ + return "heim_universal_string"; +} + +static const char * +oid_symbol(const char *basename, const Type *t) +{ + return "heim_oid"; +} + +static const char * +bitstring_symbol(const char *basename, const Type *t) +{ + if (t->members) + return basename; + return "heim_bit_string"; +} + + + +struct { + enum typetype type; + const char *(*symbol_name)(const char *, const Type *); + int is_struct; +} types[] = { + { TBMPString, bmpstring_symbol, 0 }, + { TBitString, bitstring_symbol, 0 }, + { TBoolean, boolean_symbol, 0 }, + { TGeneralString, generalstring_symbol, 0 }, + { TGeneralizedTime, time_symbol, 0 }, + { TIA5String, ia5string_symbol, 0 }, + { TInteger, integer_symbol, 0 }, + { TOID, oid_symbol, 0 }, + { TOctetString, octetstring_symbol, 0 }, + { TPrintableString, printablestring_symbol, 0 }, + { TSequence, sequence_symbol, 1 }, + { TSequenceOf, tag_symbol, 1 }, + { TSetOf, tag_symbol, 1 }, + { TTag, tag_symbol, 1 }, + { TType, ttype_symbol, 1 }, + { TUTCTime, time_symbol, 0 }, + { TUniversalString, universalstring_symbol, 0 }, + { TVisibleString, visiblestring_symbol, 0 }, + { TUTF8String, utf8string_symbol, 0 }, + { TChoice, sequence_symbol, 1 }, + { TNull, integer_symbol, 1 } +}; + +static FILE * +get_code_file(void) +{ + if (!one_code_file) + return templatefile; + return codefile; +} + + +static int +is_supported_type_p(const Type *t) +{ + size_t i; + + for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) + if (t->type == types[i].type) + return 1; + return 0; +} + +int +is_template_compat (const Symbol *s) +{ + return is_supported_type_p(s->type); +} + +static const char * +symbol_name(const char *basename, const Type *t) +{ + size_t i; + + for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) + if (t->type == types[i].type) + return (types[i].symbol_name)(basename, t); + printf("unknown der type: %d\n", t->type); + exit(1); +} + + +static char * +partial_offset(const char *basetype, const char *name, int need_offset) +{ + char *str; + if (name == NULL || need_offset == 0) + return strdup("0"); + asprintf(&str, "offsetof(struct %s, %s)", basetype, name); + return str; +} + +struct template { + char *line; + char *tt; + char *offset; + char *ptr; + ASN1_TAILQ_ENTRY(template) members; +}; + +ASN1_TAILQ_HEAD(templatehead, template); + +struct tlist { + char *name; + char *header; + struct templatehead template; + ASN1_TAILQ_ENTRY(tlist) tmembers; +}; + +ASN1_TAILQ_HEAD(tlisthead, tlist); + +static void tlist_header(struct tlist *, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); +static struct template * + add_line(struct templatehead *, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); +static int tlist_cmp(const struct tlist *, const struct tlist *); + +static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__((__format__(__printf__, 4, 5))); + + +static struct tlisthead tlistmaster = ASN1_TAILQ_HEAD_INITIALIZER(tlistmaster); +static unsigned long numdups = 0; + +static struct tlist * +tlist_new(const char *name) +{ + struct tlist *tl = calloc(1, sizeof(*tl)); + tl->name = strdup(name); + ASN1_TAILQ_INIT(&tl->template); + return tl; +} + +static void +tlist_header(struct tlist *t, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vasprintf(&t->header, fmt, ap); + va_end(ap); +} + +static unsigned long +tlist_count(struct tlist *tl) +{ + unsigned int count = 0; + struct template *q; + + ASN1_TAILQ_FOREACH(q, &tl->template, members) { + count++; + } + return count; +} + +static void +tlist_add(struct tlist *tl) +{ + ASN1_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers); +} + +static void +tlist_print(struct tlist *tl) +{ + struct template *q; + unsigned int i = 1; + FILE *f = get_code_file(); + + fprintf(f, "static const struct asn1_template asn1_%s[] = {\n", tl->name); + fprintf(f, "/* 0 */ %s,\n", tl->header); + ASN1_TAILQ_FOREACH(q, &tl->template, members) { + int last = (ASN1_TAILQ_LAST(&tl->template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); +} + +static struct tlist * +tlist_find_by_name(const char *name) +{ + struct tlist *ql; + ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (strcmp(ql->name, name) == 0) + return ql; + } + return NULL; +} + +static int +tlist_cmp_name(const char *tname, const char *qname) +{ + struct tlist *tl = tlist_find_by_name(tname); + struct tlist *ql = tlist_find_by_name(qname); + return tlist_cmp(tl, ql); +} + +static int +tlist_cmp(const struct tlist *tl, const struct tlist *ql) +{ + int ret; + struct template *t, *q; + + ret = strcmp(tl->header, ql->header); + if (ret) return ret; + + q = ASN1_TAILQ_FIRST(&ql->template); + ASN1_TAILQ_FOREACH(t, &tl->template, members) { + if (q == NULL) return 1; + + if (t->ptr == NULL || q->ptr == NULL) { + ret = strcmp(t->line, q->line); + if (ret) return ret; + } else { + ret = strcmp(t->tt, q->tt); + if (ret) return ret; + + ret = strcmp(t->offset, q->offset); + if (ret) return ret; + + if ((ret = strcmp(t->ptr, q->ptr)) != 0 || + (ret = tlist_cmp_name(t->ptr, q->ptr)) != 0) + return ret; + } + q = ASN1_TAILQ_NEXT(q, members); + } + if (q != NULL) return -1; + return 0; +} + + +static const char * +tlist_find_dup(const struct tlist *tl) +{ + struct tlist *ql; + + ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (tlist_cmp(ql, tl) == 0) { + numdups++; + return ql->name; + } + } + return NULL; +} + + +/* + * + */ + +static struct template * +add_line(struct templatehead *t, const char *fmt, ...) +{ + struct template *q = calloc(1, sizeof(*q)); + va_list ap; + va_start(ap, fmt); + vasprintf(&q->line, fmt, ap); + va_end(ap); + ASN1_TAILQ_INSERT_TAIL(t, q, members); + return q; +} + +static void +add_line_pointer(struct templatehead *t, + const char *ptr, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt; + + va_start(ap, ttfmt); + vasprintf(&tt, ttfmt, ap); + va_end(ap); + + q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(ptr); +} + +static int +use_extern(const Symbol *s) +{ + if (s->type == NULL) + return 1; + return 0; +} + +static int +is_struct(Type *t, int isstruct) +{ + size_t i; + + if (t->type == TType) + return 0; + if (t->type == TSequence || t->type == TSet || t->type == TChoice) + return 1; + if (t->type == TTag) + return is_struct(t->subtype, isstruct); + + for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) { + if (t->type == types[i].type) { + if (types[i].is_struct == 0) + return 0; + else + break; + } + } + + return isstruct; +} + +static const Type * +compact_tag(const Type *t) +{ + while (t->type == TTag) + t = t->subtype; + return t; +} + +static void +template_members(struct templatehead *temp, const char *basetype, const char *name, const Type *t, int optional, int isstruct, int need_offset) +{ + char *poffset = NULL; + + if (optional && t->type != TTag && t->type != TType) + errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name); + + poffset = partial_offset(basetype, name, need_offset); + + switch (t->type) { + case TType: + if (use_extern(t->symbol)) { + add_line(temp, "{ A1_OP_TYPE_EXTERN %s, %s, &asn1_extern_%s}", + optional ? "|A1_FLAG_OPTIONAL" : "", + poffset, t->symbol->gen_name); + } else { + add_line_pointer(temp, t->symbol->gen_name, poffset, + "A1_OP_TYPE %s", optional ? "|A1_FLAG_OPTIONAL" : ""); + } + break; + case TInteger: { + char *itype; + + if (t->members) + itype = "IMEMBER"; + else if (t->range == NULL) + itype = "HEIM_INTEGER"; + else if (t->range->min == INT_MIN && t->range->max == INT_MAX) + itype = "INTEGER"; + else if (t->range->min == 0 && t->range->max == UINT_MAX) + itype = "UNSIGNED"; + else if (t->range->min == 0 && t->range->max == INT_MAX) + itype = "UNSIGNED"; + else + errx(1, "%s: unsupported range %d -> %d", + name, t->range->min, t->range->max); + + add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset); + break; + } + case TGeneralString: + add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset); + break; + case TTeletexString: + add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset); + break; + case TPrintableString: + add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset); + break; + case TOctetString: + add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset); + break; + case TIA5String: + add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset); + break; + case TBMPString: + add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset); + break; + case TUniversalString: + add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset); + break; + case TVisibleString: + add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset); + break; + case TUTF8String: + add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset); + break; + case TGeneralizedTime: + add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset); + break; + case TUTCTime: + add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset); + break; + case TBoolean: + add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset); + break; + case TOID: + add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset); + break; + case TNull: + break; + case TBitString: { + struct templatehead template = ASN1_TAILQ_HEAD_INITIALIZER(template); + struct template *q; + Member *m; + size_t count = 0, i; + char *bname; + FILE *f = get_code_file(); + + if (ASN1_TAILQ_EMPTY(t->members)) { + add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset); + break; + } + + asprintf(&bname, "bmember_%s_%lu", name ? name : "", (unsigned long)t); + output_name(bname); + + ASN1_TAILQ_FOREACH(m, t->members, members) { + add_line(&template, "{ 0, %d, 0 } /* %s */", m->val, m->gen_name); + } + + ASN1_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname); + fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)%lu) },\n", + rfc1510_bitstring ? "|A1_HBF_RFC1510" : "", + basetype, (unsigned long)count); + i = 1; + ASN1_TAILQ_FOREACH(q, &template, members) { + int last = (ASN1_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname); + + free(bname); + + break; + } + case TSequence: { + Member *m; + + ASN1_TAILQ_FOREACH(m, t->members, members) { + char *newbasename; + + if (m->ellipsis) + continue; + + if (name) + asprintf(&newbasename, "%s_%s", basetype, name); + else + newbasename = strdup(basetype); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, isstruct, 1); + + free(newbasename); + } + + break; + } + case TTag: { + char *tname, *elname; + const char *sename, *dupname; + int subtype_is_struct = is_struct(t->subtype, isstruct); + + if (subtype_is_struct) + sename = basetype; + else + sename = symbol_name(basetype, t->subtype); + + asprintf(&tname, "tag_%s_%lu", name ? name : "", (unsigned long)t); + output_name(tname); + + asprintf(&elname, "%s_%s", basetype, tname); + + generate_template_type(elname, &dupname, NULL, sename, name, + t->subtype, 0, subtype_is_struct, 0); + + add_line_pointer(temp, dupname, poffset, + "A1_TAG_T(%s,%s,%s)%s", + classname(t->tag.tagclass), + is_primitive_type(t->subtype->type) ? "PRIM" : "CONS", + valuename(t->tag.tagclass, t->tag.tagvalue), + optional ? "|A1_FLAG_OPTIONAL" : ""); + + free(tname); + free(elname); + + break; + } + case TSetOf: + case TSequenceOf: { + const char *type, *tname, *dupname; + char *sename, *elname; + int subtype_is_struct = is_struct(t->subtype, 0); + + if (name && subtype_is_struct) { + tname = "seofTstruct"; + asprintf(&sename, "%s_%s_val", + basetype, name); + } else if (subtype_is_struct) { + tname = "seofTstruct"; + asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)); + } else { + if (name) + tname = name; + else + tname = "seofTstruct"; + sename = strdup(symbol_name(basetype, t->subtype)); + } + + if (t->type == TSetOf) type = "A1_OP_SETOF"; + else if (t->type == TSequenceOf) type = "A1_OP_SEQOF"; + else abort(); + + asprintf(&elname, "%s_%s_%lu", basetype, tname, (unsigned long)t); + + generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype, + 0, subtype_is_struct, need_offset); + + add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname); + free(sename); + break; + } + case TChoice: { + struct templatehead template = ASN1_TAILQ_HEAD_INITIALIZER(template); + struct template *q; + size_t count = 0, i; + char *tname; + FILE *f = get_code_file(); + Member *m; + int ellipsis = 0; + char *e; + + asprintf(&tname, "asn1_choice_%s_%s%x", + basetype, name ? name : "", (unsigned int)(uintptr_t)t); + + ASN1_TAILQ_FOREACH(m, t->members, members) { + const char *dupname; + char *elname; + char *newbasename; + int subtype_is_struct; + + if (m->ellipsis) { + ellipsis = 1; + continue; + } + + subtype_is_struct = is_struct(m->type, 0); + + asprintf(&elname, "%s_choice_%s", basetype, m->gen_name); + + if (subtype_is_struct) + asprintf(&newbasename, "%s_%s", basetype, m->gen_name); + else + newbasename = strdup(basetype); + + generate_template_type(elname, &dupname, NULL, + symbol_name(newbasename, m->type), + NULL, m->type, 0, subtype_is_struct, 1); + + add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }", + m->label, isstruct ? "struct " : "", + basetype, m->gen_name, + dupname); + + free(elname); + free(newbasename); + } + + if (ellipsis) { + asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype); + } else + e = NULL; + + ASN1_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template %s[] = {\n", tname); + fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)%lu) },\n", + e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count); + i = 1; + ASN1_TAILQ_FOREACH(q, &template, members) { + int last = (ASN1_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname); + + free(e); + free(tname); + break; + } + default: + abort (); + } + if (poffset) + free(poffset); +} + +static void +gen_extern_stubs(FILE *f, const char *name) +{ + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s = {\n" + "\t(asn1_type_encode)encode_%s,\n" + "\t(asn1_type_decode)decode_%s,\n" + "\t(asn1_type_length)length_%s,\n" + "\t(asn1_type_copy)copy_%s,\n" + "\t(asn1_type_release)free_%s,\n" + "\tsizeof(%s)\n" + "};\n", + name, name, name, name, + name, name, name); +} + +void +gen_template_import(const Symbol *s) +{ + FILE *f = get_code_file(); + + if (template_flag == 0) + return; + + gen_extern_stubs(f, s->gen_name); +} + +static void +generate_template_type(const char *varname, + const char **dupname, + const char *symname, + const char *basetype, + const char *name, + Type *type, + int optional, int isstruct, int need_offset) +{ + struct tlist *tl; + const char *dup; + int have_ellipsis = 0; + + tl = tlist_new(varname); + + template_members(&tl->template, basetype, name, type, optional, isstruct, need_offset); + + /* if its a sequence or set type, check if there is a ellipsis */ + if (type->type == TSequence || type->type == TSet) { + Member *m; + ASN1_TAILQ_FOREACH(m, type->members, members) { + if (m->ellipsis) + have_ellipsis = 1; + } + } + + if (ASN1_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull) + errx(1, "Tag %s...%s with no content ?", basetype, name ? name : ""); + + tlist_header(tl, "{ 0%s%s, sizeof(%s%s), ((void *)%lu) }", + (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "", + have_ellipsis ? "|A1_HF_ELLIPSIS" : "", + isstruct ? "struct " : "", basetype, tlist_count(tl)); + + dup = tlist_find_dup(tl); + if (dup) { + if (strcmp(dup, tl->name) == 0) + errx(1, "found dup of ourself"); + *dupname = dup; + } else { + *dupname = tl->name; + tlist_print(tl); + tlist_add(tl); + } +} + + +void +generate_template(const Symbol *s) +{ + FILE *f = get_code_file(); + const char *dupname; + + if (use_extern(s)) { + gen_extern_stubs(f, s->gen_name); + return; + } + + generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1); + + fprintf(f, + "\n" + "int\n" + "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n" + "{\n" + " return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname, + support_ber ? "A1_PF_ALLOW_BER" : "0"); + + fprintf(f, + "\n" + "int\n" + "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n" + "{\n" + " return _asn1_encode(asn1_%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "size_t\n" + "length_%s(const %s *data)\n" + "{\n" + " return _asn1_length(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); + + + fprintf(f, + "\n" + "void\n" + "free_%s(%s *data)\n" + "{\n" + " _asn1_free(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "int\n" + "copy_%s(const %s *from, %s *to)\n" + "{\n" + " return _asn1_copy_top(asn1_%s, from, to);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + s->gen_name, + dupname); +} diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index adc09ac68..ed663fcf5 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -2,6 +2,78 @@ KERBEROS5 DEFINITIONS ::= BEGIN +EXPORTS + AD-AND-OR, + AD-IF-RELEVANT, + AD-KDCIssued, + AD-LoginAlias, + AP-REP, + AP-REQ, + AS-REP, + AS-REQ, + AUTHDATA-TYPE, + Authenticator, + AuthorizationData, + AuthorizationDataElement, + CKSUMTYPE, + ChangePasswdDataMS, + Checksum, + ENCTYPE, + ETYPE-INFO, + ETYPE-INFO-ENTRY, + ETYPE-INFO2, + ETYPE-INFO2-ENTRY, + EncAPRepPart, + EncASRepPart, + EncKDCRepPart, + EncKrbCredPart, + EncKrbPrivPart, + EncTGSRepPart, + EncTicketPart, + EncryptedData, + EncryptionKey, + EtypeList, + HostAddress, + HostAddresses, + KDC-REQ-BODY, + KDCOptions, + KDC-REP, + KRB-CRED, + KRB-ERROR, + KRB-PRIV, + KRB-SAFE, + KRB-SAFE-BODY, + KRB5SignedPath, + KRB5SignedPathData, + KRB5SignedPathPrincipals, + KerberosString, + KerberosTime, + KrbCredInfo, + LR-TYPE, + LastReq, + METHOD-DATA, + NAME-TYPE, + PA-ClientCanonicalized, + PA-ClientCanonicalizedNames, + PA-DATA, + PA-ENC-TS-ENC, + PA-PAC-REQUEST, + PA-S4U2Self, + PA-SERVER-REFERRAL-DATA, + PA-ServerReferralData, + PA-SvrReferralData, + PADATA-TYPE, + Principal, + PrincipalName, + Principals, + Realm, + TGS-REP, + TGS-REQ, + Ticket, + TicketFlags, + TransitedEncoding, + TypedData + ; NAME-TYPE ::= INTEGER { KRB5_NT_UNKNOWN(0), -- Name type not known @@ -256,11 +328,7 @@ KDCOptions ::= BIT STRING { proxy(4), allow-postdate(5), postdated(6), - unused7(7), renewable(8), - unused9(9), - unused10(10), - unused11(11), request-anonymous(14), canonicalize(15), constrained-delegation(16), -- ms extension diff --git a/lib/asn1/main.c b/lib/asn1/main.c index 5cef970d7..a99e69d0f 100644 --- a/lib/asn1/main.c +++ b/lib/asn1/main.c @@ -63,12 +63,14 @@ seq_type(const char *p) } int support_ber; +int template_flag; int rfc1510_bitstring; int one_code_file; char *option_file; int version_flag; int help_flag; struct getargs args[] = { + { "template", 0, arg_flag, &template_flag }, { "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring }, { "decode-dce-ber", 0, arg_flag, &support_ber }, { "support-ber", 0, arg_flag, &support_ber }, diff --git a/lib/asn1/rfc2459.opt b/lib/asn1/rfc2459.opt new file mode 100644 index 000000000..d3afc6739 --- /dev/null +++ b/lib/asn1/rfc2459.opt @@ -0,0 +1,6 @@ +--preserve-binary=TBSCertificate +--preserve-binary=TBSCRLCertList +--preserve-binary=Name +--sequence=GeneralNames +--sequence=Extensions +--sequence=CRLDistributionPoints diff --git a/lib/asn1/symbol.c b/lib/asn1/symbol.c index ac00bdc6c..e65876a03 100644 --- a/lib/asn1/symbol.c +++ b/lib/asn1/symbol.c @@ -34,8 +34,6 @@ #include "gen_locl.h" #include "lex.h" -RCSID("$Id$"); - static Hashtab *htab; static int @@ -68,7 +66,7 @@ output_name(char *s) char *p; for (p = s; *p; ++p) - if (*p == '-') + if (*p == '-' || *p == '.') *p = '_'; } diff --git a/lib/asn1/template.c b/lib/asn1/template.c new file mode 100644 index 000000000..1a39677c6 --- /dev/null +++ b/lib/asn1/template.c @@ -0,0 +1,1119 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include + +#if 0 +#define ABORT_ON_ERROR() abort() +#else +#define ABORT_ON_ERROR() do { } while(0) +#endif + +#define DPOC(data,offset) ((const void *)(((const unsigned char *)data) + offset)) +#define DPO(data,offset) ((void *)(((unsigned char *)data) + offset)) + + +struct asn1_type_func prim[] = { +#define el(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } +#define elber(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name##_ber, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } + el(integer, int), + el(heim_integer, heim_integer), + el(integer, int), + el(unsigned, unsigned), + el(general_string, heim_general_string), + el(octet_string, heim_octet_string), + elber(octet_string, heim_octet_string), + el(ia5_string, heim_ia5_string), + el(bmp_string, heim_bmp_string), + el(universal_string, heim_universal_string), + el(printable_string, heim_printable_string), + el(visible_string, heim_visible_string), + el(utf8string, heim_utf8_string), + el(generalized_time, time_t), + el(utctime, time_t), + el(bit_string, heim_bit_string), + { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean, + (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer, + (asn1_type_release)der_free_integer, sizeof(int) + }, + el(oid, heim_oid), + el(general_string, heim_general_string), +#undef el +#undef elber +}; + +static size_t +sizeofType(const struct asn1_template *t) +{ + return t->offset; +} + +/* + * Here is abstraction to not so well evil fact of bit fields in C, + * they are endian dependent, so when getting and setting bits in the + * host local structure we need to know the endianness of the host. + * + * Its not the first time in Heimdal this have bitten us, and some day + * we'll grow up and use #defined constant, but bit fields are still + * so pretty and shiny. + */ + +static void +bmember_get_bit(const unsigned char *p, void *data, + unsigned int bit, size_t size) +{ + unsigned int localbit = bit % 8; + if ((*p >> (7 - localbit)) & 1) { +#ifdef WORDS_BIGENDIAN + *(unsigned int *)data |= (1 << ((size * 8) - bit - 1)); +#else + *(unsigned int *)data |= (1 << bit); +#endif + } +} + +static int +bmember_isset_bit(const void *data, unsigned int bit, size_t size) +{ +#ifdef WORDS_BIGENDIAN + if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1))) + return 1; + return 0; +#else + if ((*(unsigned int *)data) & (1 << bit)) + return 1; + return 0; +#endif +} + +static void +bmember_put_bit(unsigned char *p, const void *data, unsigned int bit, + size_t size, unsigned int *bitset) +{ + unsigned int localbit = bit % 8; + + if (bmember_isset_bit(data, bit, size)) { + *p |= (1 << (7 - localbit)); + if (*bitset == 0) + *bitset = (7 - localbit) + 1; + } +} + +int +_asn1_decode(const struct asn1_template *t, unsigned flags, + const unsigned char *p, size_t len, void *data, size_t *size) +{ + size_t elements = A1_HEADER_LEN(t); + size_t oldlen = len; + int ret = 0; + const unsigned char *startp = NULL; + unsigned int template_flags = t->tt; + + /* skip over header */ + t++; + + if (template_flags & A1_HF_PRESERVE) + startp = p; + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize, size; + void *el = DPO(data, t->offset); + void **pel = (void **)el; + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + size = sizeofType(t->ptr); + } else { + const struct asn1_type_func *f = t->ptr; + size = f->size; + } + + if (t->tt & A1_FLAG_OPTIONAL) { + *pel = calloc(1, size); + if (*pel == NULL) + return ENOMEM; + el = *pel; + } + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->decode)(p, len, el, &newsize); + } + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + free(*pel); + *pel = NULL; + break; + } + return ret; + } + p += newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + Der_type dertype; + size_t newsize; + size_t datalen, l; + void *olddata = data; + int is_indefinite = 0; + int subflags = flags; + + ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt), + &dertype, A1_TAG_TAG(t->tt), + &datalen, &l); + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) + break; + return ret; + } + + p += l; len -= l; + + /* + * Only allow indefinite encoding for OCTET STRING and BER + * for now. Should handle BIT STRING too. + */ + + if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) { + const struct asn1_template *subtype = t->ptr; + subtype++; /* skip header */ + + if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) && + A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING) + subflags |= A1_PF_INDEFINTE; + } + + if (datalen == ASN1_INDEFINITE) { + if ((flags & A1_PF_ALLOW_BER) == 0) + return ASN1_GOT_BER; + is_indefinite = 1; + datalen = len; + if (datalen < 2) + return ASN1_OVERRUN; + /* hide EndOfContent for sub-decoder, catching it below */ + datalen -= 2; + } else if (datalen > len) + return ASN1_OVERRUN; + + data = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + size_t ellen = sizeofType(t->ptr); + + *el = calloc(1, ellen); + if (*el == NULL) + return ENOMEM; + data = *el; + } + + ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize); + if (ret) + return ret; + + if (newsize != datalen) + return ASN1_EXTRA_DATA; + + len -= datalen; + p += datalen; + + /* + * Indefinite encoding needs a trailing EndOfContent, + * check for that. + */ + if (is_indefinite) { + ret = der_match_tag_and_length(p, len, ASN1_C_UNIV, + &dertype, UT_EndOfContent, + &datalen, &l); + if (ret) + return ret; + if (dertype != PRIM) + return ASN1_BAD_ID; + if (datalen != 0) + return ASN1_INDEF_EXTRA_DATA; + p += l; len -= l; + } + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + void *el = DPO(data, t->offset); + + /* + * INDEFINITE primitive types are one element after the + * same type but non-INDEFINITE version. + */ + if (flags & A1_PF_INDEFINTE) + type++; + + if (type >= sizeof(prim)/sizeof(prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (prim[type].decode)(p, len, el, &newsize); + if (ret) + return ret; + p += newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t newsize; + size_t ellen = sizeofType(t->ptr); + size_t vallength = 0; + + while (len > 0) { + void *tmp; + size_t newlen = vallength + ellen; + if (vallength > newlen) + return ASN1_OVERFLOW; + + tmp = realloc(el->val, newlen); + if (tmp == NULL) + return ENOMEM; + + memset(DPO(tmp, vallength), 0, ellen); + el->val = tmp; + + ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len, + DPO(el->val, vallength), &newsize); + if (ret) + return ret; + vallength = newlen; + el->len++; + p += newsize; len -= newsize; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t elements = A1_HEADER_LEN(bmember); + size_t pos = 0; + + bmember++; + + memset(data, 0, size); + + if (len < 1) + return ASN1_OVERRUN; + p++; len--; + + while (elements && len) { + while (bmember->offset / 8 > pos / 8) { + if (len < 1) + break; + p++; len--; + pos += 8; + } + if (len) { + bmember_get_bit(p, data, bmember->offset, size); + elements--; bmember++; + } + } + len = 0; + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + unsigned int *element = DPO(data, choice->offset); + size_t datalen; + unsigned int i; + + for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) { + /* should match first tag instead, store it in choice.tt */ + ret = _asn1_decode(choice[i].ptr, 0, p, len, + DPO(data, choice[i].offset), &datalen); + if (ret == 0) { + *element = i; + p += datalen; len -= datalen; + break; + } else if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && ret != ASN1_MISSING_FIELD) { + return ret; + } + } + if (i >= A1_HEADER_LEN(choice) + 1) { + if (choice->tt == 0) + return ASN1_BAD_ID; + + *element = 0; + ret = der_get_octet_string(p, len, + DPO(data, choice->tt), &datalen); + if (ret) + return ret; + p += datalen; len -= datalen; + } + + break; + } + default: + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + t++; + elements--; + } + /* if we are using padding, eat up read of context */ + if (template_flags & A1_HF_ELLIPSIS) + len = 0; + + oldlen -= len; + + if (size) + *size = oldlen; + + /* + * saved the raw bits if asked for it, useful for signature + * verification. + */ + if (startp) { + heim_octet_string *save = data; + + save->data = malloc(oldlen); + if (save->data == NULL) + return ENOMEM; + else { + save->length = oldlen; + memcpy(save->data, startp, oldlen); + } + } + return 0; +} + +int +_asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size) +{ + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + size_t oldlen = len; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_encode(t->ptr, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->encode)(p, len, el, &newsize); + } + + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + const void *olddata = data; + size_t l, datalen; + + data = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } + + ret = _asn1_encode(t->ptr, p, len, data, &datalen); + if (ret) + return ret; + + len -= datalen; p -= datalen; + + ret = der_put_length_and_tag(p, len, datalen, + A1_TAG_CLASS(t->tt), + A1_TAG_TYPE(t->tt), + A1_TAG_TAG(t->tt), &l); + if (ret) + return ret; + + p -= l; len -= l; + + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (type > sizeof(prim)/sizeof(prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (prim[type].encode)(p, len, el, &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = sizeofType(t->ptr); + struct heim_octet_string *val; + unsigned char *elptr = el->val; + size_t i, totallen; + + if (el->len == 0) + break; + + if (el->len > UINT_MAX/sizeof(val[0])) + return ERANGE; + + val = malloc(sizeof(val[0]) * el->len); + if (val == NULL) + return ENOMEM; + + for(totallen = 0, i = 0; i < el->len; i++) { + unsigned char *next; + size_t l; + + val[i].length = _asn1_length(t->ptr, elptr); + val[i].data = malloc(val[i].length); + + ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1), + val[i].length, elptr, &l); + if (ret) + break; + + next = elptr + ellen; + if (next < elptr) { + ret = ASN1_OVERFLOW; + break; + } + elptr = next; + totallen += val[i].length; + } + if (ret == 0 && totallen > len) + ret = ASN1_OVERFLOW; + if (ret) { + do { + free(val[i].data); + } while(i-- > 0); + free(val); + return ret; + } + + len -= totallen; + + qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort); + + i = el->len - 1; + do { + p -= val[i].length; + memcpy(p + 1, val[i].data, val[i].length); + free(val[i].data); + } while(i-- > 0); + free(val); + + break; + + } + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = sizeofType(t->ptr); + size_t newsize; + unsigned int i; + unsigned char *elptr = el->val; + + if (el->len == 0) + break; + + elptr += ellen * (el->len - 1); + + for (i = 0; i < el->len; i++) { + ret = _asn1_encode(t->ptr, p, len, + elptr, + &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + elptr -= ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t elements = A1_HEADER_LEN(bmember); + size_t pos; + unsigned char c = 0; + unsigned int bitset = 0; + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + bmember += elements; + + if (rfc1510) + pos = 31; + else + pos = bmember->offset; + + while (elements && len) { + while (bmember->offset / 8 < pos / 8) { + if (rfc1510 || bitset || c) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + c = 0; + pos -= 8; + } + bmember_put_bit(&c, data, bmember->offset, size, &bitset); + elements--; bmember--; + } + if (rfc1510 || bitset) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + + if (len < 1) + return ASN1_OVERFLOW; + if (rfc1510 || bitset == 0) + *p-- = 0; + else + *p-- = bitset - 1; + + len--; + + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + size_t datalen; + const void *el; + + if (*element > A1_HEADER_LEN(choice)) { + printf("element: %d\n", *element); + return ASN1_PARSE_ERROR; + } + + if (*element == 0) { + ret += der_put_octet_string(p, len, + DPOC(data, choice->tt), &datalen); + } else { + choice += *element; + el = DPOC(data, choice->offset); + ret = _asn1_encode(choice->ptr, p, len, el, &datalen); + if (ret) + return ret; + } + len -= datalen; p -= datalen; + + break; + } + default: + ABORT_ON_ERROR(); + } + t--; + elements--; + } + if (size) + *size = oldlen - len; + + return 0; +} + +size_t +_asn1_length(const struct asn1_template *t, const void *data) +{ + size_t elements = A1_HEADER_LEN(t); + size_t ret = 0; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret += _asn1_length(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + ret += (f->length)(el); + } + break; + } + case A1_OP_TAG: { + size_t datalen; + const void *olddata = data; + + data = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } + datalen = _asn1_length(t->ptr, data); + ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen); + ret += datalen; + data = olddata; + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + + if (type > sizeof(prim)/sizeof(prim[0])) { + ABORT_ON_ERROR(); + break; + } + ret += (prim[type].length)(el); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + ret += _asn1_length(t->ptr, element); + element += ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t elements = A1_HEADER_LEN(bmember); + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + if (rfc1510) { + ret += 5; + } else { + + ret += 1; + + bmember += elements; + + while (elements) { + if (bmember_isset_bit(data, bmember->offset, size)) { + ret += (bmember->offset / 8) + 1; + break; + } + elements--; bmember--; + } + } + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + ret += der_length_octet_string(DPOC(data, choice->tt)); + } else { + choice += *element; + ret += _asn1_length(choice->ptr, DPOC(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + elements--; + t--; + } + return ret; +} + +void +_asn1_free(const struct asn1_template *t, void *data) +{ + size_t elements = A1_HEADER_LEN(t); + + if (t->tt & A1_HF_PRESERVE) + der_free_octet_string(data); + + t++; + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + void *el = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + _asn1_free(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + (f->release)(el); + } + if (t->tt & A1_FLAG_OPTIONAL) + free(el); + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + void *el = DPO(data, t->offset); + + if (type > sizeof(prim)/sizeof(prim[0])) { + ABORT_ON_ERROR(); + break; + } + (prim[type].release)(el); + break; + } + case A1_OP_TAG: { + void *el = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + _asn1_free(t->ptr, el); + + if (t->tt & A1_FLAG_OPTIONAL) + free(el); + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = sizeofType(t->ptr); + unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + _asn1_free(t->ptr, element); + element += ellen; + } + free(el->val); + el->val = NULL; + el->len = 0; + + break; + } + case A1_OP_BMEMBER: + break; + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + der_free_octet_string(DPO(data, choice->tt)); + } else { + choice += *element; + _asn1_free(choice->ptr, DPO(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } +} + +int +_asn1_copy(const struct asn1_template *t, const void *from, void *to) +{ + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + int preserve = (t->tt & A1_HF_PRESERVE); + + t++; + + if (preserve) { + ret = der_copy_octet_string(from, to); + if (ret) + return ret; + } + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *fel = DPOC(from, t->offset); + void *tel = DPO(to, t->offset); + void **ptel = (void **)tel; + size_t size; + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + size = sizeofType(t->ptr); + } else { + const struct asn1_type_func *f = t->ptr; + size = f->size; + } + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pfel = (void **)fel; + if (*pfel == NULL) + break; + fel = *pfel; + + tel = *ptel = calloc(1, size); + if (tel == NULL) + return ENOMEM; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_copy(t->ptr, fel, tel); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->copy)(fel, tel); + } + + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + free(*ptel); + *ptel = NULL; + } + return ret; + } + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *fel = DPOC(from, t->offset); + void *tel = DPO(to, t->offset); + + if (type > sizeof(prim)/sizeof(prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + ret = (prim[type].copy)(fel, tel); + if (ret) + return ret; + break; + } + case A1_OP_TAG: { + const void *oldfrom = from; + void *oldto = to; + void **tel = NULL; + + from = DPOC(from, t->offset); + to = DPO(to, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **fel = (void **)from; + tel = (void **)to; + if (*fel == NULL) { + from = oldfrom; + to = oldto; + break; + } + from = *fel; + + to = *tel = calloc(1, sizeofType(t->ptr)); + if (to == NULL) + return ENOMEM; + } + + ret = _asn1_copy(t->ptr, from, to); + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + free(*tel); + *tel = NULL; + } + return ret; + } + + from = oldfrom; + to = oldto; + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *fel = DPOC(from, t->offset); + struct template_of *tel = DPO(to, t->offset); + size_t ellen = sizeofType(t->ptr); + unsigned int i; + + tel->val = calloc(fel->len, ellen); + if (tel->val == NULL) + return ENOMEM; + + tel->len = fel->len; + + for (i = 0; i < fel->len; i++) { + ret = _asn1_copy(t->ptr, + DPOC(fel->val, (i * ellen)), + DPO(tel->val, (i *ellen))); + if (ret) + return ret; + } + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + memcpy(to, from, size); + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *felement = DPOC(from, choice->offset); + unsigned int *telement = DPO(to, choice->offset); + + if (*felement > A1_HEADER_LEN(choice)) + return ASN1_PARSE_ERROR; + + *telement = *felement; + + if (*felement == 0) { + ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt)); + } else { + choice += *felement; + ret = _asn1_copy(choice->ptr, + DPOC(from, choice->offset), + DPO(to, choice->offset)); + } + if (ret) + return ret; + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } + return 0; +} + +int +_asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size) +{ + int ret; + memset(data, 0, t->offset); + ret = _asn1_decode(t, flags, p, len, data, size); + if (ret) { + _asn1_free(t, data); + memset(data, 0, t->offset); + } + + return ret; +} + +int +_asn1_copy_top(const struct asn1_template *t, const void *from, void *to) +{ + int ret; + memset(to, 0, t->offset); + ret = _asn1_copy(t, from, to); + if (ret) { + _asn1_free(t, to); + memset(to, 0, t->offset); + } + return ret; +} diff --git a/lib/asn1/test.asn1 b/lib/asn1/test.asn1 index f6237b85b..e3c72ac76 100644 --- a/lib/asn1/test.asn1 +++ b/lib/asn1/test.asn1 @@ -6,8 +6,11 @@ BEGIN IMPORTS heim_any FROM heim; +TESTuint32 ::= INTEGER (0..4294967295) + TESTLargeTag ::= SEQUENCE { - foo[127] INTEGER (-2147483648..2147483647) + foo[127] INTEGER (-2147483648..2147483647), + bar[128] INTEGER (-2147483648..2147483647) } TESTSeq ::= SEQUENCE { @@ -57,6 +60,11 @@ TESTAlloc ::= SEQUENCE { tagless2 heim_any OPTIONAL } +TESTOptional ::= SEQUENCE { + zero [0] INTEGER (-2147483648..2147483647) OPTIONAL, + one [1] INTEGER (-2147483648..2147483647) OPTIONAL +} + TESTCONTAINING ::= OCTET STRING ( CONTAINING INTEGER ) TESTENCODEDBY ::= OCTET STRING ( ENCODED BY @@ -92,4 +100,36 @@ TESTSeqSizeOf4 ::= SEQUENCE SIZE (MIN..2) OF TESTInteger TESTOSSize1 ::= OCTET STRING SIZE (1..2) +TESTSeqOfSeq ::= SEQUENCE OF SEQUENCE { + zero [0] TESTInteger +} + +TESTSeqOfSeq2 ::= SEQUENCE OF SEQUENCE { + string [0] GeneralString +} + +TESTSeqOfSeq3 ::= SEQUENCE OF SEQUENCE { + zero [0] TESTInteger, + string [0] GeneralString +} + +TESTSeqOf2 ::= SEQUENCE { + strings SEQUENCE OF GeneralString +} + +TESTSeqOf3 ::= SEQUENCE { + strings SEQUENCE OF GeneralString OPTIONAL +} + +TESTPreserve ::= SEQUENCE { + zero [0] TESTInteger, + one [1] TESTInteger +} + +TESTBitString ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31) +} + END