From ece3c688e00c3f62322a828ff9f40b8494bade09 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Wed, 24 Feb 2021 21:08:17 -0600 Subject: [PATCH] asn1: Enrich asn1_print with schema Our asn1_print, like OpenSSL's, just knows how to parse and dump DER. Ours can attempt to decode OCTET STRING and IMPLICIT-tagged constructed values as DER, which is very useful. But _now_ it's even better. Now it knows about all types exported from all ASN.1 modules in `lib/asn1/` in Heimdal, and if told to print as some type, it will use the new printing interface to print JSON-like representations of values: ``` $ ./asn1_print /tmp/t490/ek2.crt Certificate | jq '.tbsCertificate.extensions[3]._extnValue[]._values' [ { "_type": "TPMSpecification", "family": "2.0", "level": "0", "revision": "138" } ] [ { "_type": "TPMSecurityAssertions", "version": "0", "fieldUpgradable": true, "ekGenerationType": "655617", "ekGenerationLocation": "655616", "ekCertificateGenerationLocation": "655616", "ccInfo": { "_type": "CommonCriteriaMeasures", "version": "3.1", "assurancelevel": "4", "evaluationStatus": "2", "plus": true, "strengthOfFunction": null, "profileOid": null, "profileUri": null, "targetOid": null, "targetUri": null }, "fipsLevel": { "_type": "FIPSLevel", "version": "140-2", "level": "2", "plus": false }, "iso9000Certified": false, "iso9000Uri": null } ] ``` --- lib/asn1/README.md | 608 +++++++++++++++++++++++++++++++++++++++++- lib/asn1/asn1_print.1 | 94 +++++++ lib/asn1/asn1_print.c | 224 ++++++++++++++-- lib/asn1/gen.c | 20 +- 4 files changed, 911 insertions(+), 35 deletions(-) create mode 100644 lib/asn1/asn1_print.1 diff --git a/lib/asn1/README.md b/lib/asn1/README.md index c105bd334..b97c2272f 100644 --- a/lib/asn1/README.md +++ b/lib/asn1/README.md @@ -9,10 +9,10 @@ annotations](/lib/asn1/README-X681.md). 1. [Introduction](#Introduction) 2. [ASN.1 Support in Heimdal](#asn1-support-in-heimdal) - 3. [News](#News) - 4. [Features](#Features) - 5. [Limitations](#Limitations) - 6. [Compiler Usage](#Compiler-usage) + 3. [Features](#Features) + 4. [Limitations](#Limitations) + 5. [Compiler Usage](#Compiler-usage) + 6. [asn1_print Usage](#asn1_print-usage) 7. [Implementation](#implementation) 8. [Moving From C](#moving-from-c) @@ -164,7 +164,7 @@ make it easy to add support for encoding rules other than X.690. ```bash $ ./asn1_print ek.crt Certificate | - jq '.tbsCertificate.extensions[3]._open_type[]._open_type' + jq '.tbsCertificate.extensions[3]._extnValue[]._values' ``` ```JSON @@ -180,7 +180,7 @@ make it easy to add support for encoding rules other than X.690. { "_type": "TPMSecurityAssertions", "version": "0", - "fieldUpgradable": "1", + "fieldUpgradable": true, "ekGenerationType": "655617", "ekGenerationLocation": "655616", "ekCertificateGenerationLocation": "655616", @@ -189,7 +189,7 @@ make it easy to add support for encoding rules other than X.690. "version": "3.1", "assurancelevel": "4", "evaluationStatus": "2", - "plus": "1", + "plus": true, "strengthOfFunction": null, "profileOid": null, "profileUri": null, @@ -200,14 +200,564 @@ make it easy to add support for encoding rules other than X.690. "_type": "FIPSLevel", "version": "140-2", "level": "2", - "plus": "0" + "plus": false }, - "iso9000Certified": "0", + "iso9000Certified": false, "iso9000Uri": null } ] ``` + A complete dump of such a certificate: + + ```bash + $ ./asn1_print ek.crt Certificate | jq . + ``` + + ```JSON + { + "_type": "Certificate", + "tbsCertificate": { + "_type": "TBSCertificate", + "_save": "30820376A00302010202146A0597BA71D7E6D3AC0EDC9EDC95A15B998DE40A300D06092A864886F70D01010B05003055310B3009060355040613024348311E301C060355040A131553544D6963726F656C656374726F6E696373204E56312630240603550403131D53544D2054504D20454B20496E7465726D656469617465204341203035301E170D3138313231343030303030305A170D3238313231343030303030305A300030820122300D06092A864886F70D01010105000382010F003082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5F0D559B10203010001A38201A9308201A5301F0603551D230418301680141ADB994AB58BE57A0CC9B900E7851E1A43C0866030420603551D20043B303930370604551D2000302F302D06082B060105050702011621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F30590603551D110101FF044F304DA44B304931163014060567810502010C0B69643A353335343444323031173015060567810502020C0C53543333485450484148433031163014060567810502030C0B69643A303034393030303830670603551D090460305E301706056781050210310E300C0C03322E300201000202008A304306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100300E0603551D0F0101FF040403020520300C0603551D130101FF0402300030100603551D250409300706056781050801304A06082B06010505070101043E303C303A06082B06010505073002862E687474703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274", + "version": "2", + "serialNumber": "6A0597BA71D7E6D3AC0EDC9EDC95A15B998DE40A", + "signature": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.11", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 11 + ], + "name": "id-pkcs1-sha256WithRSAEncryption" + }, + "parameters": "0500" + }, + "issuer": { + "_choice": "rdnSequence", + "value": [ + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.6", + "components": [ + 2, + 5, + 4, + 6 + ], + "name": "id-at-countryName" + }, + "value": { + "_choice": "printableString", + "value": "CH" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.10", + "components": [ + 2, + 5, + 4, + 10 + ], + "name": "id-at-organizationName" + }, + "value": { + "_choice": "printableString", + "value": "STMicroelectronics NV" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.3", + "components": [ + 2, + 5, + 4, + 3 + ], + "name": "id-at-commonName" + }, + "value": { + "_choice": "printableString", + "value": "STM TPM EK Intermediate CA 05" + } + } + ] + ] + }, + "validity": { + "_type": "Validity", + "notBefore": { + "_choice": "utcTime", + "value": "2018-12-14T00:00:00Z" + }, + "notAfter": { + "_choice": "utcTime", + "value": "2028-12-14T00:00:00Z" + } + }, + "subject": { + "_choice": "rdnSequence", + "value": [] + }, + "subjectPublicKeyInfo": { + "_type": "SubjectPublicKeyInfo", + "algorithm": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.1", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 1 + ], + "name": "id-pkcs1-rsaEncryption" + }, + "parameters": "0500" + }, + "subjectPublicKey": "2160:3082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5F0D559B10203010001" + }, + "issuerUniqueID": null, + "subjectUniqueID": null, + "extensions": [ + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.35", + "components": [ + 2, + 5, + 29, + 35 + ], + "name": "id-x509-ce-authorityKeyIdentifier" + }, + "critical": false, + "extnValue": "301680141ADB994AB58BE57A0CC9B900E7851E1A43C08660", + "_extnValue_choice": "ext-AuthorityKeyIdentifier", + "_extnValue": { + "_type": "AuthorityKeyIdentifier", + "keyIdentifier": "1ADB994AB58BE57A0CC9B900E7851E1A43C08660", + "authorityCertIssuer": null, + "authorityCertSerialNumber": null + } + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.32", + "components": [ + 2, + 5, + 29, + 32 + ], + "name": "id-x509-ce-certificatePolicies" + }, + "critical": false, + "extnValue": "303930370604551D2000302F302D06082B060105050702011621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F", + "_extnValue_choice": "ext-CertificatePolicies", + "_extnValue": [ + { + "_type": "PolicyInformation", + "policyIdentifier": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.32.0", + "components": [ + 2, + 5, + 29, + 32, + 0 + ], + "name": "id-x509-ce-certificatePolicies-anyPolicy" + }, + "policyQualifiers": [ + { + "_type": "PolicyQualifierInfo", + "policyQualifierId": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.3.6.1.5.5.7.2.1", + "components": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 2, + 1 + ], + "name": "id-pkix-qt-cps" + }, + "qualifier": "1621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F" + } + ] + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.17", + "components": [ + 2, + 5, + 29, + 17 + ], + "name": "id-x509-ce-subjectAltName" + }, + "critical": true, + "extnValue": "304DA44B304931163014060567810502010C0B69643A353335343444323031173015060567810502020C0C53543333485450484148433031163014060567810502030C0B69643A3030343930303038", + "_extnValue_choice": "ext-SubjectAltName", + "_extnValue": [ + { + "_choice": "directoryName", + "value": { + "_choice": "rdnSequence", + "value": [ + [ + { + "_type": "AttributeTypeAndValue", + "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", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.2", + "components": [ + 2, + 23, + 133, + 2, + 2 + ], + "name": "tcg-at-tpmModel" + }, + "value": { + "_choice": "utf8String", + "value": "ST33HTPHAHC0" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.3", + "components": [ + 2, + 23, + 133, + 2, + 3 + ], + "name": "tcg-at-tpmVersion" + }, + "value": { + "_choice": "utf8String", + "value": "id:00490008" + } + } + ] + ] + } + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.9", + "components": [ + 2, + 5, + 29, + 9 + ], + "name": "id-x509-ce-subjectDirectoryAttributes" + }, + "critical": false, + "extnValue": "305E301706056781050210310E300C0C03322E300201000202008A304306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100", + "_extnValue_choice": "ext-SubjectDirectoryAttributes", + "_extnValue": [ + { + "_type": "AttributeSet", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.16", + "components": [ + 2, + 23, + 133, + 2, + 16 + ], + "name": "tcg-at-tpmSpecification" + }, + "values": [ + "300C0C03322E300201000202008A" + ], + "_values_choice": "at-TPMSpecification", + "_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-tpmSecurityAssertions" + }, + "values": [ + "30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100" + ], + "_values_choice": "at-TPMSecurityAssertions", + "_values": [ + { + "_type": "TPMSecurityAssertions", + "version": "0", + "fieldUpgradable": true, + "ekGenerationType": "655617", + "ekGenerationLocation": "655616", + "ekCertificateGenerationLocation": "655616", + "ccInfo": { + "_type": "CommonCriteriaMeasures", + "version": "3.1", + "assurancelevel": "4", + "evaluationStatus": "2", + "plus": true, + "strengthOfFunction": null, + "profileOid": 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": true, + "extnValue": "03020520", + "_extnValue_choice": "ext-KeyUsage", + "_extnValue": [ + "keyEncipherment" + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.19", + "components": [ + 2, + 5, + 29, + 19 + ], + "name": "id-x509-ce-basicConstraints" + }, + "critical": true, + "extnValue": "3000", + "_extnValue_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": "id-x509-ce-extKeyUsage" + }, + "critical": false, + "extnValue": "300706056781050801", + "_extnValue_choice": "ext-ExtKeyUsage", + "_extnValue": [ + { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.8.1", + "components": [ + 2, + 23, + 133, + 8, + 1 + ], + "name": "tcg-kp-EKCertificate" + } + ] + }, + { + "_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" + }, + "critical": false, + "extnValue": "303C303A06082B06010505073002862E687474703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274", + "_extnValue_choice": "ext-AuthorityInfoAccess", + "_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": "uniformResourceIdentifier", + "value": "http://secure.globalsign.com/stmtpmekint05.crt" + } + } + ] + } + ] + }, + "signatureAlgorithm": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.11", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 11 + ], + "name": "id-pkcs1-sha256WithRSAEncryption" + }, + "parameters": "0500" + }, + "signatureValue": "2048:3D4C381E5B4F1BCBE09C63D52F1F04570CAEA142FD9CD942043B11F8E3BDCF50007AE16CF8869013041E92CDD3280BA4B51FBBD40582ED750219E261A695095674855AACEB520ADAFF9E7E908480A39CDCF900462D9171960FFE55D3AC49E8C981341BBD2EFBCC252A4C18A4F3B7C84CCE42CE70A208C84D2630A7ABFBE72D6271E75B9FF1C971D20EB3DBD763F1E04D834EAA692D2E4001BBF4730A3E3FDA9711AE386524D91C63BE0E516D00D5C6141FCCF6C539F3518E180049865BE16B69CAE1F8CB7FDC474B38F7EE56CBE7D8A89D9BA99B65D5265AEF32AA62426B10E6D75BB8677EC44F755BBC2806FD2B4E04BDF5D44259DBEAA42B6F563DF7AA7506" + } + ``` + + (Notice that OID names look a bit weird. For reasons that may have been + lost to time and may no longer be relevant, these OIDs are defined with + slightly different names in the ASN.1 modules in Heimdal's source tree. + We'll fix this eventually.) + - 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 @@ -349,6 +899,46 @@ HEIMDAL February 22, 2021 HEIMDAL ``` +## asn1_print Usage + +``` +ASN1_PRINT(1) BSD General Commands Manual ASN1_PRINT(1) + +NAME + asn1_print — dump ASN.1 DER encoded values + +SYNOPSIS + asn1_print [-i | --no-indent] [-I | --inner] [-l | --list-types] + [-l -v | --version] [-l -h | --help] [FILE [TypeName]] + +DESCRIPTION + asn1_print Dumps ASN.1 DER-encoded values. If a TypeName is given, then + asn1_print will print the value in a JSON-like format using its knowledge + of the ASN.1 module defining that type. If a TypeName is given, it must + be the name of an ASN.1 type exported by an ASN.1 module that is compiled + into asn1_print. Use the --list-types option to list ASN.1 types known + to asn1_print. + + Options supported: + + -i, --no-indent + Do not indent dump. + + -I, --inner + Try to parse inner structures of OCTET STRING and constructed + values. + + -l, --list-types + Try to parse inner structures of OCTET STRING and constructed + values. + + -v, --version + + -h, --help + +HEIMDAL February 22, 2021 HEIMDAL +``` + ## Implementation ... diff --git a/lib/asn1/asn1_print.1 b/lib/asn1/asn1_print.1 new file mode 100644 index 000000000..ca10e7ecb --- /dev/null +++ b/lib/asn1/asn1_print.1 @@ -0,0 +1,94 @@ +.\" Copyright (c) 2021 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" 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. +.\" +.\" $Id$ +.\" +.Dd February 22, 2021 +.Dt ASN1_PRINT 1 +.Os HEIMDAL +.Sh NAME +.Nm asn1_print +.Nd dump ASN.1 DER encoded values +.Sh SYNOPSIS +.Nm +.Bk -words +.Oo Fl i \*(Ba Xo +.Fl Fl no-indent +.Xc +.Oc +.Oo Fl I \*(Ba Xo +.Fl Fl inner +.Xc +.Oc +.Oo Fl l \*(Ba Xo +.Fl Fl list-types +.Xc +.Oc +.Oo Fl l v \*(Ba Xo +.Fl Fl version +.Xc +.Oc +.Oo Fl l h \*(Ba Xo +.Fl Fl help +.Xc +.Oc +.Op Ar FILE Op Ar TypeName +.Ek +.Sh DESCRIPTION +.Nm +Dumps ASN.1 DER-encoded values. +If a +.Ar TypeName +is given, then +.Nm +will print the value in a JSON-like format using its knowledge of +the ASN.1 module defining that type. +If a +.Ar TypeName +is given, it must be the name of an ASN.1 type exported by an +ASN.1 module that is compiled into +.Nm . +Use the +.Fl Fl list-types +option to list ASN.1 types known to +.Nm . +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl i, Fl Fl no-indent +Do not indent dump. +.It Fl I, Fl Fl inner +Try to parse inner structures of OCTET STRING and constructed values. +.It Fl l, Fl Fl list-types +Try to parse inner structures of OCTET STRING and constructed values. +.It Fl v, Fl Fl version +.It Fl h, Fl Fl help +.El diff --git a/lib/asn1/asn1_print.c b/lib/asn1/asn1_print.c index f45983c12..99ebe3ba2 100644 --- a/lib/asn1/asn1_print.c +++ b/lib/asn1/asn1_print.c @@ -37,9 +37,23 @@ #include #include #include +#include #include #include #include +#include "cms_asn1.h" +#include "digest_asn1.h" +#include "krb5_asn1.h" +#include "kx509_asn1.h" +#include "ocsp_asn1.h" +#include "pkcs10_asn1.h" +#include "pkcs12_asn1.h" +#include "pkcs8_asn1.h" +#include "pkcs9_asn1.h" +#include "pkinit_asn1.h" +#include "rfc2459_asn1.h" +#include "rfc4108_asn1.h" +#include "x690sample_asn1.h" static int indent_flag = 1; static int inner_flag = 0; @@ -47,6 +61,41 @@ static int inner_flag = 0; static unsigned long indefinite_form_loop; static unsigned long indefinite_form_loop_max = 10000; +typedef int (*decoder)(const unsigned char *, size_t, void *, size_t *); +typedef char *(*printer)(const void *, int); +typedef void (*releaser)(void *); +struct types { + const char *name; + decoder decode; + printer print; + releaser release; + size_t sz; +} types[] = { +#define ASN1_SYM_INTVAL(n, gn, gns, i) +#define ASN1_SYM_OID(n, gn, gns) +#define ASN1_SYM_TYPE(n, gn, gns) \ + { \ + n, \ + (decoder)decode_ ## gns, \ + (printer)print_ ## gns, \ + (releaser)free_ ## gns, \ + sizeof(gns) \ + }, +#include "cms_asn1_syms.x" +#include "digest_asn1_syms.x" +#include "krb5_asn1_syms.x" +#include "kx509_asn1_syms.x" +#include "ocsp_asn1_syms.x" +#include "pkcs10_asn1_syms.x" +#include "pkcs12_asn1_syms.x" +#include "pkcs8_asn1_syms.x" +#include "pkcs9_asn1_syms.x" +#include "pkinit_asn1_syms.x" +#include "rfc2459_asn1_syms.x" +#include "rfc4108_asn1_syms.x" +#include "x690sample_asn1_syms.x" +}; + static size_t loop (unsigned char *buf, size_t len, int indent) { @@ -289,44 +338,161 @@ loop (unsigned char *buf, size_t len, int indent) } static int -doit (const char *filename) +type_cmp(const void *va, const void *vb) { - int fd = open (filename, O_RDONLY); + const struct types *ta = (const struct types *)va; + const struct types *tb = (const struct types *)vb; + + return strcmp(ta->name, tb->name); +} + +static int +doit(const char *filename, const char *typename) +{ + int fd = open(filename, O_RDONLY); struct stat sb; unsigned char *buf; size_t len; int ret; if(fd < 0) - err (1, "opening %s for read", filename); + err(1, "opening %s for read", filename); if (fstat (fd, &sb) < 0) - err (1, "stat %s", filename); + err(1, "stat %s", filename); len = sb.st_size; - buf = emalloc (len); - if (read (fd, buf, len) != len) - errx (1, "read failed"); - close (fd); - ret = loop (buf, len, 0); - free (buf); + buf = emalloc(len); + if (read(fd, buf, len) != len) + errx(1, "read failed"); + close(fd); + if (typename) { + struct types *sorted_types = emalloc(sizeof(types)); + size_t right = sizeof(types)/sizeof(types[0]) - 1; + size_t left = 0; + size_t mid; + size_t sz; + char *s; + void *v; + int c = -1; + + memcpy(sorted_types, types, sizeof(types)); + qsort(sorted_types, + sizeof(types)/sizeof(types[0]), + sizeof(types[0]), + type_cmp); + + while (left <= right) { + mid = (left + right) >> 1; + c = strcmp(sorted_types[mid].name, typename); + if (c < 0) + left = mid + 1; + else if (c > 0) + right = mid - 1; + else + break; + } + if (c != 0) + errx(1, "Type %s not found", typename); + v = ecalloc(1, sorted_types[mid].sz); + ret = sorted_types[mid].decode(buf, len, v, &sz); + if (ret == 0) { + s = sorted_types[mid].print(v, + indent_flag ? ASN1_PRINT_INDENT : 0); + sorted_types[mid].release(v); + if (!s) + ret = errno; + } + if (ret == 0) { + fprintf(stdout, "%s\n", s); + free(buf); + free(s); + exit(0); + } + switch (ret) { + case ASN1_BAD_TIMEFORMAT: + errx(1, "Could not decode and print data as type %s: " + "Bad time format", typename); + case ASN1_MISSING_FIELD: + errx(1, "Could not decode and print data as type %s: " + "Missing required field", typename); + case ASN1_MISPLACED_FIELD: + errx(1, "Could not decode and print data as type %s: " + "Fields out of order", typename); + case ASN1_TYPE_MISMATCH: + errx(1, "Could not decode and print data as type %s: " + "Type mismatch", typename); + case ASN1_OVERFLOW: + errx(1, "Could not decode and print data as type %s: " + "DER value too large", typename); + case ASN1_OVERRUN: + errx(1, "Could not decode and print data as type %s: " + "DER value too short", typename); + case ASN1_BAD_ID: + errx(1, "Could not decode and print data as type %s: " + "DER tag is unexpected", typename); + case ASN1_BAD_LENGTH: + errx(1, "Could not decode and print data as type %s: " + "DER length does not match value", typename); + case ASN1_BAD_FORMAT: + case ASN1_PARSE_ERROR: + errx(1, "Could not decode and print data as type %s: " + "DER badly formatted", typename); + case ASN1_EXTRA_DATA: + errx(1, "Could not decode and print data as type %s: " + "Extra data past end of end structure", typename); + case ASN1_BAD_CHARACTER: + errx(1, "Could not decode and print data as type %s: " + "Invalid character encoding in string", typename); + case ASN1_MIN_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Too few elements", typename); + case ASN1_MAX_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Too many elements", typename); + case ASN1_EXACT_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Wrong count of elements", typename); + case ASN1_INDEF_OVERRUN: + errx(1, "Could not decode and print data as type %s: " + "BER indefinte encoding overun", typename); + case ASN1_INDEF_UNDERRUN: + errx(1, "Could not decode and print data as type %s: " + "BER indefinte encoding underun", typename); + case ASN1_GOT_BER: + errx(1, "Could not decode and print data as type %s: " + "BER encoding when DER expected", typename); + case ASN1_INDEF_EXTRA_DATA: + errx(1, "Could not decode and print data as type %s: " + "End-of-contents tag contains data", typename); + default: + err(1, "Could not decode and print data as type %s", typename); + } + + } + ret = loop(buf, len, 0); + free(buf); return ret; } +static int list_types_flag = 0; static int version_flag; static int help_flag; struct getargs args[] = { - { "indent", 0, arg_negative_flag, &indent_flag, NULL, NULL }, - { "inner", 0, arg_flag, &inner_flag, - "try to parse inner structures of OCTET STRING", NULL }, - { "version", 0, arg_flag, &version_flag, NULL, NULL }, - { "help", 0, arg_flag, &help_flag, NULL, NULL } + { "indent", 'i', arg_negative_flag, &indent_flag, + "\tdo not indent dump", NULL }, + { "inner", 'I', arg_flag, &inner_flag, + "\ttry to parse inner structures of OCTET STRING", NULL }, + { "list-types", 'l', arg_flag, &list_types_flag, + "\tlist ASN.1 types known to this program", NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL } }; int num_args = sizeof(args) / sizeof(args[0]); static void usage(int code) { - arg_printusage(args, num_args, NULL, "dump-file"); + arg_printusage(args, num_args, NULL, "dump-file [TypeName]"); exit(code); } @@ -335,19 +501,29 @@ main(int argc, char **argv) { int optidx = 0; - setprogname (argv[0]); - initialize_asn1_error_table (); - if(getarg(args, num_args, argc, argv, &optidx)) + setprogname(argv[0]); + initialize_asn1_error_table(); + if (getarg(args, num_args, argc, argv, &optidx)) usage(1); - if(help_flag) + if (help_flag) usage(0); - if(version_flag) { + if (version_flag) { print_version(NULL); exit(0); } argv += optidx; argc -= optidx; - if (argc != 1) - usage (1); - return doit (argv[0]); + if (list_types_flag) { + size_t i; + + if (argc) + usage(1); + + for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) + printf("%s\n", types[i].name); + exit(0); + } + if (argc != 1 && argc != 2) + usage(1); + return doit(argv[0], argv[1]); } diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index 2373b060f..df9f93713 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -41,6 +41,7 @@ extern int prefix_enum; RCSID("$Id$"); FILE *privheaderfile, *headerfile, *oidsfile, *codefile, *logfile, *templatefile; +FILE *symsfile; #define STEM "asn1" @@ -285,6 +286,11 @@ init_generate (const char *filename, const char *base) oidsfile = fopen(fn, "w"); if (oidsfile == NULL) err (1, "open %s", fn); + if (asprintf(&fn, "%s_syms.x", base) < 0 || fn == NULL) + errx(1, "malloc"); + symsfile = fopen(fn, "w"); + if (symsfile == NULL) + err (1, "open %s", fn); free(fn); fn = NULL; @@ -462,6 +468,10 @@ generate_constant (const Symbol *s) "enum { %s = %lld };\n\n", s->gen_name, s->gen_name, s->gen_name, (long long)s->value->u.integervalue); + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_INTVAL(\"%s\", \"%s\", %s, %lld)\n", + s->name, s->gen_name, s->gen_name, + (long long)s->value->u.integervalue); break; case nullvalue: break; @@ -508,6 +518,9 @@ generate_constant (const Symbol *s) s->gen_name, (unsigned long)len, s->gen_name); fprintf(oidsfile, "DEFINE_OID_WITH_NAME(%s)\n", s->gen_name); + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_OID(\"%s\", \"%s\", %s)\n", + s->name, s->gen_name, s->gen_name); free(list); @@ -1606,6 +1619,9 @@ generate_type_header (const Symbol *s) if (s->emitted_definition) return; + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_TYPE(\"%s\", \"%s\", %s)\n", + s->name, s->gen_name, s->gen_name); fprintf(headerfile, "typedef "); define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, preserve_type(s->name) ? TRUE : FALSE); @@ -1632,7 +1648,7 @@ generate_type (const Symbol *s) if (!one_code_file) generate_header_of_codefile(s->gen_name); - generate_type_header (s); + generate_type_header(s); if (template_flag) generate_template(s); @@ -1691,5 +1707,5 @@ generate_type (const Symbol *s) if (!one_code_file) { fprintf(codefile, "\n\n"); close_codefile(); - } + } }