Class: RubyTls::SSL::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-tls/ssl.rb

Constant Summary collapse

CIPHERS =
'EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4'
SESSION =
'ruby-tls'
ALPN_LOOKUP =
::Concurrent::Map.new
ALPN_Select_CB =
FFI::Function.new(:int, [
    # array of str, unit8 out,uint8 in,        *arg
    :pointer, :pointer, :pointer, :string, :uint, :pointer
]) do |ssl_p, out, outlen, inp, inlen, arg|
    ssl = Box::InstanceLookup[ssl_p.address]
    return SSL::SSL_TLSEXT_ERR_ALERT_FATAL unless ssl

    protos = ssl.context.alpn_str
    status = SSL.SSL_select_next_proto(out, outlen, protos, protos.length, inp, inlen)
    ssl.negotiated

    case status
    when SSL::OPENSSL_NPN_UNSUPPORTED
        SSL::SSL_TLSEXT_ERR_ALERT_FATAL
    when SSL::OPENSSL_NPN_NEGOTIATED
        SSL::SSL_TLSEXT_ERR_OK
    when SSL::OPENSSL_NPN_NO_OVERLAP
        SSL::SSL_TLSEXT_ERR_ALERT_WARNING
    end
end
ServerNameCB =
FFI::Function.new(:int, [:pointer, :pointer, :pointer]) do |ssl, _, _|
    ruby_ssl = Box::InstanceLookup[ssl.address]
    return SSL::SSL_TLSEXT_ERR_NOACK unless ruby_ssl

    ctx = ruby_ssl.hosts[SSL.SSL_get_servername(ssl, SSL::TLSEXT_NAMETYPE_host_name)]
    if ctx
        SSL.SSL_set_SSL_CTX(ssl, ctx.ssl_ctx)
        SSL::SSL_TLSEXT_ERR_OK
    else
        SSL::SSL_TLSEXT_ERR_ALERT_FATAL
    end
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server, options = {}) ⇒ Context

Returns a new instance of Context.



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# 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

Instance Attribute Details

#alpn_setObject (readonly)

Returns the value of attribute alpn_set.



457
458
459
# File 'lib/ruby-tls/ssl.rb', line 457

def alpn_set
  @alpn_set
end

#alpn_strObject (readonly)

Returns the value of attribute alpn_str.



458
459
460
# File 'lib/ruby-tls/ssl.rb', line 458

def alpn_str
  @alpn_str
end

#is_serverObject (readonly)

Returns the value of attribute is_server.



455
456
457
# File 'lib/ruby-tls/ssl.rb', line 455

def is_server
  @is_server
end

#ssl_ctxObject (readonly)

Returns the value of attribute ssl_ctx.



456
457
458
# File 'lib/ruby-tls/ssl.rb', line 456

def ssl_ctx
  @ssl_ctx
end

Instance Method Details

#add_server_name_indicationObject



460
461
462
463
# 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

#cleanupObject



448
449
450
451
452
453
# 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) ⇒ Object



437
438
439
440
441
442
# 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) ⇒ Object



430
431
432
433
434
435
# 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