diff --git a/lib/asn1/Makefile.am b/lib/asn1/Makefile.am index d2146fe3e..2c7584f38 100644 --- a/lib/asn1/Makefile.am +++ b/lib/asn1/Makefile.am @@ -6,7 +6,7 @@ YFLAGS = -d -t AM_CPPFLAGS += $(ROKEN_RENAME) -man_MANS = asn1_compile.1 +man_MANS = asn1_print.1 asn1_compile.1 lib_LTLIBRARIES = libasn1.la libasn1_la_LDFLAGS = -version-info 8:0:0 @@ -109,6 +109,7 @@ dist_libasn1base_la_SOURCES = \ der_get.c \ der_put.c \ der_free.c \ + der_print.c \ der_length.c \ der_copy.c \ der_cmp.c \ @@ -132,7 +133,7 @@ asn1_compile_LDADD = \ $(LIB_roken) $(LEXLIB) check_der_LDADD = \ - libasn1base.la \ + libasn1.la \ $(LIB_roken) check_template_LDADD = $(check_der_LDADD) diff --git a/lib/asn1/NTMakefile b/lib/asn1/NTMakefile index d738db12a..fe4ff2da4 100644 --- a/lib/asn1/NTMakefile +++ b/lib/asn1/NTMakefile @@ -116,6 +116,7 @@ LIBASN1_OBJS= \ $(OBJ)\der_get.obj \ $(OBJ)\der_put.obj \ $(OBJ)\der_free.obj \ + $(OBJ)\der_print.obj \ $(OBJ)\der_length.obj \ $(OBJ)\der_copy.obj \ $(OBJ)\der_cmp.obj \ @@ -381,6 +382,7 @@ libasn1_base_SOURCES= \ der_get.c \ der_put.c \ der_free.c \ + der_print.c \ der_length.c \ der_copy.c \ der_cmp.c \ diff --git a/lib/asn1/README.md b/lib/asn1/README.md index 3a4a31275..c105bd334 100644 --- a/lib/asn1/README.md +++ b/lib/asn1/README.md @@ -159,6 +159,55 @@ make it easy to add support for encoding rules other than X.690. - Most of X.690 is supported for decoding, with only DER supported for encoding. + - We have an `asn1_print` program that can decode DER from any exported types + from any ASN.1 modules committed in Heimdal: + + ```bash + $ ./asn1_print ek.crt Certificate | + jq '.tbsCertificate.extensions[3]._open_type[]._open_type' + ``` + + ```JSON + [ + { + "_type": "TPMSpecification", + "family": "2.0", + "level": "0", + "revision": "138" + } + ] + [ + { + "_type": "TPMSecurityAssertions", + "version": "0", + "fieldUpgradable": "1", + "ekGenerationType": "655617", + "ekGenerationLocation": "655616", + "ekCertificateGenerationLocation": "655616", + "ccInfo": { + "_type": "CommonCriteriaMeasures", + "version": "3.1", + "assurancelevel": "4", + "evaluationStatus": "2", + "plus": "1", + "strengthOfFunction": null, + "profileOid": null, + "profileUri": null, + "targetOid": null, + "targetUri": null + }, + "fipsLevel": { + "_type": "FIPSLevel", + "version": "140-2", + "level": "2", + "plus": "0" + }, + "iso9000Certified": "0", + "iso9000Uri": null + } + ] + ``` + - Unconstrained integer types have a large integer representation in C that is not terribly useful in common cases. Range constraints on integer types cause the compiler to use `int32_t`, `int64_t`, `uint32_t`, and/or @@ -183,6 +232,11 @@ make it easy to add support for encoding rules other than X.690. ## Limitations + - `asn1_print`'s JSON support is not X.697 (JER) compatible. + + - Control over C types generated is very limited, mainly only for integer + types. + - When using the template backend, `SET { .. }` types are currently not sorted by tag as they should be, but if the module author sorts them by hand then DER will be produced. diff --git a/lib/asn1/asn1-common.h b/lib/asn1/asn1-common.h index f68efa0e9..7797eed49 100644 --- a/lib/asn1/asn1-common.h +++ b/lib/asn1/asn1-common.h @@ -55,6 +55,10 @@ typedef struct heim_base_data heim_any_set; typedef struct heim_base_data HEIM_ANY; typedef struct heim_base_data HEIM_ANY_SET; +enum asn1_print_flags { + ASN1_PRINT_INDENT = 1, +}; + #define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \ do { \ (BL) = length_##T((S)); \ diff --git a/lib/asn1/asn1-template.h b/lib/asn1/asn1-template.h index 47fe53499..6be8d79a9 100644 --- a/lib/asn1/asn1-template.h +++ b/lib/asn1/asn1-template.h @@ -118,9 +118,8 @@ * offset is all ones */ -/* name: when it happens at index 1 it's the name of the SET/SEQUENCE/CHOICE - * when it happens at any other index it's the name of the field that the - * next entry deals with +/* name: first one is the name of the SET/SEQUENCE/CHOICE type + * subsequent ones are the name of the nth field * * 0..23 unused * 24..27 flags A1_NM_* @@ -218,6 +217,7 @@ typedef int (ASN1CALL *asn1_type_encode)(unsigned char *, size_t, const void *, typedef size_t (ASN1CALL *asn1_type_length)(const void *); typedef void (ASN1CALL *asn1_type_release)(void *); typedef int (ASN1CALL *asn1_type_copy)(const void *, void *); +typedef char * (ASN1CALL *asn1_type_print)(const void *, int); struct asn1_type_func { asn1_type_encode encode; @@ -225,6 +225,7 @@ struct asn1_type_func { asn1_type_length length; asn1_type_copy copy; asn1_type_release release; + asn1_type_print print; size_t size; }; @@ -279,8 +280,10 @@ _asn1_copy_top ( void * /*to*/); void -_asn1_free_top(const struct asn1_template *t, - void *data); +_asn1_free_top(const struct asn1_template *, void *); + +char * +_asn1_print_top(const struct asn1_template *, int, const void *); int _asn1_decode_top ( diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index 7165db290..93de629a5 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -2182,9 +2182,184 @@ test_ios(void) 0xea, 0xa4, 0x2b, 0x6f, 0x56, 0x3d, 0xf7, 0xaa, 0x75, 0x06, }; + char cert_json[] = { + "{\"_type\":\"Certificate\",\"tbsCertificate\":{\"_type\":\"TBSCe" + "rtificate\",\"_save\":\"30820376A00302010202146A0597BA71D7E6D3AC" + "0EDC9EDC95A15B998DE40A300D06092A864886F70D01010B05003055310B3009" + "060355040613024348311E301C060355040A131553544D6963726F656C656374" + "726F6E696373204E56312630240603550403131D53544D2054504D20454B2049" + "6E7465726D656469617465204341203035301E170D3138313231343030303030" + "305A170D3238313231343030303030305A300030820122300D06092A864886F7" + "0D01010105000382010F003082010A0282010100CC14EB27A78CEB0EA486FA2D" + "F7835F5FA8E905B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239F" + "A95310651B1B56FD2CFE53C87352EBD996E33256160404CE9302A08066801E78" + "6A2F86E181F949966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347" + "871C91E15437E8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB" + "4036B359CB72A294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C7561" + "7047058F7ED7D603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D" + "198BEBCE86040FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D1" + "6891FBFBA02A18AFE59F9D6F149744E5F0D559B10203010001A38201A9308201" + "A5301F0603551D230418301680141ADB994AB58BE57A0CC9B900E7851E1A43C0" + "866030420603551D20043B303930370604551D2000302F302D06082B06010505" + "0702011621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F73" + "69746F72792F30590603551D110101FF044F304DA44B30493116301406056781" + "0502010C0B69643A353335343444323031173015060567810502020C0C535433" + "33485450484148433031163014060567810502030C0B69643A30303439303030" + "3830670603551D090460305E301706056781050210310E300C0C03322E300201" + "000202008A304306056781050212313A30380201000101FFA0030A0101A1030A" + "0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D160531" + "34302D320A0102010100300E0603551D0F0101FF040403020520300C0603551D" + "130101FF0402300030100603551D250409300706056781050801304A06082B06" + "010505070101043E303C303A06082B06010505073002862E687474703A2F2F73" + "65637572652E676C6F62616C7369676E2E636F6D2F73746D74706D656B696E74" + "30352E637274\",\"version\":\"2\",\"serialNumber\":\"6A0597BA71D7" + "E6D3AC0EDC9EDC95A15B998DE40A\",\"signature\":{\"_type\":\"Algori" + "thmIdentifier\",\"algorithm\":{\"_type\":\"OBJECT IDENTIFIER\",\"" + "oid\":\"1.2.840.113549.1.1.11\",\"components\":[1,2,840,113549," + "1,1,11],\"name\":\"id-pkcs1-sha256WithRSAEncryption\"},\"paramet" + "ers\":\"0500\"},\"issuer\":{\"_choice\":\"rdnSequence\",\"value\"" + ":[[{\"_type\":\"AttributeTypeAndValue\",\"type\":{\"_type\":\"O" + "BJECT IDENTIFIER\",\"oid\":\"2.5.4.6\",\"components\":[2,5,4,6]," + "\"name\":\"id-at-countryName\"},\"value\":{\"_choice\":\"printab" + "leString\",\"value\":\"CH\"}}],[{\"_type\":\"AttributeTypeAndVal" + "ue\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.4.1" + "0\",\"components\":[2,5,4,10],\"name\":\"id-at-organizationName\"" + "},\"value\":{\"_choice\":\"printableString\",\"value\":\"STMicr" + "oelectronics NV\"}}],[{\"_type\":\"AttributeTypeAndValue\",\"typ" + "e\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.4.3\",\"compo" + "nents\":[2,5,4,3],\"name\":\"id-at-commonName\"},\"value\":{\"_c" + "hoice\":\"printableString\",\"value\":\"STM TPM EK Intermediate " + "CA 05\"}}]]},\"validity\":{\"_type\":\"Validity\",\"notBefore\":" + "{\"_choice\":\"utcTime\",\"value\":\"2018-12-14T00:00:00Z\"},\"n" + "otAfter\":{\"_choice\":\"utcTime\",\"value\":\"2028-12-14T00:00:" + "00Z\"}},\"subject\":{\"_choice\":\"rdnSequence\",\"value\":[]},\"" + "subjectPublicKeyInfo\":{\"_type\":\"SubjectPublicKeyInfo\",\"al" + "gorithm\":{\"_type\":\"AlgorithmIdentifier\",\"algorithm\":{\"_t" + "ype\":\"OBJECT IDENTIFIER\",\"oid\":\"1.2.840.113549.1.1.1\",\"c" + "omponents\":[1,2,840,113549,1,1,1],\"name\":\"id-pkcs1-rsaEncryp" + "tion\"},\"parameters\":\"0500\"},\"subjectPublicKey\":\"2160:308" + "2010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BD" + "E50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87" + "352EBD996E33256160404CE9302A08066801E786A2F86E181F949966F492A85B" + "58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5E" + "B271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF" + "0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D603E03250809" + "4FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C765" + "7414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F1" + "49744E5F0D559B10203010001\"},\"issuerUniqueID\":null,\"subjectUn" + "iqueID\":null,\"extensions\":[{\"_type\":\"Extension\",\"extnID\"" + ":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.29.35\",\"compo" + "nents\":[2,5,29,35],\"name\":\"id-x509-ce-authorityKeyIdentifier" + "\"},\"critical\":false,\"extnValue\":\"301680141ADB994AB58BE57A0" + "CC9B900E7851E1A43C08660\",\"_extnValue_choice\":\"ext-AuthorityK" + "eyIdentifier\",\"_extnValue\":{\"_type\":\"AuthorityKeyIdentifi" + "er\",\"keyIdentifier\":\"1ADB994AB58BE57A0CC9B900E7851E1A43C0866" + "0\",\"authorityCertIssuer\":null,\"authorityCertSerialNumber\":n" + "ull}},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT ID" + "ENTIFIER\",\"oid\":\"2.5.29.32\",\"components\":[2,5,29,32],\"na" + "me\":\"id-x509-ce-certificatePolicies\"},\"critical\":false,\"ex" + "tnValue\":\"303930370604551D2000302F302D06082B060105050702011621" + "687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F7279" + "2F\",\"_extnValue_choice\":\"ext-CertificatePolicies\",\"_extnV" + "alue\":[{\"_type\":\"PolicyInformation\",\"policyIdentifier\":{\"" + "_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.29.32.0\",\"compone" + "nts\":[2,5,29,32,0],\"name\":\"id-x509-ce-certificatePolicies-an" + "yPolicy\"},\"policyQualifiers\":[{\"_type\":\"PolicyQualifierInf" + "o\",\"policyQualifierId\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid" + "\":\"1.3.6.1.5.5.7.2.1\",\"components\":[1,3,6,1,5,5,7,2,1],\"na" + "me\":\"id-pkix-qt-cps\"},\"qualifier\":\"1621687474703A2F2F77777" + "72E73742E636F6D2F54504D2F7265706F7369746F72792F\"}]}]},{\"_type\"" + ":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oi" + "d\":\"2.5.29.17\",\"components\":[2,5,29,17],\"name\":\"id-x509-" + "ce-subjectAltName\"},\"critical\":true,\"extnValue\":\"304DA44B3" + "04931163014060567810502010C0B69643A35333534344432303117301506056" + "7810502020C0C53543333485450484148433031163014060567810502030C0B6" + "9643A3030343930303038\",\"_extnValue_choice\":\"ext-SubjectAltNa" + "me\",\"_extnValue\":[{\"_choice\":\"directoryName\",\"value\":{" + "\"_choice\":\"rdnSequence\",\"value\":[[{\"_type\":\"AttributeTy" + "peAndValue\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"" + "2.23.133.2.1\",\"components\":[2,23,133,2,1],\"name\":\"tcg-at-" + "tpmManufacturer\"},\"value\":{\"_choice\":\"utf8String\",\"value" + "\":\"id:53544D20\"}}],[{\"_type\":\"AttributeTypeAndValue\",\"ty" + "pe\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.2\",\"" + "components\":[2,23,133,2,2],\"name\":\"tcg-at-tpmModel\"},\"val" + "ue\":{\"_choice\":\"utf8String\",\"value\":\"ST33HTPHAHC0\"}}],[" + "{\"_type\":\"AttributeTypeAndValue\",\"type\":{\"_type\":\"OBJEC" + "T IDENTIFIER\",\"oid\":\"2.23.133.2.3\",\"components\":[2,23,133" + ",2,3],\"name\":\"tcg-at-tpmVersion\"},\"value\":{\"_choice\":\"u" + "tf8String\",\"value\":\"id:00490008\"}}]]}}]},{\"_type\":\"Exten" + "sion\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5" + ".29.9\",\"components\":[2,5,29,9],\"name\":\"id-x509-ce-subjectD" + "irectoryAttributes\"},\"critical\":false,\"extnValue\":\"305E301" + "706056781050210310E300C0C03322E300201000202008A30430605678105021" + "2313A30380201000101FFA0030A0101A1030A0100A2030A0100A310300E16033" + "32E310A01040A01020101FFA40F300D16053134302D320A0102010100\",\"_e" + "xtnValue_choice\":\"ext-SubjectDirectoryAttributes\",\"_extnVal" + "ue\":[{\"_type\":\"AttributeSet\",\"type\":{\"_type\":\"OBJECT I" + "DENTIFIER\",\"oid\":\"2.23.133.2.16\",\"components\":[2,23,133,2" + ",16],\"name\":\"tcg-at-tpmSpecification\"},\"values\":[\"300C0C0" + "3322E300201000202008A\"],\"_values_choice\":\"at-TPMSpecificatio" + "n\",\"_values\":[{\"_type\":\"TPMSpecification\",\"family\":\"2" + ".0\",\"level\":0,\"revision\":138}]},{\"_type\":\"AttributeSet\"" + ",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2." + "18\",\"components\":[2,23,133,2,18],\"name\":\"tcg-at-tpmSecurit" + "yAssertions\"},\"values\":[\"30380201000101FFA0030A0101A1030A010" + "0A2030A0100A310300E1603332E310A01040A01020101FFA40F300D160531343" + "02D320A0102010100\"],\"_values_choice\":\"at-TPMSecurityAssertio" + "ns\",\"_values\":[{\"_type\":\"TPMSecurityAssertions\",\"versio" + "n\":\"0\",\"fieldUpgradable\":true,\"ekGenerationType\":\"655617" + "\",\"ekGenerationLocation\":\"655616\",\"ekCertificateGeneration" + "Location\":\"655616\",\"ccInfo\":{\"_type\":\"CommonCriteriaMeas" + "ures\",\"version\":\"3.1\",\"assurancelevel\":\"4\",\"evaluation" + "Status\":\"2\",\"plus\":true,\"strengthOfFunction\":null,\"profi" + "leOid\":null,\"profileUri\":null,\"targetOid\":null,\"targetUri\"" + ":null},\"fipsLevel\":{\"_type\":\"FIPSLevel\",\"version\":\"140" + "-2\",\"level\":\"2\",\"plus\":false},\"iso9000Certified\":false," + "\"iso9000Uri\":null}]}]},{\"_type\":\"Extension\",\"extnID\":{\"" + "_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.29.15\",\"components" + "\":[2,5,29,15],\"name\":\"id-x509-ce-keyUsage\"},\"critical\":tr" + "ue,\"extnValue\":\"03020520\",\"_extnValue_choice\":\"ext-KeyUsa" + "ge\",\"_extnValue\":[\"keyEncipherment\"]},{\"_type\":\"Extensi" + "on\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.2" + "9.19\",\"components\":[2,5,29,19],\"name\":\"id-x509-ce-basicCon" + "straints\"},\"critical\":true,\"extnValue\":\"3000\",\"_extnValu" + "e_choice\":\"ext-BasicConstraints\",\"_extnValue\":{\"_type\":\"" + "BasicConstraints\",\"cA\":false,\"pathLenConstraint\":null}},{\"" + "_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER" + "\",\"oid\":\"2.5.29.37\",\"components\":[2,5,29,37],\"name\":\"i" + "d-x509-ce-extKeyUsage\"},\"critical\":false,\"extnValue\":\"3007" + "06056781050801\",\"_extnValue_choice\":\"ext-ExtKeyUsage\",\"_e" + "xtnValue\":[{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133." + "8.1\",\"components\":[2,23,133,8,1],\"name\":\"tcg-kp-EKCertific" + "ate\"}]},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT" + " IDENTIFIER\",\"oid\":\"1.3.6.1.5.5.7.1.1\",\"components\":[1,3," + "6,1,5,5,7,1,1],\"name\":\"id-pkix-pe-authorityInfoAccess\"},\"cr" + "itical\":false,\"extnValue\":\"303C303A06082B06010505073002862E6" + "87474703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D7" + "4706D656B696E7430352E637274\",\"_extnValue_choice\":\"ext-Author" + "ityInfoAccess\",\"_extnValue\":[{\"_type\":\"AccessDescription\"" + ",\"accessMethod\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"1." + "3.6.1.5.5.7.48.2\",\"components\":[1,3,6,1,5,5,7,48,2],\"name\":" + "\"id-pkix-ad-caIssuers\"},\"accessLocation\":{\"_choice\":\"unif" + "ormResourceIdentifier\",\"value\":\"http://secure.globalsign.com" + "/stmtpmekint05.crt\"}}]}]},\"signatureAlgorithm\":{\"_type\":\"A" + "lgorithmIdentifier\",\"algorithm\":{\"_type\":\"OBJECT IDENTIFIE" + "R\",\"oid\":\"1.2.840.113549.1.1.11\",\"components\":[1,2,840,11" + "3549,1,1,11],\"name\":\"id-pkcs1-sha256WithRSAEncryption\"},\"pa" + "rameters\":\"0500\"},\"signatureValue\":\"2048:3D4C381E5B4F1BCBE" + "09C63D52F1F04570CAEA142FD9CD942043B11F8E3BDCF50007AE16CF88690130" + "41E92CDD3280BA4B51FBBD40582ED750219E261A695095674855AACEB520ADAF" + "F9E7E908480A39CDCF900462D9171960FFE55D3AC49E8C981341BBD2EFBCC252" + "A4C18A4F3B7C84CCE42CE70A208C84D2630A7ABFBE72D6271E75B9FF1C971D20" + "EB3DBD763F1E04D834EAA692D2E4001BBF4730A3E3FDA9711AE386524D91C63B" + "E0E516D00D5C6141FCCF6C539F3518E180049865BE16B69CAE1F8CB7FDC474B3" + "8F7EE56CBE7D8A89D9BA99B65D5265AEF32AA62426B10E6D75BB8677EC44F755" + "BBC2806FD2B4E04BDF5D44259DBEAA42B6F563DF7AA7506\"}" + }; heim_octet_string os; Certificate c0, c1; size_t i, nknown, size; + char *s; int ret; /* @@ -2200,6 +2375,13 @@ test_ios(void) if (size != sizeof(encoded_sample)) return 1; + s = print_Certificate(&c0, 0); + if (!s) + return 1; + if (strcmp(s, cert_json)) + return 1; + free(s); + ret = copy_Certificate(&c0, &c1); if (ret) return 1; @@ -2225,6 +2407,7 @@ test_ios(void) if (!nknown) return 1; + /* * Check that this round trips. But note that this attempt to encode will * ignore the automatically decoded open type values from above because @@ -2272,7 +2455,6 @@ test_ios(void) return 1; der_free_octet_string(&os); - /* XXX Test setting some of the _ioschoice_extnValue._element's to 0 */ free_Certificate(&c0); free_Certificate(&c1); return 0; diff --git a/lib/asn1/der_print.c b/lib/asn1/der_print.c new file mode 100644 index 000000000..84fded31a --- /dev/null +++ b/lib/asn1/der_print.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2021 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 "hex.h" + +RCSID("$Id$"); + +char * +der_print_general_string(const heim_general_string *str, int flags) +{ + return strdup(*str); +} + +char * +der_print_boolean(const int *i, int flags) +{ + return *i ? strdup("true") : strdup("false"); +} + +char * +der_print_integer(const int *i, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%d", *i) == -1 || s == NULL) + return NULL; + return s; +} + +char * +der_print_integer64(const int64_t *i, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%lld", (long long)*i) == -1 || s == NULL) + return NULL; + return s; +} + +char * +der_print_unsigned(const unsigned *u, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%u", *u) == -1 || s == NULL) + return NULL; + return s; +} + +char * +der_print_unsigned64(const uint64_t *u, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%llu", (long long)*u) == -1 || s == NULL) + return NULL; + return s; +} + +char * +der_print_generalized_time(const time_t *t, int flags) +{ + struct tm tms; + char str[sizeof("1970-01-01T00:00:00Z")]; + +#ifdef WIN32 + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_s(&tms, t)) == 0) + return NULL; +#else + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_r(t, &tms)) == 0) + return NULL; +#endif + return strdup(str); +} + +char * +der_print_utctime(const time_t *t, int flags) +{ + struct tm tms; + char str[sizeof("1970-01-01T00:00:00Z")]; + +#ifdef WIN32 + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_s(&tms, t)) == 0) + return NULL; +#else + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_r(t, &tms)) == 0) + return NULL; +#endif + return strdup(str); +} + + +char * +der_print_utf8string(const heim_utf8_string *str, int flags) +{ + return strdup(*str); +} + +char * +der_print_printable_string(const heim_printable_string *str, int flags) +{ + return strndup(str->data, str->length); +} + +char * +der_print_ia5_string(const heim_ia5_string *str, int flags) +{ + return strndup(str->data, str->length); +} + +char * +der_print_bmp_string(const heim_bmp_string *k, int flags) +{ + return strdup(""); +} + +char * +der_print_universal_string(const heim_universal_string *k, int flags) +{ + return strdup(""); +} + +char * +der_print_visible_string(const heim_visible_string *str, int flags) +{ + return strdup(*str); +} + +char * +der_print_octet_string(const heim_octet_string *k, int flags) +{ + char *s = NULL; + + (void) hex_encode(k->data, k->length, &s); + return s; +} + +char * +der_print_heim_integer(const heim_integer *k, int flags) +{ + char *s = NULL; + + (void) der_print_hex_heim_integer(k, &s); + return s; +} + +char * +der_print_oid(const heim_oid *k, int flags) +{ + struct rk_strpool *r = NULL; + const char *sym = NULL; + char *s = NULL; + size_t i; + + (void) der_print_heim_oid(k, '.', &s); + + if (!s) + return NULL; + r = rk_strpoolprintf(r, "{\"_type\":\"OBJECT IDENTIFIER\"," + "\"oid\":\"%s\"," + "\"components\":[", + s); + free(s); + for (i = 0; i < k->length; i++) + r = rk_strpoolprintf(r, "%s%u", i ? "," : "", k->components[i]); + if (r) + r = rk_strpoolprintf(r, "]"); + (void) der_find_heim_oid_by_oid(k, &sym); + if (sym && r) { + if ((s = strdup(sym))) { + for (i = 0; s[i]; i++) + if (s[i] == '_') + s[i] = '-'; + } + r = rk_strpoolprintf(r, ",\"name\":\"%s\"", s ? s : sym); + free(s); + } + if (r) + r = rk_strpoolprintf(r, "}"); + return rk_strpoolcollect(r); +} + +char * +der_print_bit_string(const heim_bit_string *k, int flags) +{ + char *s2 = NULL; + char *s = NULL; + + (void) hex_encode(k->data, k->length / 8, &s); + if (asprintf(&s2, "%llu:%s", (unsigned long long)k->length, s) == -1 || !s2) + return NULL; + free(s); + return s2; +} diff --git a/lib/asn1/extra.c b/lib/asn1/extra.c index a4a18f63e..f9b5b7a7a 100644 --- a/lib/asn1/extra.c +++ b/lib/asn1/extra.c @@ -90,6 +90,12 @@ free_heim_any(heim_any *data) der_free_octet_string(data); } +char * +print_heim_any(const heim_any *data) +{ + return der_print_octet_string(data, 0); +} + size_t length_heim_any(const heim_any *data) { @@ -122,6 +128,12 @@ free_HEIM_ANY(heim_any *data) der_free_octet_string(data); } +char * +print_HEIM_ANY(const heim_any *data) +{ + return der_print_octet_string(data, 0); +} + size_t length_HEIM_ANY(const heim_any *data) { @@ -154,6 +166,12 @@ free_heim_any_set(heim_any_set *data) der_free_octet_string(data); } +char * +print_heim_any_set(const heim_any_set *data) +{ + return der_print_octet_string(data, 0); +} + size_t length_heim_any_set(const heim_any *data) { @@ -192,6 +210,12 @@ free_HEIM_ANY_SET(heim_any_set *data) der_free_octet_string(data); } +char * +print_HEIM_ANY_SET(const heim_any_set *data) +{ + return der_print_octet_string(data, 0); +} + size_t length_HEIM_ANY_SET(const heim_any *data) { diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index 3dd09b959..2373b060f 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -237,6 +237,11 @@ init_generate (const char *filename, const char *base) "typedef struct heim_base_data heim_any_set;\n" "typedef struct heim_base_data HEIM_ANY;\n" "typedef struct heim_base_data HEIM_ANY_SET;\n\n"); + + fprintf (headerfile, + "enum asn1_print_flags {\n" + " ASN1_PRINT_INDENT = 1,\n" + "};\n\n"); fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \\\n" " do { \\\n" " (BL) = length_##T((S)); \\\n" @@ -1675,6 +1680,12 @@ generate_type (const Symbol *s) exp, s->gen_name, s->gen_name); + if (template_flag) + fprintf(h, + "%schar * ASN1CALL print_%s (const %s *, int);\n", + exp, + s->gen_name, s->gen_name); + fprintf(h, "\n\n"); if (!one_code_file) { diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c index 82fc053a9..be1dc6ff9 100644 --- a/lib/asn1/gen_template.c +++ b/lib/asn1/gen_template.c @@ -295,6 +295,8 @@ 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 void add_line_string(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); static void add_line_pointer_reference(struct templatehead *, const char *, const char *, const char *, ...) __attribute__ ((__format__ (__printf__, 4, 5))); @@ -384,6 +386,8 @@ tlist_cmp(const struct tlist *tl, const struct tlist *ql) int ret; struct template *t, *q; + if (tl == ql) + return 0; ret = strcmp(tl->header, ql->header); if (ret) return ret; @@ -470,6 +474,28 @@ add_line_pointer(struct templatehead *t, q->ptr = strdup(ptr); } +static void +add_line_string(struct templatehead *t, + const char *str, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + q = add_line(t, "{ %s, %s, \"%s\" }", tt, offset, str); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(str); +} + static void add_line_pointer_reference(struct templatehead *t, const char *ptr, @@ -755,6 +781,7 @@ template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) sort_object_set(os, typeidfield, &objects, &nobjs); tl = tlist_new(os->symbol->name); + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", os->symbol->name); for (i = 0; i < nobjs; i++) { ObjectField *typeidobjf = NULL, *opentypeobjf = NULL; ObjectField *of; @@ -777,6 +804,7 @@ template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) continue; } + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", o->symbol->name); /* * Some of this logic could stand to move into sanity checks of object * definitions in asn1parse.y. @@ -849,6 +877,17 @@ template_open_type(struct templatehead *temp, free(s); } +static void +template_names(struct templatehead *temp, const char *basetype, const Type *t) +{ + Member *m; + + add_line_string(temp, basetype, "0", "A1_OP_NAME"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line_string(temp, m->name, "0", "A1_OP_NAME"); + } +} + static void template_members(struct templatehead *temp, const char *basetype, @@ -968,7 +1007,7 @@ template_members(struct templatehead *temp, output_name(bname); HEIM_TAILQ_FOREACH(m, t->members, members) { - add_line(&template, "{ 0, %d, 0 } /* %s */", m->val, m->gen_name); + add_line(&template, "{ 0, %d, \"%s\" }", m->val, m->gen_name); } HEIM_TAILQ_FOREACH(q, &template, members) { @@ -1038,6 +1077,9 @@ template_members(struct templatehead *temp, template_open_type(temp, basetype, t, typeididx, opentypeidx, typeidfield, opentypefield, opentypemember, is_array_of_open_type); + + if (isstruct) + template_names(temp, basetype, t); break; } case TSequence: { @@ -1086,6 +1128,9 @@ template_members(struct templatehead *temp, template_open_type(temp, basetype, t, typeididx, opentypeidx, typeidfield, opentypefield, opentypemember, is_array_of_open_type); + + if (isstruct) + template_names(temp, basetype, t); break; } case TTag: { @@ -1233,6 +1278,10 @@ template_members(struct templatehead *temp, free(newbasename); } + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line(&template, "{ 0, 0, \"%s\" }", m->name); + } + e = NULL; if (ellipsis) { if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL) @@ -1276,10 +1325,11 @@ gen_extern_stubs(FILE *f, const char *name) "\t(asn1_type_length)length_%s,\n" "\t(asn1_type_copy)copy_%s,\n" "\t(asn1_type_release)free_%s,\n" + "\t(asn1_type_print)print_%s,\n" "\tsizeof(%s)\n" "};\n", name, name, name, name, - name, name, name); + name, name, name, name); } void @@ -1463,4 +1513,16 @@ generate_template(const Symbol *s) s->gen_name, s->gen_name, dupname); + + fprintf(f, + "\n" + "char *\n" + "print_%s(const %s *data, int flags)\n" + "{\n" + " return _asn1_print_top(asn1_%s, flags, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); } diff --git a/lib/asn1/heim_asn1.h b/lib/asn1/heim_asn1.h index 0f8ff65d1..90fc1de61 100644 --- a/lib/asn1/heim_asn1.h +++ b/lib/asn1/heim_asn1.h @@ -37,6 +37,7 @@ int encode_heim_any(unsigned char *, size_t, const heim_any *, size_t *); int decode_heim_any(const unsigned char *, size_t, heim_any *, size_t *); void free_heim_any(heim_any *); +char *print_heim_any(const heim_any *); size_t length_heim_any(const heim_any *); int copy_heim_any(const heim_any *, heim_any *); @@ -45,6 +46,7 @@ int encode_heim_any_set(unsigned char *, size_t, int decode_heim_any_set(const unsigned char *, size_t, heim_any_set *,size_t *); void free_heim_any_set(heim_any_set *); +char *print_heim_any_set(const heim_any_set *); size_t length_heim_any_set(const heim_any_set *); int copy_heim_any_set(const heim_any_set *, heim_any_set *); int heim_any_cmp(const heim_any_set *, const heim_any_set *); @@ -52,6 +54,7 @@ int heim_any_cmp(const heim_any_set *, const heim_any_set *); int encode_HEIM_ANY(unsigned char *, size_t, const heim_any *, size_t *); int decode_HEIM_ANY(const unsigned char *, size_t, heim_any *, size_t *); void free_HEIM_ANY(heim_any *); +char *print_HEIM_ANY(const heim_any *); size_t length_HEIM_ANY(const heim_any *); int copy_HEIM_ANY(const heim_any *, heim_any *); @@ -60,6 +63,7 @@ int encode_HEIM_ANY_SET(unsigned char *, size_t, int decode_HEIM_ANY_SET(const unsigned char *, size_t, heim_any_set *,size_t *); void free_HEIM_ANY_SET(heim_any_set *); +char *print_HEIM_ANY_SET(const heim_any_set *); size_t length_HEIM_ANY_SET(const heim_any_set *); int copy_HEIM_ANY_SET(const heim_any_set *, heim_any_set *); int heim_any_cmp(const heim_any_set *, const heim_any_set *); diff --git a/lib/asn1/libasn1-exports.def b/lib/asn1/libasn1-exports.def index 956a099d0..10caf5b81 100644 --- a/lib/asn1/libasn1-exports.def +++ b/lib/asn1/libasn1-exports.def @@ -2221,6 +2221,360 @@ EXPORTS length_X690SampleEmployeeNumber length_X690SampleName length_X690SamplePersonnelRecord + print_AccessDescription + print_AD_AND_OR + print_AD_IF_RELEVANT + print_AD_INITIAL_VERIFIED_CAS + print_AD_KDCIssued + print_AD_LoginAlias + print_AD_MANDATORY_FOR_KDC + print_AlgorithmIdentifier + print_AliasIA5String + print_AliasPrintableString + print_AliasUTF8String + print_APOptions + print_AP_REP + print_AP_REQ + print_AS_REP + print_AS_REQ + print_Attribute + print_AttributeSet + print_AttributeType + print_AttributeTypeAndValue + print_AttributeValue + print_AttributeValues + print_AUTHDATA_TYPE + print_Authenticator + print_AuthorityInfoAccessSyntax + print_AuthorityKeyIdentifier + print_AuthorizationData + print_AuthorizationDataElement + print_AuthPack + print_AuthPack_Win2k + print_BaseDistance + print_BasicConstraints + print_Certificate + print_CertificateList + print_CertificatePolicies + print_CertificateRevocationLists + print_Certificates + print_CertificateSerialNumber + print_CertificateSet + print_CertificationRequest + print_CertificationRequestInfo + print_CertPolicyId + print_ChangePasswdDataMS + print_Checksum + print_CKSUMTYPE + print_CMSAttributes + print_CMSCBCParameter + print_CMSEncryptedData + print_CMSIdentifier + print_CMSRC2CBCParameter + print_CMSVersion + print_CommonCriteriaMeasures + print_CommunityIdentifier + print_CommunityIdentifiers + print_ContentEncryptionAlgorithmIdentifier + print_ContentInfo + print_ContentType + print_CPSuri + print_CRLCertificateList + print_CRLDistributionPoints + print_CRLReason + print_CurrentFWConfig + print_DecryptKeyIdentifier + print_DHNonce + print_DHParameter + print_DHPublicKey + print_DHRepInfo + print_DigestAlgorithmIdentifier + print_DigestAlgorithmIdentifiers + print_DigestError + print_DigestInfo + print_DigestInit + print_DigestInitReply + print_DigestREP + print_DigestRepInner + print_DigestREQ + print_DigestReqInner + print_DigestRequest + print_DigestResponse + print_DigestTypes + print_DirectoryString + print_DisplayText + print_DistributionPoint + print_DistributionPointName + print_DistributionPointReasonFlags + print_DomainParameters + print_DSAParams + print_DSAPublicKey + print_DSASigValue + print_ECDSA_Sig_Value + print_ECParameters + print_ECPoint + print_EKCertificateGenerationLocation + print_EKGenerationLocation + print_EKGenerationType + print_EncAPRepPart + print_EncapsulatedContentInfo + print_EncASRepPart + print_EncKDCRepPart + print_EncKrbCredPart + print_EncKrbPrivPart + print_EncryptedContent + print_EncryptedContentInfo + print_EncryptedData + print_EncryptedKey + print_EncryptionKey + print_EncTGSRepPart + print_EncTicketPart + print_ENCTYPE + print_EnvelopedData + print_ETYPE_INFO + print_ETYPE_INFO2 + print_ETYPE_INFO2_ENTRY + print_ETYPE_INFO_ENTRY + print_EtypeList + print_EvaluationAssuranceLevel + print_EvaluationStatus + print_Extension + print_Extensions + print_ExternalPrincipalIdentifier + print_ExternalPrincipalIdentifiers + print_ExtKeyUsage + print_FastOptions + print_FIPSLevel + print_FirmwarePackageIdentifier + print_FirmwarePackageInfo + print_FirmwarePackageLoadError + print_FirmwarePackageLoadErrorCode + print_FirmwarePackageLoadReceipt + print_FirmwarePkgData + print_FWErrorVersion + print_FWReceiptVersion + print_GeneralName + print_GeneralNames + print_GeneralSubtree + print_GeneralSubtrees + print_HardwareModuleName + print_HardwareModules + print_HardwareSerialEntry + print_heim_any + print_HEIM_ANY + print_heim_any_set + print_HEIM_ANY_SET + print_HostAddress + print_HostAddresses + print_ImplementedCompressAlgorithms + print_ImplementedCryptoAlgorithms + print_IssuerAndSerialNumber + print_KDCDHKeyInfo + print_KDCDHKeyInfo_Win2k + print_KDCFastCookie + print_KDCFastFlags + print_KDCFastState + print_KDCOptions + print_KDC_PROXY_MESSAGE + print_KDC_REP + print_KDC_REQ + print_KDC_REQ_BODY + print_KDFAlgorithmId + print_KERB_ARMOR_SERVICE_REPLY + print_KERB_CRED + print_KerberosString + print_KerberosTime + print_KERB_TGS_REP_IN + print_KERB_TGS_REP_OUT + print_KERB_TGS_REQ_IN + print_KERB_TGS_REQ_OUT + print_KERB_TIMES + print_KeyEncryptionAlgorithmIdentifier + print_KeyIdentifier + print_KeyTransRecipientInfo + print_KeyUsage + print_Krb5Int32 + print_KRB5PrincipalName + print_KRB5SignedPath + print_KRB5SignedPathData + print_Krb5UInt32 + print_KRB_CRED + print_KrbCredInfo + print_KRB_ERROR + print_KrbFastArmor + print_KrbFastArmoredRep + print_KrbFastArmoredReq + print_KrbFastFinished + print_KrbFastReq + print_KrbFastResponse + print_KRB_PRIV + print_KRB_SAFE + print_KRB_SAFE_BODY + print_Kx509CSRPlus + print_Kx509ErrorCode + print_KX509_ERROR_CODE + print_Kx509Request + print_Kx509Response + print_LastReq + print_LR_TYPE + print_MessageDigest + print_MESSAGE_TYPE + print_METHOD_DATA + print_MS_UPN_SAN + print_Name + print_NameConstraints + print_NAME_TYPE + print_NoticeReference + print_NTLMInit + print_NTLMInitReply + print_NTLMReply + print_NTLMRequest + print_NTLMRequest2 + print_NTLMResponse + print_OCSPBasicOCSPResponse + print_OCSPCertID + print_OCSPCertStatus + print_OCSPInnerRequest + print_OCSPKeyHash + print_OCSPRequest + print_OCSPResponderID + print_OCSPResponse + print_OCSPResponseBytes + print_OCSPResponseData + print_OCSPResponseStatus + print_OCSPSignature + print_OCSPSingleResponse + print_OCSPTBSRequest + print_OCSPVersion + print_OriginatorInfo + print_OtherName + print_PA_DATA + print_PADATA_TYPE + print_PA_ENC_SAM_RESPONSE_ENC + print_PA_ENC_TS_ENC + print_PA_FX_FAST_REPLY + print_PA_FX_FAST_REQUEST + print_PA_PAC_REQUEST + print_PA_PK_AS_REP + print_PA_PK_AS_REP_BTMM + print_PA_PK_AS_REP_Win2k + print_PA_PK_AS_REQ + print_PA_PK_AS_REQ_Win2k + print_PA_S4U2Self + print_PA_SAM_CHALLENGE_2 + print_PA_SAM_CHALLENGE_2_BODY + print_PA_SAM_REDIRECT + print_PA_SAM_RESPONSE_2 + print_PA_SAM_TYPE + print_PA_ServerReferralData + print_PA_SERVER_REFERRAL_DATA + print_PA_SvrReferralData + print_PermanentIdentifier + print_PKAuthenticator + print_PKAuthenticator_Win2k + print_PKCS12_Attribute + print_PKCS12_Attributes + print_PKCS12_AuthenticatedSafe + print_PKCS12_CertBag + print_PKCS12_MacData + print_PKCS12_OctetString + print_PKCS12_PBEParams + print_PKCS12_PFX + print_PKCS12_SafeBag + print_PKCS12_SafeContents + print_PKCS8Attributes + print_PKCS8EncryptedData + print_PKCS8EncryptedPrivateKeyInfo + print_PKCS8PrivateKey + print_PKCS8PrivateKeyAlgorithmIdentifier + print_PKCS8PrivateKeyInfo + print_PKCS9_BMPString + print_PKCS9_friendlyName + print_PkinitSP80056AOtherInfo + print_PkinitSuppPubInfo + print_PKIXXmppAddr + print_PolicyConstraints + print_PolicyInformation + print_PolicyMapping + print_PolicyMappings + print_PolicyQualifierId + print_PolicyQualifierInfo + print_PolicyQualifierInfos + print_PreferredOrLegacyPackageIdentifier + print_PreferredOrLegacyStalePackageIdentifier + print_PreferredPackageIdentifier + print_Principal + print_PrincipalName + print_Principals + print_PrivateKeyUsagePeriod + print_PROV_SRV_LOCATION + print_ProxyCertInfo + print_ProxyPolicy + print_RDNSequence + print_Realm + print_RecipientIdentifier + print_RecipientInfo + print_RecipientInfos + print_RelativeDistinguishedName + print_ReplyKeyPack + print_ReplyKeyPack_Win2k + print_RSAPrivateKey + print_RSAPublicKey + print_SAMFlags + print_SecurityLevel + print_SignatureAlgorithmIdentifier + print_SignatureValue + print_SignedData + print_SignerIdentifier + print_SignerInfo + print_SignerInfos + print_SingleAttribute + print_SkipCerts + print_SRVName + print_StrengthOfFunction + print_SubjectDirectoryAttributes + print_SubjectInfoAccessSyntax + print_SubjectKeyIdentifier + print_SubjectPublicKeyInfo + print_TargetHardwareIdentifiers + print_TBSCertificate + print_TBSCRLCertList + print_TD_DH_PARAMETERS + print_TD_INVALID_CERTIFICATES + print_TD_TRUSTED_CERTIFIERS + print_TGS_REP + print_TGS_REQ + print_Ticket + print_TicketFlags + print_Time + print_TPMSecurityAssertions + print_TPMSpecification + print_TPMVersion + print_TransitedEncoding + print_TrustedCA + print_TrustedCA_Win2k + print_TypedData + print_TYPED_DATA + print_UniqueIdentifier + print_UnprotectedAttributes + print_URIReference + print_UserNotice + print_ValidationParms + print_Validity + print_VendorLoadErrorCode + print_Version + print_WrappedFirmwareKey + print_X520CommonName + print_X520LocalityName + print_X520name + print_X520OrganizationalUnitName + print_X520OrganizationName + print_X520StateOrProvinceName + print_X690SampleChildInformation + print_X690SampleDate + print_X690SampleEmployeeNumber + print_X690SampleName + print_X690SamplePersonnelRecord remove_AttributeValues remove_AuthorizationData remove_CertificatePolicies diff --git a/lib/asn1/oid_resolution.c b/lib/asn1/oid_resolution.c index b58ba98a7..1f631415f 100644 --- a/lib/asn1/oid_resolution.c +++ b/lib/asn1/oid_resolution.c @@ -319,6 +319,7 @@ der_print_heim_oid_sym(const heim_oid *oid, char delim, char **strp) const char *sym; char *s1 = NULL; char *s2 = NULL; + char *p; int ret; if (der_find_heim_oid_by_oid(oid, &sym)) @@ -330,6 +331,11 @@ der_print_heim_oid_sym(const heim_oid *oid, char delim, char **strp) *strp = s1; return 0; } + p = s2 + strlen(s1) + 1; + for (p = s2 + strlen(s1) + 1; *p; p++) { + if (*p == '_') + *p = '-'; + } *strp = s2; free(s1); return 0; diff --git a/lib/asn1/template.c b/lib/asn1/template.c index 93225cda0..fe6c4f1dd 100644 --- a/lib/asn1/template.c +++ b/lib/asn1/template.c @@ -35,6 +35,7 @@ #include "der_locl.h" #include +#include struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = { #define el(name, type) { \ @@ -43,6 +44,7 @@ struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = { (asn1_type_length)der_length_##name, \ (asn1_type_copy)der_copy_##name, \ (asn1_type_release)der_free_##name, \ + (asn1_type_print)der_print_##name, \ sizeof(type) \ } #define elber(name, type) { \ @@ -51,6 +53,7 @@ struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = { (asn1_type_length)der_length_##name, \ (asn1_type_copy)der_copy_##name, \ (asn1_type_release)der_free_##name, \ + (asn1_type_print)der_print_##name, \ sizeof(type) \ } el(integer, int), @@ -73,7 +76,8 @@ struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = { 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) + (asn1_type_release)der_free_integer, (asn1_type_print)der_print_boolean, + sizeof(int) }, el(oid, heim_oid), el(general_string, heim_general_string), @@ -524,16 +528,23 @@ _asn1_decode_open_type(const struct asn1_template *t, * An object set template looks like: * * const struct asn1_template asn1_ObjectSetName[] = { - * { 0, 0, ((void*)17) }, // HEADER ENTRY, here 17 objects - * // then two entries per object: + * // Header entry (in this case it says there's 17 objects): + * { 0, 0, ((void*)17) }, + * + * // here's the name of the object set: + * { A1_OP_NAME, 0, "ObjectSetName" }, + * + * // then three entries per object: object name, object type ID, + * // object type: + * { A1_OP_NAME, 0, "ext-AuthorityInfoAccess" }, * { A1_OP_OPENTYPE_ID, 0, (const void*)&asn1_oid_oidName }, * { A1_OP_OPENTYPE, sizeof(SomeType), (const void*)&asn1_SomeType }, * ... * }; * - * `i' will be a logical object offset, so i*2+1 will be the index of the - * A1_OP_OPENTYPE_ID entry for the current object, and i*2+2 will be the - * index of the A1_OP_OPENTYPE entry for the current object. + * `i' being a logical object offset, i*3+3 would be the index of the + * A1_OP_OPENTYPE_ID entry for the current object, and i*3+4 the index of + * the A1_OP_OPENTYPE entry for the current object. */ if (t->tt & A1_OS_IS_SORTED) { size_t left = 0; @@ -544,13 +555,13 @@ _asn1_decode_open_type(const struct asn1_template *t, while (left <= right) { size_t mid = (left + right) >> 1; - if ((tos[1 + mid * 2].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + if ((tos[3 + mid * 3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) return 0; if (typeid_is_int) - c = typeid_int_cmp(vp, (intptr_t)tos[1 + mid * 2].ptr, + c = typeid_int_cmp(vp, (intptr_t)tos[3 + mid * 3].ptr, ttypeid_univ); else if (typeid_is_oid) - c = der_heim_oid_cmp(vp, tos[1 + mid * 2].ptr); + c = der_heim_oid_cmp(vp, tos[3 + mid * 3].ptr); if (c < 0) { if (mid) right = mid - 1; @@ -568,15 +579,15 @@ _asn1_decode_open_type(const struct asn1_template *t, } else { for (i = 0, n = A1_HEADER_LEN(tos); i < n; i++) { /* We add 1 to `i' because we're skipping the header */ - if ((tos[1 + i*2].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + if ((tos[3 + i*3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) return 0; if (typeid_is_int && typeid_int_cmp(DPO(data, ttypeid->offset), - (intptr_t)tos[1 + i*2].ptr, + (intptr_t)tos[3 + i*3].ptr, ttypeid_univ)) continue; if (typeid_is_oid && - der_heim_oid_cmp(DPO(data, ttypeid->offset), tos[1 + i*2].ptr)) + der_heim_oid_cmp(DPO(data, ttypeid->offset), tos[3 + i*3].ptr)) continue; break; } @@ -592,7 +603,7 @@ _asn1_decode_open_type(const struct asn1_template *t, * the object we'll be decoding into, and its `ptr' is the pointer to the * template for decoding that type. */ - tactual_type = &tos[i*2 + 2]; + tactual_type = &tos[i*3 + 4]; /* Decode the encoded open type value(s) */ if (!(t->tt & A1_OS_OT_IS_ARRAY)) { @@ -1074,7 +1085,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, */ *element = 1; - for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) { + for (i = 1; i < A1_HEADER_LEN(choice) + 1 && choice[i].tt; i++) { /* * This is more permissive than is required. CHOICE * alternatives must have different outer tags, so in principle @@ -1102,10 +1113,11 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, return ret; } } - if (i >= A1_HEADER_LEN(choice) + 1) { + if (i >= A1_HEADER_LEN(choice) + 1 || !choice[i].tt) { if (choice->tt == 0) return ASN1_BAD_ID; + /* This is the ellipsis case */ *element = 0; ret = der_get_octet_string(p, len, DPO(data, choice->tt), &datalen); @@ -1261,13 +1273,13 @@ _asn1_encode_open_type(const struct asn1_template *t, * field. */ ret = typeid_int_copy(DPO(data, ttypeid->offset), - (intptr_t)tos[1 + (element-1)*2].ptr, ttypeid_univ); + (intptr_t)tos[3 + (element-1)*3].ptr, ttypeid_univ); } else if (typeid_is_oid) { /* * Copy the OID from the type ID object field to the type ID struct * field. */ - ret = der_copy_oid(tos[1 + (element-1)*2].ptr, DPO(data, ttypeid->offset)); + ret = der_copy_oid(tos[3 + (element-1)*3].ptr, DPO(data, ttypeid->offset)); } else enotsup = 1; @@ -1278,7 +1290,7 @@ _asn1_encode_open_type(const struct asn1_template *t, if (enotsup) return ENOTSUP; - tactual_type = &tos[(element-1)*2 + 2]; + tactual_type = &tos[(element-1)*3 + 4]; if (!(t->tt & A1_OS_OT_IS_ARRAY)) { struct heim_base_data *os = DPO(data, topentype->offset); @@ -1861,11 +1873,11 @@ _asn1_length_open_type(const struct asn1_template *tbase, } else if (typeid_is_oid) { heim_oid no_oid = { 0, 0 }; - sz = _asn1_length_open_type_id(ttypeid, tos[1 + (element - 1)*2].ptr); + sz = _asn1_length_open_type_id(ttypeid, tos[3 + (element - 1)*3].ptr); sz -= _asn1_length_open_type_id(ttypeid, &no_oid); } - tactual_type = &tos[(element-1)*2 + 2]; + tactual_type = &tos[(element-1)*3 + 4]; /* Compute the size of the encoded value(s) */ if (!(t->tt & A1_OS_OT_IS_ARRAY)) { @@ -2126,7 +2138,7 @@ _asn1_free_open_type(const struct asn1_template *t, /* object set template */ /* XXX We assume sizeof(enum) == sizeof(int) */ if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1) return; /* Unknown choice -> it's not decoded, nothing to free here */ - tactual_type = tos[2*(*elementp - 1) + 2].ptr; + tactual_type = tos[3*(*elementp - 1) + 4].ptr; if (!(t->tt & A1_OS_OT_IS_ARRAY)) { dp = DPO(data, t->offset + sizeof(*elementp)); @@ -2271,6 +2283,363 @@ _asn1_free(const struct asn1_template *t, void *data) } } +static char * +getindent(int flags, unsigned int i) +{ + char *s; + + if (!(flags & ASN1_PRINT_INDENT) || i == 0) + return NULL; + if (i > 128) + i = 128; + if ((s = malloc(i * 2 + 2)) == NULL) + return NULL; + s[0] = '\n'; + s[i * 2 + 1] = '\0'; + memset(s + 1, ' ', i * 2); + return s; +} + +static struct rk_strpool *_asn1_print(const struct asn1_template *, + struct rk_strpool *, + int, + unsigned int, + const void *, + const heim_octet_string *); + +/* See commentary in _asn1_decode_open_type() */ +static struct rk_strpool * +_asn1_print_open_type(const struct asn1_template *t, /* object set template */ + struct rk_strpool *r, + int flags, + unsigned int indent, + const void *data, + const char *opentype_name) +{ + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + const unsigned int *lenp = NULL; /* Pointer to array length field */ + unsigned int len = 1; /* Array length */ + size_t i; + const void * const *dp; + const void * const *val; + const int *elementp = DPOC(data, t->offset); /* Choice enum pointer */ + char *indents = getindent(flags, indent); + char *s; + + /* XXX We assume sizeof(enum) == sizeof(int) */ + if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1) { + r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"_ERROR_DECODING_\"", + indents ? indents : "", opentype_name); + free(indents); + } + tactual_type = tos[3*(*elementp - 1) + 4].ptr; + + r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"%s\"", + indents ? indents : "", opentype_name, + (const char *)tos[3*(*elementp - 1) + 2].ptr); + if (!r) { + free(indents); + return r; + } + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + dp = DPOC(data, t->offset + sizeof(*elementp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + if (*dp) { + struct rk_strpool *r2 = NULL; + + r2 = _asn1_print(tactual_type, r2, flags, indent + 1, *dp, NULL); + if (r2 == NULL) { + r = rk_strpoolprintf(r, + ",%s\"_%s\":\"_ERROR_FORMATTING_\"", + indents ? indents : "", opentype_name); + free(indents); + return r; + } + s = rk_strpoolcollect(r2); + r = rk_strpoolprintf(r, ",%s\"_%s\":%s", + indents ? indents : "", opentype_name, s); + free(indents); + free(s); + } + return r; + } + + lenp = DPOC(data, t->offset + sizeof(*elementp)); + len = *lenp; + dp = DPOC(data, t->offset + sizeof(*elementp) + sizeof(*lenp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + val = *dp; + + r = rk_strpoolprintf(r, ",%s\"_%s\":[", indents ? indents : "", + opentype_name); + free(indents); + indents = getindent(flags, indent + 1); + if (indents) + r = rk_strpoolprintf(r, "%s", indents ? indents : ""); + for (i = 0; r && i < len; i++) { + struct rk_strpool *r2 = NULL; + if (val[i]) { + r2 = _asn1_print(tactual_type, r2, flags, indent + 2, val[i], NULL); + if (r2 == NULL) + continue; + } + if (i) + r = rk_strpoolprintf(r, ",%s", indents ? indents : ""); + if (r) + r = rk_strpoolprintf(r, "%s", (s = rk_strpoolcollect(r2))); + free(s); + } + return rk_strpoolprintf(r, "]"); +} + +static struct rk_strpool * +_asn1_print(const struct asn1_template *t, + struct rk_strpool *r, + int flags, + unsigned int indent, + const void *data, + const heim_octet_string *saved) +{ + const struct asn1_template *tbase = t; + const struct asn1_template *tnames; + size_t nelements = A1_HEADER_LEN(t); + size_t elements = nelements; + size_t nnames = 0; + char *indents = getindent(flags, indent); + + for (t += nelements; t > tbase && (t->tt & A1_OP_MASK) == A1_OP_NAME; t--) + nnames++; + + tnames = tbase + nelements - nnames + 1; + + if (nnames) + r = rk_strpoolprintf(r, "%s{\"_type\":\"%s\"", + indents ? indents : "", + (const char *)(tnames++)->ptr); + if (saved && r) { + char *s = der_print_octet_string(data, 0); + + if (!s) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + r = rk_strpoolprintf(r, ",%s\"_save\":\"%s\"", + indents ? indents : "", s); + free(s); + } + saved = NULL; + if (tbase->tt & A1_HF_PRESERVE) + saved = data; + + t = tbase + 1; + while (elements && (t->tt & A1_OP_MASK) != A1_OP_NAME) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_NAME: + continue; + case A1_OP_DEFVAL: + t++; + elements--; + continue; + case A1_OP_OPENTYPE_OBJSET: { + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + r = _asn1_print_open_type(t, r, flags, indent + 1, data, + tbase[(nelements - nnames) + 2 + opentype].ptr); + t++; + elements--; + continue; + } + default: break; + } + if (nnames) + r = rk_strpoolprintf(r, ",%s\"%s\":", + indents ? indents : "", + (const char *)(tnames++)->ptr); + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: + break; + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + const void * const *pel = (const void *const *)el; + if (*pel == NULL) { + r = rk_strpoolprintf(r, "null"); + break; + } + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved); + } else { + const struct asn1_type_func *f = t->ptr; + char *s2 = NULL; + char *s = NULL; + + s = (f->print)(el, 0); + if (s == NULL || + rk_strasvis(&s2, s, VIS_TAB|VIS_NL|VIS_DQ, "") == -1) { + rk_strpoolfree(r); + free(indents); + free(s); + return NULL; + } + free(s); + r = rk_strpoolprintf(r, "\"%s\"", s2); + free(s2); + } + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + char *s = NULL; + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + s = (asn1_template_prim[type].print)(el, flags); + switch (type) { + case A1T_OID: + case A1T_BOOLEAN: + case A1T_INTEGER: + case A1T_INTEGER64: + case A1T_UNSIGNED: + case A1T_UNSIGNED64: + if (s) + r = rk_strpoolprintf(r, "%s", s); + break; + default: { + char *s2 = NULL; + + if (s) + (void) rk_strasvis(&s2, s, VIS_TAB|VIS_NL|VIS_DQ, ""); + free(s); + s = s2; + if (s) + r = rk_strpoolprintf(r, "\"%s\"", s); + } + } + if (!s) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + free(s); + break; + } + case A1_OP_TAG: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + const void * const *pel = (const void * const *)el; + if (*pel == NULL) { + r = rk_strpoolprintf(r, "null"); + break; + } + el = *pel; + } + + r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + r = rk_strpoolprintf(r, "%s[", indents ? indents : ""); + for (i = 0; r && i < el->len; i++) { + if (i) + r = rk_strpoolprintf(r, ",%s", indents ? indents : ""); + r = _asn1_print(t->ptr, r, flags, indent + 1, element, saved); + element += ellen; + } + if (r) + r = rk_strpoolprintf(r, "]"); + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + int first = 1; + + bmember += belements; + r = rk_strpoolprintf(r, "%s[", indents ? indents : ""); + while (r && belements) { + if (!first) + r = rk_strpoolprintf(r, ","); + if (r && _asn1_bmember_isset_bit(data, bmember->offset, size)) + r = rk_strpoolprintf(r, "%s\"%s\"", indents ? indents : "", + (const char *)bmember->ptr); + belements--; bmember--; + } + if (r) + r = rk_strpoolprintf(r, "]"); + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + unsigned int nchoices = ((uintptr_t)choice->ptr) >> 1; + + if (*element > A1_HEADER_LEN(choice)) { + r = rk_strpoolprintf(r, "null"); + } else if (*element == 0) { + r = rk_strpoolprintf(r, "null"); + } else { + choice += *element; + r = rk_strpoolprintf(r, "%s{\"_choice\":\"%s\",%s\"value\":", + indents ? indents : "", + (const char *)choice[nchoices].ptr, + indents ? indents : ""); + if (r) + r = _asn1_print(choice->ptr, r, flags, indent + 1, + DPOC(data, choice->offset), NULL); + if (r) + r = rk_strpoolprintf(r, "}"); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } + free(indents); + if (nnames && r) + return rk_strpoolprintf(r, "}"); + return r; +} + +char * +_asn1_print_top(const struct asn1_template *t, + int flags, + const void *data) +{ + struct rk_strpool *r = _asn1_print(t, NULL, flags, 0, data, NULL); + + if (r == NULL) + return NULL; + return rk_strpoolcollect(r); +} + /* See commentary in _asn1_decode_open_type() */ static int _asn1_copy_open_type(const struct asn1_template *t, /* object set template */ @@ -2299,7 +2668,7 @@ _asn1_copy_open_type(const struct asn1_template *t, /* object set template */ memset(etop, 0, sizeof(int) + sizeof(void *)); return 0; /* Unknown choice -> not copied */ } - tactual_type = &tos[2*(*efromp - 1) + 2]; + tactual_type = &tos[3*(*efromp - 1) + 4]; if (!(t->tt & A1_OS_OT_IS_ARRAY)) { dfromp = DPO(from, t->offset + sizeof(*efromp));