class RubyTls::SSL::Context

Constants

ALPN_LOOKUP
ALPN_Select_CB
CIPHERS

Based on information from raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

SESSION
ServerNameCB

Attributes

alpn_set[R]
alpn_str[R]
is_server[R]
ssl_ctx[R]

Public Class Methods

new(server, options = {}) click to toggle source
# File lib/ruby-tls/ssl.rb, line 382
def initialize(server, options = {})
    @is_server = server

    if @is_server
        @ssl_ctx = SSL.SSL_CTX_new(SSL.TLS_server_method)
        set_private_key(options[:private_key] || SSL::DEFAULT_PRIVATE)
        set_certificate(options[:cert_chain]  || SSL::DEFAULT_CERT)
        set_client_ca(options[:client_ca])
    else
        @ssl_ctx = SSL.SSL_CTX_new(SSL.TLS_client_method)
    end

    SSL.SSL_CTX_set_options(@ssl_ctx, SSL::SSL_OP_ALL)
    SSL.SSL_CTX_set_mode(@ssl_ctx, SSL::SSL_MODE_RELEASE_BUFFERS)

    SSL.SSL_CTX_set_cipher_list(@ssl_ctx, options[:ciphers] || CIPHERS)
    @alpn_set = false

    version = options[:version]
    if version
        vresult = set_min_proto_version(version)
        raise "#{version} is unsupported" unless vresult
    end

    if @is_server
        SSL.SSL_CTX_sess_set_cache_size(@ssl_ctx, 128)
        SSL.SSL_CTX_set_session_id_context(@ssl_ctx, SESSION, 8)

        if SSL::ALPN_SUPPORTED && options[:protocols]
            @alpn_str = Context.build_alpn_string(options[:protocols])
            SSL.SSL_CTX_set_alpn_select_cb(@ssl_ctx, ALPN_Select_CB, nil)
            @alpn_set = true
        end
    else
        set_private_key(options[:private_key])
        set_certificate(options[:cert_chain])

        # Check for ALPN support
        if SSL::ALPN_SUPPORTED && options[:protocols]
            protocols = Context.build_alpn_string(options[:protocols])
            @alpn_set = SSL.SSL_CTX_set_alpn_protos(@ssl_ctx, protocols, protocols.length) == 0
        end
    end
end

Private Class Methods

build_alpn_string(protos) click to toggle source
# File lib/ruby-tls/ssl.rb, line 482
def self.build_alpn_string(protos)
    protocols = String.new.force_encoding('ASCII-8BIT')
    protos.each do |prot|
        protocol = prot.to_s
        protocols << protocol.length
        protocols << protocol
    end
    protocols
end

Public Instance Methods

add_server_name_indication() click to toggle source
# File lib/ruby-tls/ssl.rb, line 460
def add_server_name_indication
    raise 'only valid for server mode context' unless @is_server
    SSL.SSL_CTX_set_tlsext_servername_callback(@ssl_ctx, ServerNameCB)
end
cleanup() click to toggle source
# File lib/ruby-tls/ssl.rb, line 448
def cleanup
    if @ssl_ctx
        SSL.SSL_CTX_free(@ssl_ctx)
        @ssl_ctx = nil
    end
end
set_max_proto_version(version) click to toggle source
# File lib/ruby-tls/ssl.rb, line 437
def set_max_proto_version(version)
    num = SSL.const_get("#{version}_VERSION")
    SSL.SSL_CTX_set_max_proto_version(@ssl_ctx, num) == 1
rescue NameError
    false
end
set_min_proto_version(version) click to toggle source
# File lib/ruby-tls/ssl.rb, line 430
def set_min_proto_version(version)
    num = SSL.const_get("#{version}_VERSION")
    SSL.SSL_CTX_set_min_proto_version(@ssl_ctx, num) == 1
rescue NameError
    false
end

Private Instance Methods

set_certificate(cert) click to toggle source
# File lib/ruby-tls/ssl.rb, line 510
def set_certificate(cert)
    err = if cert.is_a? FFI::Pointer
        SSL.SSL_CTX_use_certificate(@ssl_ctx, cert)
    elsif cert && File.file?(cert)
        SSL.SSL_CTX_use_certificate_chain_file(@ssl_ctx, cert)
    else
        1
    end

    if err <= 0
        cleanup
        raise 'invalid certificate or file not found'
    end
end
set_client_ca(ca) click to toggle source
# File lib/ruby-tls/ssl.rb, line 525
def set_client_ca(ca)
    return unless ca

    if File.file?(ca) && (ca_ptr = SSL.SSL_load_client_CA_file(ca))
        # there is no error checking provided by SSL_CTX_set_client_CA_list
        SSL.SSL_CTX_set_client_CA_list(@ssl_ctx, ca_ptr)
    else
        cleanup
        raise 'invalid ca certificate or file not found'
    end
end
set_private_key(key) click to toggle source
# File lib/ruby-tls/ssl.rb, line 492
def set_private_key(key)
    err = if key.is_a? FFI::Pointer
        SSL.SSL_CTX_use_PrivateKey(@ssl_ctx, key)
    elsif key && File.file?(key)
        SSL.SSL_CTX_use_PrivateKey_file(@ssl_ctx, key, SSL_FILETYPE_PEM)
    else
        1
    end

    # Check for errors
    if err <= 0
        # TODO:: ERR_print_errors_fp or ERR_print_errors
        # So we can properly log the issue
        cleanup
        raise 'invalid private key or file not found'
    end
end