diff options
-rw-r--r-- | src/build-data/oids.txt | 1 | ||||
-rw-r--r-- | src/lib/asn1/oids.cpp | 4 | ||||
-rw-r--r-- | src/lib/x509/x509_ext.cpp | 11 | ||||
-rw-r--r-- | src/lib/x509/x509_ext.h | 11 | ||||
-rw-r--r-- | src/lib/x509/x509cert.cpp | 16 | ||||
-rw-r--r-- | src/lib/x509/x509cert.h | 5 | ||||
-rw-r--r-- | src/tests/data/x509/misc/contains_authority_info_access.pem | 31 | ||||
-rw-r--r-- | src/tests/data/x509/misc/contains_authority_info_access_with_two_ca_issuers.pem | 46 | ||||
-rw-r--r-- | src/tests/unit_x509.cpp | 39 |
9 files changed, 160 insertions, 4 deletions
diff --git a/src/build-data/oids.txt b/src/build-data/oids.txt index 089523e69..321439e5b 100644 --- a/src/build-data/oids.txt +++ b/src/build-data/oids.txt @@ -235,6 +235,7 @@ 1.3.6.1.5.5.7.48.1 = PKIX.OCSP 1.3.6.1.5.5.7.48.1.1 = PKIX.OCSP.BasicResponse +1.3.6.1.5.5.7.48.2 = PKIX.CertificateAuthorityIssuers 1.3.6.1.4.1.311.20.2.2 = Microsoft SmartcardLogon diff --git a/src/lib/asn1/oids.cpp b/src/lib/asn1/oids.cpp index 2c97f1d29..b60ec24d2 100644 --- a/src/lib/asn1/oids.cpp +++ b/src/lib/asn1/oids.cpp @@ -1,7 +1,7 @@ /* * OID maps * -* This file was automatically generated by ./src/scripts/oids.py on 2017-12-05 +* This file was automatically generated by ./src/scripts/oids.py on 2018-01-03 * * All manual edits to this file will be lost. Edit the script * then regenerate this source file. @@ -143,6 +143,7 @@ std::string lookup(const OID& oid) if(oid_str == "1.3.6.1.5.5.7.3.9") return "PKIX.OCSPSigning"; if(oid_str == "1.3.6.1.5.5.7.48.1") return "PKIX.OCSP"; if(oid_str == "1.3.6.1.5.5.7.48.1.1") return "PKIX.OCSP.BasicResponse"; + if(oid_str == "1.3.6.1.5.5.7.48.2") return "PKIX.CertificateAuthorityIssuers"; if(oid_str == "1.3.6.1.5.5.7.8.5") return "PKIX.XMPPAddr"; if(oid_str == "2.16.840.1.101.3.4.1.2") return "AES-128/CBC"; if(oid_str == "2.16.840.1.101.3.4.1.22") return "AES-192/CBC"; @@ -303,6 +304,7 @@ OID lookup(const std::string& name) if(name == "PKCS9.MessageDigest") return OID("1.2.840.113549.1.9.4"); if(name == "PKCS9.UnstructuredName") return OID("1.2.840.113549.1.9.2"); if(name == "PKIX.AuthorityInformationAccess") return OID("1.3.6.1.5.5.7.1.1"); + if(name == "PKIX.CertificateAuthorityIssuers") return OID("1.3.6.1.5.5.7.48.2"); if(name == "PKIX.ClientAuth") return OID("1.3.6.1.5.5.7.3.2"); if(name == "PKIX.CodeSigning") return OID("1.3.6.1.5.5.7.3.3"); if(name == "PKIX.EmailProtection") return OID("1.3.6.1.5.5.7.3.4"); diff --git a/src/lib/x509/x509_ext.cpp b/src/lib/x509/x509_ext.cpp index afb79f6bf..c3b58236a 100644 --- a/src/lib/x509/x509_ext.cpp +++ b/src/lib/x509/x509_ext.cpp @@ -777,6 +777,15 @@ void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in) } } + if(oid == OIDS::lookup("PKIX.CertificateAuthorityIssuers")) + { + BER_Object name = info.get_next_object(); + + if(name.type_tag == 6 && name.class_tag == CONTEXT_SPECIFIC) + { + m_ca_issuers.push_back(ASN1::to_string(name)); + } + } } } @@ -784,6 +793,8 @@ void Authority_Information_Access::contents_to(Data_Store& subject, Data_Store&) { if(!m_ocsp_responder.empty()) subject.add("OCSP.responder", m_ocsp_responder); + for(const std::string& ca_issuer : m_ca_issuers) + subject.add("PKIX.CertificateAuthorityIssuers", ca_issuer); } /* diff --git a/src/lib/x509/x509_ext.h b/src/lib/x509/x509_ext.h index 235496cbd..8e702daf1 100644 --- a/src/lib/x509/x509_ext.h +++ b/src/lib/x509/x509_ext.h @@ -544,21 +544,25 @@ class BOTAN_PUBLIC_API(2,0) Certificate_Policies final : public Certificate_Exte std::vector<OID> m_oids; }; +/** +* Authority Information Access Extension +*/ class BOTAN_PUBLIC_API(2,0) Authority_Information_Access final : public Certificate_Extension { public: Authority_Information_Access* copy() const override - { return new Authority_Information_Access(m_ocsp_responder); } + { return new Authority_Information_Access(m_ocsp_responder, m_ca_issuers); } Authority_Information_Access() = default; - explicit Authority_Information_Access(const std::string& ocsp) : - m_ocsp_responder(ocsp) {} + explicit Authority_Information_Access(const std::string& ocsp, const std::vector<std::string>& ca_issuers = std::vector<std::string>()) : + m_ocsp_responder(ocsp), m_ca_issuers(ca_issuers) {} std::string ocsp_responder() const { return m_ocsp_responder; } static OID static_oid() { return OID("1.3.6.1.5.5.7.1.1"); } OID oid_of() const override { return static_oid(); } + const std::vector<std::string> ca_issuers() const { return m_ca_issuers; } private: std::string oid_name() const override @@ -572,6 +576,7 @@ class BOTAN_PUBLIC_API(2,0) Authority_Information_Access final : public Certific void contents_to(Data_Store&, Data_Store&) const override; std::string m_ocsp_responder; + std::vector<std::string> m_ca_issuers; }; /** diff --git a/src/lib/x509/x509cert.cpp b/src/lib/x509/x509cert.cpp index dd0514dfb..f298006c0 100644 --- a/src/lib/x509/x509cert.cpp +++ b/src/lib/x509/x509cert.cpp @@ -47,6 +47,7 @@ struct X509_Certificate_Data std::vector<std::string> m_crl_distribution_points; std::string m_ocsp_responder; + std::vector<std::string> m_ca_issuers; AlternativeName m_subject_alt_name; AlternativeName m_issuer_alt_name; @@ -262,6 +263,7 @@ std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(const X509_Object& o if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::Authority_Information_Access>()) { data->m_ocsp_responder = ext->ocsp_responder(); + data->m_ca_issuers = ext->ca_issuers(); } if(auto ext = data->m_v3_extensions.get_extension_object_as<Cert_Extension::CRL_Distribution_Points>()) @@ -543,6 +545,11 @@ std::string X509_Certificate::ocsp_responder() const return data().m_ocsp_responder; } +std::vector<std::string> X509_Certificate::ca_issuers() const + { + return data().m_ca_issuers; + } + std::string X509_Certificate::crl_distribution_point() const { // just returns the first (arbitrarily) @@ -815,6 +822,15 @@ std::string X509_Certificate::to_string() const if(!ocsp_responder().empty()) out << "OCSP responder " << ocsp_responder() << "\n"; + + std::vector<std::string> ca_issuers = this->ca_issuers(); + if(!ca_issuers.empty()) + { + out << "CA Issuers:\n"; + for(size_t i = 0; i != ca_issuers.size(); i++) + out << " URI: " << ca_issuers[i] << "\n"; + } + if(!crl_distribution_point().empty()) out << "CRL " << crl_distribution_point() << "\n"; diff --git a/src/lib/x509/x509cert.h b/src/lib/x509/x509cert.h index e87e5e436..a1448637d 100644 --- a/src/lib/x509/x509cert.h +++ b/src/lib/x509/x509cert.h @@ -346,6 +346,11 @@ class BOTAN_PUBLIC_API(2,0) X509_Certificate : public X509_Object std::string ocsp_responder() const; /** + * Return the listed addresses of ca issuers, or empty if not set + */ + std::vector<std::string> ca_issuers() const; + + /** * Return the CRL distribution point, or empty if not set */ std::string crl_distribution_point() const; diff --git a/src/tests/data/x509/misc/contains_authority_info_access.pem b/src/tests/data/x509/misc/contains_authority_info_access.pem new file mode 100644 index 000000000..5a0d780c7 --- /dev/null +++ b/src/tests/data/x509/misc/contains_authority_info_access.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCBFOgAwIBAgIQA9OHVX59Hl5rTdrLvK1+iDANBgkqhkiG9w0BAQsFADBC +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMS +UmFwaWRTU0wgU0hBMjU2IENBMB4XDTE3MDIwOTAwMDAwMFoXDTE4MDIxMTIzNTk1 +OVowGDEWMBQGA1UEAwwNKi5uZXhlbmlvLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAPgFzshLD9g4UDCzD64Qt+ZMC6EfTfIRrTprIL32Bq94eu+l +qEsuVgoXd9inV/52+mqzQXAa//zIY32XkW+kZVlD3zjC7jVZwV9gJJterrCpqLR0 +B4OECsciARJkasJwo82gt40OCgsUMWAwigl+geo93yuL403vB3wVOBD73e8I+W4D +49sWSzfepyFMzg+JwTrs6GafNOG8S4ZlC/js4eUJl5MllMXUzzYa/flBqZ/U2nZ3 +MtbvgPiW7NPblrAaIUSTs2rJgXIT5zZnfbZWRcpY8uSuXLywMqf5mXIoUNrn1Xc5 +oVnva9PIUpnFG47aOQ39P6Q3u4R3FosREgdW2oUCAwEAAaOCAoUwggKBMCUGA1Ud +EQQeMByCDSoubmV4ZW5pby5jb22CC25leGVuaW8uY29tMAkGA1UdEwQCMAAwKwYD +VR0fBCQwIjAgoB6gHIYaaHR0cDovL2dwLnN5bWNiLmNvbS9ncC5jcmwwbwYDVR0g +BGgwZjBkBgZngQwBAgEwWjAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRz +c2wuY29tL2xlZ2FsMCwGCCsGAQUFBwICMCAMHmh0dHBzOi8vd3d3LnJhcGlkc3Ns +LmNvbS9sZWdhbDAfBgNVHSMEGDAWgBSXwidQnsLJ7AyIMsh8reKmAU/abzAOBgNV +HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFcGCCsG +AQUFBwEBBEswSTAfBggrBgEFBQcwAYYTaHR0cDovL2dwLnN5bWNkLmNvbTAmBggr +BgEFBQcwAoYaaHR0cDovL2dwLnN5bWNiLmNvbS9ncC5jcnQwggEEBgorBgEEAdZ5 +AgQCBIH1BIHyAPAAdwDd6x0reg1PpiCLga2BaHB+Lo6dAdVciI09EcTNtuy+zAAA +AVojuwb7AAAEAwBIMEYCIQD65jDGmWRhjXeXt3sTexf+KOHsQ0McBEFJI21J6RYy +rgIhALScDzJaJBFnwPVz7lMnQye4O1gBbQc2qRtbCjhkwoxpAHUApLkJkLQYWBSH +uxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFaI7sHMQAABAMARjBEAiByzWJV1ewW +SugasxG6UGIolrRcueMDiYNcgvv98+ImIQIgN3jXAtnZRSjRIOggvSo59KUGuWvO +HXb9zZR7FGubm04wDQYJKoZIhvcNAQELBQADggEBAGbFsNFcunndr71N646kTmpu +UDr/bZcL5GCbsd0mV9LcVHeqxjL1d6jRUZKp4QVAyEVSL8KaAv1IAbQmFEO74mqf +MpH1qzoMqtoOnPCVCO4LP9yLSqDSc+oBQQ1yocGVEnHEiJD3kJrzd47dC5zY0e/D +/k8VFn8ln88g6lyzfjUtvs6kMBgj9xbOEUzVb3zVawqDUgzOuwYuFEMG85ff6a5F +6MIlMiQxIXxH23z2Smcffu1I9HLIb0sJfbNDRSsbfL8/+GYWqnF9aOuCeFPX/Eav +mbV6s/+dy90v7DB67ykcmWIiDHZypV9+7c+I5jUXNqA0rQNYs6eyMo/LnDvIIkU= +-----END CERTIFICATE----- diff --git a/src/tests/data/x509/misc/contains_authority_info_access_with_two_ca_issuers.pem b/src/tests/data/x509/misc/contains_authority_info_access_with_two_ca_issuers.pem new file mode 100644 index 000000000..f7a2923e1 --- /dev/null +++ b/src/tests/data/x509/misc/contains_authority_info_access_with_two_ca_issuers.pem @@ -0,0 +1,46 @@ +-----BEGIN CERTIFICATE----- +MIIINTCCBh2gAwIBAgIDAOudMA0GCSqGSIb3DQEBDQUAMG4xCzAJBgNVBAYTAkRF +MR0wGwYDVQQKExRCdW5kZXNkcnVja2VyZWkgR21iSDEeMBwGA1UECxMVQmRyaXZl +IEF1dGhlbnRpY2F0aW9uMSAwHgYDVQQDExdCZHJpdmUgVGVzdCBDQSAxLTIgMjAx +NzAeFw0xNzA3MDQxNjQ2MTJaFw0yMDA3MDQxNjQ2MTJaMIG9MQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMbmVYZW5pbyBHbWJIMRUwEwYDVQQDDAxSZW7DqSBNZXVzZWwx +DjAMBgNVBCoMBVJlbsOpMQ8wDQYDVQQEEwZNZXVzZWwxFTATBgNVBAUTDENTTTAw +MTg3MDI4NDEPMA0GA1UEBxMGQmVybGluMSYwJAYJKoZIhvcNAQkBFhdyZW5lLm1l +dXNlbEBuZXhlbmlvLmNvbTEPMA0GA1UECBMGQmVybGluMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA0DoJbM6jwZOgNU5BWheLWKB04ycd7BajeMyQ7GNd +c13U5Br+61VUP7V8r72a/eDoZxlLPzDhlgZp0U5kDKfsrQfulx3SFJ4cfh9Zk1Jn +XpAj+iVKJRfJCM7yH7D+pAyeMqkujsAgS2PNbek9ftSn4bMDz8BfJulH6ttM+82h +hn2L7F5jVXJVOlhDgVk9lONm17FxtgrJLQ3Pyq+K7SAJsBHCWbDQ+jA3ftE+MEzC +kWZgSpqY5S0PSPq1886doMTfCmoBBvlFJqmIwxDLue1rVrtcoDaDmu8ubpiGNMyV +9MS+8SRtt83N7uC1AWjaaNo0F0YkHI7pu3ezBzEDixDQENFo6dQEjwwVZ1U8+sGx +XyyZCZ59Q0qA4lgO9rKW7STPET7lYWxRWKAjTJqbcSrfSlF/aISeIYExzWlzNc/x +j77oUTXFSJUet77saQ8Q2fDFZrY186ILwdsSfoJTyq4rHVaUTTsXSZWM/3JAuyto +BCiB3JAFjT3VIL+J2CAfHA0tbo/S/3rTTeL9FDtjZqFxLSIGlonUkC37h7X2kJz8 +NDNzRZivce16suHJvcCug5BLv8YR6L4ltJb+5R4Oap6sj0ucdyRHfxFhOGm6KuQZ +UdPKg702iVI1MSFfogehaaSuLdzQf9JZhUBcrHD3hnFB43dM9P1gjtHdlKTTmn5r +xu0CAwEAAaOCAoowggKGMCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDBQYI +KwYBBQUHAwcwHwYDVR0jBBgwFoAUTLjqt54mTOqT9hq3Dlk+Eyxshh4wggEEBggr +BgEFBQcBAQSB9zCB9DArBggrBgEFBQcwAYYfaHR0cDovL3N0YWdpbmcub2NzcC5k +LXRydXN0Lm5ldDBGBggrBgEFBQcwAoY6aHR0cDovL3d3dy5kLXRydXN0Lm5ldC9j +Z2ktYmluL0Jkcml2ZV9UZXN0X0NBXzEtMl8yMDE3LmNydDB9BggrBgEFBQcwAoZx +bGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5ldC9DTj1CZHJpdmUlMjBUZXN0JTIw +Q0ElMjAxLTIlMjAyMDE3LE89QnVuZGVzZHJ1Y2tlcmVpJTIwR21iSCxDPURFP2NB +Q2VydGlmaWNhdGU/YmFzZT8wFwYDVR0gBBAwDjAMBgorBgEEAaU0AgICMIHFBgNV +HR8Egb0wgbowgbeggbSggbGGd2xkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQv +Q049QmRyaXZlJTIwVGVzdCUyMENBJTIwMS0yJTIwMjAxNyxPPUJ1bmRlc2RydWNr +ZXJlaSUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0hjZodHRw +Oi8vY3JsLmQtdHJ1c3QubmV0L2NybC9iZHJpdmVfdGVzdF9jYV8xLTJfMjAxNy5j +cmwwHQYDVR0OBBYEFOvOhR43QAFq7O7B8Ju7PuL6BaXPMA4GA1UdDwEB/wQEAwIH +gDAiBgNVHREEGzAZgRdyZW5lLm1ldXNlbEBuZXhlbmlvLmNvbTANBgkqhkiG9w0B +AQ0FAAOCAgEADLWieLjuNv4VxrYLbfPoP5U0BTlvpvnxAwC8//l91b+KO3J+Pvz5 +ina+xTErIT9c+jg2QtC5oXqNihzN3RxQUs/7NA22td8tWfBld0138BASNckuP595 +LH4Ka7FY6pWwhRHty0GLqmRg8fR8LbnyOUqBLgs6DYI4RmhaSDUPCVMrh3OIwbSc +fKL/88Z8UHD8sxdww3GNybv8FbcRo5g0udtm0MMeemSt7E1B7nlMItLjqspLI9Ay +GnnkNmn95LxCDLXRIyViuHr3877yMmE9ibv+y41Xz+MLEFvmxe2rFOc+uWVrjFfK +HMtV7Q34xJYqBY4uVFF+Kmg4OyYFgNjOInwc8Bu09SqGsla/fyMBJwd2IG7xwobm +cwnf8+En8aavwlYG4lzfdNVo9CGpft6/86x7OoGbDSeH5JIjYI6xLqa/Cw1F64mR +Maye+cdGg+t4RE1Xri3e65lZM0Z11MT4NtIS5owBBMsmqILIHTaWStD9XfM7FTdQ +GnLD8AQBqMADxrEwIu8uUtZFxO9ZaYkBDtEVqo671ErwjCNtzx0EtE9bh6Vfat6s +qk4CFqKlfCWmAAUXlIQXm5DgKsnC4wE6XTa0HVSDLzh+WBeOdrX7gmhcPSmWkJ8Z +/blH36mCwiQ+Mx+Z1InIfSS9FoOhxsmmpX0QXnfBgjUWE8aq6yiXInA= +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/src/tests/unit_x509.cpp b/src/tests/unit_x509.cpp index 1fd4dc239..0aa9d0209 100644 --- a/src/tests/unit_x509.cpp +++ b/src/tests/unit_x509.cpp @@ -465,6 +465,44 @@ Test::Result test_x509_bmpstring() return result; } +Test::Result test_x509_authority_info_access_extension() + { + Test::Result result("X509 with PKIX.AuthorityInformationAccess extension"); + + // contains no AIA extension + Botan::X509_Certificate no_aia_cert(Test::data_file("x509/misc/contains_utf8string.pem")); + + result.test_eq("number of ca_issuers URLs", no_aia_cert.ca_issuers().size(), 0); + result.test_eq("CA issuer URL matches", no_aia_cert.ocsp_responder(), ""); + + // contains AIA extension with 1 CA issuer URL and 1 OCSP responder + Botan::X509_Certificate aia_cert(Test::data_file("x509/misc/contains_authority_info_access.pem")); + + const auto ca_issuers = aia_cert.ca_issuers(); + + result.test_eq("number of ca_issuers URLs", ca_issuers.size(), 1); + if (result.tests_failed()) + return result; + + result.test_eq("CA issuer URL matches", ca_issuers[0], "http://gp.symcb.com/gp.crt"); + result.test_eq("OCSP responder URL matches", aia_cert.ocsp_responder(), "http://gp.symcd.com"); + + // contains AIA extension with 2 CA issuer URL and 1 OCSP responder + Botan::X509_Certificate aia_cert_2ca(Test::data_file("x509/misc/contains_authority_info_access_with_two_ca_issuers.pem")); + + const auto ca_issuers2 = aia_cert_2ca.ca_issuers(); + + result.test_eq("number of ca_issuers URLs", ca_issuers2.size(), 2); + if (result.tests_failed()) + return result; + + result.test_eq("CA issuer URL matches", ca_issuers2[0], "http://www.d-trust.net/cgi-bin/Bdrive_Test_CA_1-2_2017.crt"); + result.test_eq("CA issuer URL matches", ca_issuers2[1], "ldap://directory.d-trust.net/CN=Bdrive%20Test%20CA%201-2%202017,O=Bundesdruckerei%20GmbH,C=DE?cACertificate?base?"); + result.test_eq("OCSP responder URL matches", aia_cert_2ca.ocsp_responder(), "http://staging.ocsp.d-trust.net"); + + return result; + } + Test::Result test_x509_cert(const std::string& sig_algo, const std::string& sig_padding = "", const std::string& hash_fn = "SHA-256") { Test::Result result("X509 Unit"); @@ -1424,6 +1462,7 @@ class X509_Cert_Unit_Tests final : public Test results.push_back(test_crl_dn_name()); results.push_back(test_x509_uninit()); results.push_back(test_x509_decode_list()); + results.push_back(test_x509_authority_info_access_extension()); return results; } |