From c67c768395c89f3b13fc1bd5fbdb6aba926aaff2 Mon Sep 17 00:00:00 2001 From: mh Date: Wed, 8 Feb 2017 22:44:48 +0100 Subject: [PATCH] display and parse inconsistency with DNS SubjectAltNames As soon as a certificate has more than one (DNS?) SAN, jruby-openssl a) represents them internally as multiple extensions b) the `to_text` also renders them as multiple entries However, as far as I understand https://tools.ietf.org/html/rfc5280#section-4.2 an extension MUST only appear once: "A certificate MUST NOT include more than one instance of a particular extension.", which means that the representation like it is now is at least misleading, if not even completely wrong. MRI openssl returns for the same certificate only one extension, matching a string that is also expected in the other SAN test case. This especially breaks any kind of client tools that are looking for the *first* extension and then try to match that content. Also the test shows an inconsistency before and after parsing. --- src/test/ruby/x509/test_x509ext.rb | 34 ++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/test/ruby/x509/test_x509ext.rb b/src/test/ruby/x509/test_x509ext.rb index afadda84..2cd035e1 100644 --- a/src/test/ruby/x509/test_x509ext.rb +++ b/src/test/ruby/x509/test_x509ext.rb @@ -150,10 +150,40 @@ def test_subject_alt_name_sign_to_pem assert dns =~ /test.example.com.*?test2.example.com.*?example.com.*?www.example.com/ end + def test_subject_alt_name_sign_to_pem_through_cert + domain_list = 'test.example.com,test2.example.com,example.com,www.example.com' + rsa_key = OpenSSL::PKey::RSA.new(2048) + crt = OpenSSL::X509::Certificate.new + crt.subject = OpenSSL::X509::Name.new [ ["C", 'AU'], ["ST", "NSW"], ["O", 'org'], ["CN", 'www.example.com'] ] + crt.issuer = crt.subject + crt.not_before = Time.now + crt.not_after = Time.now + 1 * 24 * 60 * 60 + crt.serial = 0 + crt.version = 2 + + crt.public_key = rsa_key.public_key + + ef = OpenSSL::X509::ExtensionFactory.new + ef.subject_certificate = crt + ef.issuer_certificate = crt + crt.add_extension ef.create_extension("subjectAltName", domain_list.split(',').map { |d| "DNS:#{d}" }.join(', ')) + + crt.sign rsa_key, OpenSSL::Digest::SHA256.new + + puts crt.to_text if $VERBOSE + puts crt.to_pem if $VERBOSE + + assert_equal 1,crt.extensions.select{|e| e.oid == 'subjectAltName' }.count + + crt = OpenSSL::X509::Certificate.new pem = crt.to_pem + assert_equal 1,crt.extensions.select{|e| e.oid == 'subjectAltName' }.count + assert crt.extensions.find{|e| e.oid == 'subjectAltName' }.value =~ /test.example.com.*?test2.example.com.*?example.com.*?www.example.com/ + end + def subject_alt_name(domains) ef = OpenSSL::X509::ExtensionFactory.new - ef.create_extension("subjectAltName", domains.split(',').map { |d| "DNS: #{d}" }.join(',')) + ef.create_extension("subjectAltName", domains.split(',').map { |d| "DNS:#{d}" }.join(', ')) end private :subject_alt_name -end \ No newline at end of file +end