class MidiSmtpServer::TlsTransport
class for TlsTransport
Attributes
ssl_context[R]
current TLS OpenSSL::SSL::SSLContext
Public Class Methods
new(cert_path, key_path, ciphers, methods, cert_cn, cert_san, logger)
click to toggle source
# File lib/midi-smtp-server/tls-transport.rb, line 28 def initialize(cert_path, key_path, ciphers, methods, cert_cn, cert_san, logger) # if need to debug something while working with openssl # OpenSSL::debug = true # save references @logger = logger @cert_path = cert_path.to_s == '' ? nil : cert_path.strip @key_path = key_path.to_s == '' ? nil : key_path.strip # create SSL context @ssl_context = OpenSSL::SSL::SSLContext.new @ssl_context.ciphers = ciphers.to_s == '' ? TLS_CIPHERS_ADVANCED_PLUS : ciphers @ssl_context.ssl_version = methods.to_s == '' ? TLS_METHODS_ADVANCED : methods # check cert_path and key_path if @cert_path.nil? # 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 @cert_cn = cert_cn.to_s.strip @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(',')}]") @ssl_context.key = OpenSSL::PKey::RSA.new 4096 @ssl_context.cert = OpenSSL::X509::Certificate.new @ssl_context.cert.version = 2 @ssl_context.cert.serial = 1 # the subject and the issuer are identical only for test certificate @ssl_context.cert.subject = OpenSSL::X509::Name.new [['CN', @cert_cn]] @ssl_context.cert.issuer = @ssl_context.cert.subject @ssl_context.cert.public_key = @ssl_context.key # valid for 90 days @ssl_context.cert.not_before = Time.now @ssl_context.cert.not_after = Time.now + (60 * 60 * 24 * 90) # setup some cert extensions x509_extension_factory = OpenSSL::X509::ExtensionFactory.new x509_extension_factory.subject_certificate = @ssl_context.cert x509_extension_factory.issuer_certificate = @ssl_context.cert @ssl_context.cert.add_extension(x509_extension_factory.create_extension('basicConstraints', 'CA:FALSE', false)) @ssl_context.cert.add_extension(x509_extension_factory.create_extension('keyUsage', 'digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment', false)) @ssl_context.cert.add_extension(x509_extension_factory.create_extension('subjectAltName', (@cert_san.map { |san| "DNS:#{san}" } + @cert_san_ip.map { |ip| "IP:#{ip}" }).join(', '), false)) @ssl_context.cert.sign @ssl_context.key, OpenSSL::Digest.new('SHA256') logger.debug("SSL: generated test certificate\r\n#{@ssl_context.cert.to_text}") else # if any is set, test the paths raise "File \"#{@cert_path}\" does not exist or is not a regular file. Could not load certificate." unless File.file?(@cert_path.to_s) raise "File \"#{@key_path}\" does not exist or is not a regular file. Could not load private key." unless @key_path.nil? || File.file?(@key_path.to_s) # try to load certificate and key cert_lines = File.read(@cert_path.to_s).lines # check if the cert file contains a chain of certs cert_indexes = cert_lines.each_with_index.map { |line, index| index if line.downcase.include?('-begin certificate-') }.compact # create each cert in the chain certs = [] cert_indexes.each_with_index do |cert_index, current_index| end_index = current_index + 1 < cert_indexes.length ? cert_indexes[current_index + 1] : -1 certs << OpenSSL::X509::Certificate.new(cert_lines[cert_index..end_index].join) end # add the cert and optional found chain to context @ssl_context.cert = certs.first @ssl_context.extra_chain_cert = certs[1..] # check if key was given by separate file or should be included in cert if @key_path.nil? key_index = cert_lines.index { |line| line =~ /-begin[^-]+key-/i } end_index = cert_lines.index { |line| line =~ /-end[^-]+key-/i } @ssl_context.key = OpenSSL::PKey::RSA.new(cert_lines[key_index..end_index].join) else @ssl_context.key = OpenSSL::PKey::RSA.new(File.open(@key_path.to_s)) end end end
Public Instance Methods
start(io)
click to toggle source
start ssl connection over existing tcpserver socket
# File lib/midi-smtp-server/tls-transport.rb, line 100 def start(io) # start SSL negotiation ssl = OpenSSL::SSL::SSLSocket.new(io, @ssl_context) # connect to server socket ssl.accept # make sure to close also the underlying io ssl.sync_close = true # return as new io socket return ssl end