From 5fe29a3415b2cf2740628ce4c4f79097f7aa8b73 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Tue, 9 Jul 2024 21:15:11 +0900 Subject: [PATCH] x509: fix handling of multiple URIs in Certificate#crl_uris The implementation of OpenSSL::X509::Certificate#crl_uris makes the assumption that each DistributionPoint in the CRL distribution points extension contains a single general name of type URI. This is not guaranteed by RFC 5280. A DistributionPoint may only contains something other than a URI, or more than one URI. Let's include all URIs seen in the extension. If only non-URI pointers are found, return an empty array. Fixes: https://github.com/ruby/openssl/issues/775 --- lib/openssl/x509.rb | 4 ++-- test/openssl/test_x509cert.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/openssl/x509.rb b/lib/openssl/x509.rb index b66727420..d5d16cc73 100644 --- a/lib/openssl/x509.rb +++ b/lib/openssl/x509.rb @@ -135,14 +135,14 @@ def crl_uris raise ASN1::ASN1Error, "invalid extension" end - crl_uris = cdp_asn1.map do |crl_distribution_point| + crl_uris = cdp_asn1.flat_map do |crl_distribution_point| distribution_point = crl_distribution_point.value.find do |v| v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0 end full_name = distribution_point&.value&.find do |v| v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0 end - full_name&.value&.find do |v| + full_name&.value&.select do |v| v.tag_class == :CONTEXT_SPECIFIC && v.tag == 6 # uniformResourceIdentifier end end diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb index 426356943..47cf031a9 100644 --- a/test/openssl/test_x509cert.rb +++ b/test/openssl/test_x509cert.rb @@ -151,6 +151,39 @@ def test_crl_uris ) end + def test_crl_uris_multiple_general_names + # Single DistributionPoint contains multiple general names of type URI + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(<<~_cnf_) + [crlDistPts_section] + fullname = URI:http://www.example.com/crl, URI:ldap://ldap.example.com/cn=ca?certificateRevocationList;binary + _cnf_ + cdp_cert = generate_cert(@ee1, @rsa2048, 3, nil) + ef.subject_certificate = cdp_cert + cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "crlDistPts_section")) + cdp_cert.sign(@rsa2048, "sha256") + assert_equal( + ["http://www.example.com/crl", "ldap://ldap.example.com/cn=ca?certificateRevocationList;binary"], + cdp_cert.crl_uris + ) + end + + def test_crl_uris_no_uris + # The only DistributionPointName is a directoryName + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(<<~_cnf_) + [crlDistPts_section] + fullname = dirName:dirname_section + [dirname_section] + CN = dirname + _cnf_ + cdp_cert = generate_cert(@ee1, @rsa2048, 3, nil) + ef.subject_certificate = cdp_cert + cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "crlDistPts_section")) + cdp_cert.sign(@rsa2048, "sha256") + assert_equal([], cdp_cert.crl_uris) + end + def test_aia_missing cert = issue_cert(@ee1, @rsa2048, 1, [], nil, nil) assert_nil(cert.ca_issuer_uris)