From e87999ef5536991629b9064b0ff08b4856b3ae58 Mon Sep 17 00:00:00 2001 From: Bart de Water Date: Sun, 20 Oct 2019 16:18:08 -0400 Subject: [PATCH] Add helper to retrieve CRL URIs from a certificate --- lib/openssl/x509.rb | 34 ++++++++++++++++++++++++++++++++++ test/test_x509cert.rb | 15 +++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/lib/openssl/x509.rb b/lib/openssl/x509.rb index 4f3a4337f..0f29311b7 100644 --- a/lib/openssl/x509.rb +++ b/lib/openssl/x509.rb @@ -113,6 +113,39 @@ def authority_key_identifier key_id.nil? ? nil : key_id.value end end + + module CrlDistributionPoints + include Helpers + + # Get the distributionPoint fullName URI from the certificate's CRL + # distribution points extension, as described in RFC5280 Section + # 4.2.1.13 + # + # Returns an array of strings or nil or raises ASN1::ASN1Error. + def crl_uris + ext = find_extension("crlDistributionPoints") + return nil if ext.nil? + + cdp_asn1 = ASN1.decode(ext.value_der) + if cdp_asn1.tag_class != :UNIVERSAL || cdp_asn1.tag != ASN1::SEQUENCE + raise ASN1::ASN1Error "invalid extension" + end + + crl_uris = cdp_asn1.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| + v.tag_class == :CONTEXT_SPECIFIC && v.tag == 6 # uniformResourceIdentifier + end + end + + crl_uris.map(&:value) + end + end end class Name @@ -234,6 +267,7 @@ def cleanup class Certificate include Extension::SubjectKeyIdentifier include Extension::AuthorityKeyIdentifier + include Extension::CrlDistributionPoints def pretty_print(q) q.object_group(self) { diff --git a/test/test_x509cert.rb b/test/test_x509cert.rb index a490ccfc7..dd3b5779e 100644 --- a/test/test_x509cert.rb +++ b/test/test_x509cert.rb @@ -98,6 +98,21 @@ def test_extension assert_equal(ee1_exts[i].last, ext.critical?) } + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(<<~_cnf_) + [crlDistPts] + URI.1 = http://www.example.com/crl + URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary + _cnf_ + cdp_cert = generate_cert(@ee1, @rsa1024, 3, ca_cert) + ef.subject_certificate = cdp_cert + cdp_cert.add_extension(ef.create_extension("crlDistributionPoints", "@crlDistPts")) + cdp_cert.sign(@rsa2048, "sha256") + assert_equal( + ["http://www.example.com/crl", "ldap://ldap.example.com/cn=ca?certificateRevocationList;binary"], + cdp_cert.crl_uris + ) + no_exts_cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) assert_equal nil, no_exts_cert.authority_key_identifier assert_equal nil, no_exts_cert.subject_key_identifier