From aee9f5e4e84e26ec718b56f90edcd1e8ad042eca Mon Sep 17 00:00:00 2001 From: Matthew McPherrin Date: Tue, 14 Feb 2017 21:40:46 -0800 Subject: [PATCH] Print full subject in JSON (instead of hardcoded list of members) --- lib/display.go | 21 +-------------------- lib/encoder.go | 25 +++++++++++-------------- lib/oids.go | 34 ++++++++++++++++++++++++++++++++++ tests/dump-leaf-to-json.t | 2 +- tests/dump-small-key-to-json.t | 2 +- 5 files changed, 48 insertions(+), 36 deletions(-) create mode 100644 lib/oids.go diff --git a/lib/display.go b/lib/display.go index 1c98d53..d011cb9 100644 --- a/lib/display.go +++ b/lib/display.go @@ -223,24 +223,5 @@ func redify(text string) string { } func oidify(oid asn1.ObjectIdentifier) string { - raw := oid.String() - names := map[string]string{ - "2.5.4.3": "CommonName", - "2.5.4.5": "EV Incorporation Registration Number", - "2.5.4.6": "Country", - "2.5.4.7": "Locality", - "2.5.4.8": "Province", - "2.5.4.10": "Organization", - "2.5.4.11": "Organizational Unit", - "2.5.4.15": "Business Category", - "1.2.840.113549.1.9.1": "emailAddress", - "1.3.6.1.4.1.311.60.2.1.1": "EV Incorporation Locality", - "1.3.6.1.4.1.311.60.2.1.2": "EV Incorporation Province", - "1.3.6.1.4.1.311.60.2.1.3": "EV Incorporation Country", - } - name, ok := names[raw] - if ok { - return name - } - return raw + return describeOid(oid).Name } diff --git a/lib/encoder.go b/lib/encoder.go index 75921ba..c1e9bad 100644 --- a/lib/encoder.go +++ b/lib/encoder.go @@ -180,21 +180,18 @@ func createSimpleCertificate(name string, cert *x509.Certificate) simpleCertific func (p simplePKIXName) MarshalJSON() ([]byte, error) { out := map[string]interface{}{} - if p.Name.CommonName != "" { - out["common_name"] = p.Name.CommonName - } - if len(p.Name.Organization) > 0 { - out["organization"] = p.Name.Organization - } - if len(p.Name.OrganizationalUnit) > 0 { - out["organizational_unit"] = p.Name.OrganizationalUnit - } - if len(p.Name.Country) > 0 { - out["country"] = p.Name.Country - } - if len(p.Name.Locality) > 0 { - out["locality"] = p.Name.Locality + for _, rdn := range p.Name.Names { + oid := describeOid(rdn.Type) + if prev, ok := out[oid.Slug]; oid.Multiple && ok { + l := prev.([]interface{}) + out[oid.Slug] = append(l, rdn.Value) + } else if oid.Multiple { + out[oid.Slug] = []interface{}{rdn.Value} + } else { + out[oid.Slug] = rdn.Value + } } + if len(p.KeyID) > 0 { out["key_id"] = hexify(p.KeyID) } diff --git a/lib/oids.go b/lib/oids.go new file mode 100644 index 0000000..1e3d1f3 --- /dev/null +++ b/lib/oids.go @@ -0,0 +1,34 @@ +package lib + +import "encoding/asn1" + +// OidDescription returns a human-readable name, a snake_case slug suitable as a json key, +// and a boolean describing whether multiple copies can appear on an X509 cert. +type OidDescription struct { + Name string + Slug string + Multiple bool +} + +func describeOid(oid asn1.ObjectIdentifier) OidDescription { + raw := oid.String() + // Multiple should be true for any types that are []string in x509.pkix.Name. When in doubt, set it to true. + names := map[string]OidDescription{ + "2.5.4.3": {"CommonName", "common_name", false}, + "2.5.4.5": {"EV Incorporation Registration Number", "ev_registration_number", false}, + "2.5.4.6": {"Country", "country", true}, + "2.5.4.7": {"Locality", "locality", true}, + "2.5.4.8": {"Province", "province", true}, + "2.5.4.10": {"Organization", "organization", true}, + "2.5.4.11": {"Organizational Unit", "organizational_unit", true}, + "2.5.4.15": {"Business Category", "business_category", true}, + "1.2.840.113549.1.9.1": {"Email Address", "email_address", true}, + "1.3.6.1.4.1.311.60.2.1.1": {"EV Incorporation Locality", "ev_locality", true}, + "1.3.6.1.4.1.311.60.2.1.2": {"EV Incorporation Province", "ev_province", true}, + "1.3.6.1.4.1.311.60.2.1.3": {"EV Incorporation Country", "ev_country", true}, + } + if description, ok := names[raw]; ok { + return description + } + return OidDescription{raw, raw, true} +} diff --git a/tests/dump-leaf-to-json.t b/tests/dump-leaf-to-json.t index 3a9d1cc..b4eeadb 100644 --- a/tests/dump-leaf-to-json.t +++ b/tests/dump-leaf-to-json.t @@ -27,4 +27,4 @@ Set up test data. Dump an example certificate (example-leaf.crt) to JSON output $ certigo dump --json example-leaf.crt - {"certificates":[{"serial":"15384458167827828543","not_before":"2016-06-10T22:14:11Z","not_after":"2023-04-15T22:14:11Z","signature_algorithm":"SHA256-RSA","is_self_signed":false,"subject":{"common_name":"example-leaf","country":["US"],"organization":["certigo"],"organizational_unit":["example"]},"issuer":{"common_name":"example-leaf","country":["US"],"organization":["certigo"],"organizational_unit":["example"]},"extended_key_usage":["Client Auth","Server Auth"],"dns_names":["localhost"],"ip_addresses":["127.0.0.1","::1"],"pem":"-----BEGIN CERTIFICATE-----\nMIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMH\nZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoX\nDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYD\nVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxl\nLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3\nv34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69\nw8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhR\npPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84c\nzKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF\n5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2\nNp6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAs\nBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJ\nKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sM\nlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7\nLstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7d\nvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeL\nFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2Xl\niJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU=\n-----END CERTIFICATE-----\n"}]} + {"certificates":[{"serial":"15384458167827828543","not_before":"2016-06-10T22:14:11Z","not_after":"2023-04-15T22:14:11Z","signature_algorithm":"SHA256-RSA","is_self_signed":false,"subject":{"common_name":"example-leaf","country":["US"],"organization":["certigo"],"organizational_unit":["example"],"province":["CA"]},"issuer":{"common_name":"example-leaf","country":["US"],"organization":["certigo"],"organizational_unit":["example"],"province":["CA"]},"extended_key_usage":["Client Auth","Server Auth"],"dns_names":["localhost"],"ip_addresses":["127.0.0.1","::1"],"pem":"-----BEGIN CERTIFICATE-----\nMIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4GA1UECxMH\nZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYxMDIyMTQxMVoX\nDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYD\nVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxl\nLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7stSvfQyGuHw3\nv34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKdsR/J5sbWSl8K/5djpzj31eIzqU69\nw8v7SChM5x9bouDsABHz3kZucx5cSafEgJojysBkcrq3VY+aJanzbL+qErYX+lhR\npPcZK6JMWIwar8Y3B2la4yWwieecw2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84c\nzKPyt9r40gDk2XiH/lGts5a94rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF\n5O5iSV9rEI+m2+7j2S+jHDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2\nNp6i464lAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAs\nBgNVHREEJTAjhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJ\nKoZIhvcNAQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sM\nlM05kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7\nLstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloSaa7d\nvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx8MNGvUeL\nFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObiqdsJLMVvb2Xl\niJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIU=\n-----END CERTIFICATE-----\n"}]} diff --git a/tests/dump-small-key-to-json.t b/tests/dump-small-key-to-json.t index 2870269..3b17a16 100644 --- a/tests/dump-small-key-to-json.t +++ b/tests/dump-small-key-to-json.t @@ -20,4 +20,4 @@ Set up test data. Dump an example certificate (example-leaf.crt) to JSON output $ certigo dump --json example-small-key.crt - {"certificates":[{"serial":"14381893493177441266","not_before":"2016-06-10T22:14:12Z","not_after":"2023-04-15T22:14:12Z","signature_algorithm":"SHA256-RSA","is_self_signed":true,"subject":{"common_name":"example-small-key","country":["US"],"organization":["certigo"],"organizational_unit":["example"]},"issuer":{"common_name":"example-small-key","country":["US"],"organization":["certigo"],"organizational_unit":["example"]},"warnings":["Certificate is not in X509v3 format (version is 2)","Size of RSA key should be at least 2048 bits"],"pem":"-----BEGIN CERTIFICATE-----\nMIICKzCCAZQCCQDHlr/u+lfb8jANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJV\nUzELMAkGA1UECBMCQ0ExEDAOBgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1w\nbGUxGjAYBgNVBAMTEWV4YW1wbGUtc21hbGwta2V5MB4XDTE2MDYxMDIyMTQxMloX\nDTIzMDQxNTIyMTQxMlowWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYD\nVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRowGAYDVQQDExFleGFtcGxl\nLXNtYWxsLWtleTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlzyCIeP1T87k\n1rHVMtbaGXIWpK/VQuvuXwig+e3ct1ajA4bw0BAInXZ37FEGGSCUix0k/CjH2Nlt\nGREtwbahE0k5oTkVbA5XS4xkNs0M0poAFN5OiFKEAqZ014hqhvKnEUQ2oTe9SVOR\nWw49mLNg36AIEE2Fu2KQb/VT90cwwD0CAwEAATANBgkqhkiG9w0BAQsFAAOBgQBV\nsJ4Vb2L1ywLVeAxNqY0PZqS7a8Q2GLhNr5V+3hOoWn7bwqQ7L06UJGSrcLOPZeIH\nIWM20aOFHSTWbocd4f+m6s3llyXwBBlK2BPZbWv0OeAHgjN9AVav4flAZ4oD2GxA\naJkGAXmR9QzZNJLai5mv3L/B/p/NxeU3UGfaySxVvw==\n-----END CERTIFICATE-----\n"}]} + {"certificates":[{"serial":"14381893493177441266","not_before":"2016-06-10T22:14:12Z","not_after":"2023-04-15T22:14:12Z","signature_algorithm":"SHA256-RSA","is_self_signed":true,"subject":{"common_name":"example-small-key","country":["US"],"organization":["certigo"],"organizational_unit":["example"],"province":["CA"]},"issuer":{"common_name":"example-small-key","country":["US"],"organization":["certigo"],"organizational_unit":["example"],"province":["CA"]},"warnings":["Certificate is not in X509v3 format (version is 2)","Size of RSA key should be at least 2048 bits"],"pem":"-----BEGIN CERTIFICATE-----\nMIICKzCCAZQCCQDHlr/u+lfb8jANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJV\nUzELMAkGA1UECBMCQ0ExEDAOBgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1w\nbGUxGjAYBgNVBAMTEWV4YW1wbGUtc21hbGwta2V5MB4XDTE2MDYxMDIyMTQxMloX\nDTIzMDQxNTIyMTQxMlowWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYD\nVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRowGAYDVQQDExFleGFtcGxl\nLXNtYWxsLWtleTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlzyCIeP1T87k\n1rHVMtbaGXIWpK/VQuvuXwig+e3ct1ajA4bw0BAInXZ37FEGGSCUix0k/CjH2Nlt\nGREtwbahE0k5oTkVbA5XS4xkNs0M0poAFN5OiFKEAqZ014hqhvKnEUQ2oTe9SVOR\nWw49mLNg36AIEE2Fu2KQb/VT90cwwD0CAwEAATANBgkqhkiG9w0BAQsFAAOBgQBV\nsJ4Vb2L1ywLVeAxNqY0PZqS7a8Q2GLhNr5V+3hOoWn7bwqQ7L06UJGSrcLOPZeIH\nIWM20aOFHSTWbocd4f+m6s3llyXwBBlK2BPZbWv0OeAHgjN9AVav4flAZ4oD2GxA\naJkGAXmR9QzZNJLai5mv3L/B/p/NxeU3UGfaySxVvw==\n-----END CERTIFICATE-----\n"}]}