From d7717d7b5673079594cd90769441b981b2cea2ac Mon Sep 17 00:00:00 2001 From: Tom Freudenberg Date: Tue, 21 Jan 2020 04:33:01 +0100 Subject: [PATCH] add: subjectAltName extension to memory only test certificates while using TLS --- lib/midi-smtp-server.rb | 4 ++-- lib/midi-smtp-server/tls-transport.rb | 13 ++++++++++--- test/integration/memory_only_certificate_test.rb | 1 - 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/midi-smtp-server.rb b/lib/midi-smtp-server.rb index 5a6404d..bc8a570 100644 --- a/lib/midi-smtp-server.rb +++ b/lib/midi-smtp-server.rb @@ -336,8 +336,8 @@ def initialize(ports = DEFAULT_SMTPD_PORT, hosts = DEFAULT_SMTPD_HOST, max_proce require 'openssl' # check for given CN and SAN if opts.include?(:tls_cert_cn) - tls_cert_cn = opts[:tls_cert_cn] - tls_cert_san = opts[:tls_cert_san] + tls_cert_cn = opts[:tls_cert_cn].to_s.strip + tls_cert_san = opts[:tls_cert_san].to_s.delete(' ').split(',') else # build generic set of "valid" self signed certificate CN and SAN # using all given hosts and detected ip_addresses but not "*" wildcard diff --git a/lib/midi-smtp-server/tls-transport.rb b/lib/midi-smtp-server/tls-transport.rb index 7fa56b0..be21cec 100644 --- a/lib/midi-smtp-server/tls-transport.rb +++ b/lib/midi-smtp-server/tls-transport.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'resolv' + # A small and highly customizable ruby SMTP-Server. module MidiSmtpServer @@ -42,9 +44,12 @@ def initialize(cert_path, key_path, ciphers, methods, cert_cn, cert_san, logger) @ctx.key = OpenSSL::PKey::RSA.new(File.open(@key_path.to_s)) else # if none cert_path was set, create a self signed test certificate - # and try to setup common subject and subject alt name(s) for cert + # and try to setup common subject and subject alt name(s) for cert @cert_cn = cert_cn.to_s.strip - @cert_san = cert_san.nil? ? [] : cert_san.uniq + @cert_san = ([@cert_cn] + (cert_san.nil? ? [] : cert_san)).uniq + # as well as IP Address extension entries for subject alt name(s) if ipv4 or ipv6 address + @cert_san_ip = [] + @cert_san.each { |san| @cert_san_ip << san if san =~ Resolv::IPv4::Regex || san =~ Resolv::IPv6::Regex } # initialize self certificate and key logger.debug("SSL: using self generated test certificate! CN=#{@cert_cn} SAN=[#{@cert_san.join(',')}]") @ctx.key = OpenSSL::PKey::RSA.new 4096 @@ -64,7 +69,9 @@ def initialize(cert_path, key_path, ciphers, methods, cert_cn, cert_san, logger) @ef.issuer_certificate = @ctx.cert @ctx.cert.add_extension(@ef.create_extension('basicConstraints', 'CA:FALSE', false)) @ctx.cert.add_extension(@ef.create_extension('keyUsage', 'digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment', false)) - @ctx.cert.sign @ctx.key, OpenSSL::Digest::SHA1.new + @ctx.cert.add_extension(@ef.create_extension('subjectAltName', (@cert_san.map { |san| "DNS:#{san}" } + @cert_san_ip.map { |ip| "IP:#{ip}" }).join(', '), false)) + @ctx.cert.sign @ctx.key, OpenSSL::Digest::SHA256.new + logger.debug("SSL: generated test certificate\r\n#{@ctx.cert.to_text}") end end diff --git a/test/integration/memory_only_certificate_test.rb b/test/integration/memory_only_certificate_test.rb index 72e42e9..5614aed 100644 --- a/test/integration/memory_only_certificate_test.rb +++ b/test/integration/memory_only_certificate_test.rb @@ -15,7 +15,6 @@ def setup do_dns_reverse_lookup: false, auth_mode: :AUTH_OPTIONAL, tls_mode: :TLS_REQUIRED, - tls_cert_cn: '127.0.0.1', pipelining_extension: false, internationalization_extensions: true )