Class: RubyTls::SSL::Box
- Inherits:
-
Object
- Object
- RubyTls::SSL::Box
- Defined in:
- lib/ruby-tls/ssl.rb
Constant Summary collapse
- InstanceLookup =
::Concurrent::Map.new
- READ_BUFFER =
2048- SSL_VERIFY_PEER =
0x01- SSL_VERIFY_CLIENT_ONCE =
0x04- SSL_ERROR_WANT_READ =
2- SSL_ERROR_SSL =
1- SSL_RECEIVED_SHUTDOWN =
2
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#handshake_completed ⇒ Object
readonly
Returns the value of attribute handshake_completed.
-
#hosts ⇒ Object
readonly
Returns the value of attribute hosts.
-
#is_server ⇒ Object
readonly
Returns the value of attribute is_server.
Instance Method Summary collapse
- #add_host(host_name:, **options) ⇒ Object
- #cleanup ⇒ Object
- #decrypt(data) ⇒ Object
- #encrypt(data) ⇒ Object
- #get_peer_cert ⇒ Object
-
#initialize(server, transport, options = {}) ⇒ Box
constructor
A new instance of Box.
- #negotiated ⇒ Object
- #negotiated_protocol ⇒ Object
-
#remove_host(host_name) ⇒ Object
Careful with this.
- #signal_handshake ⇒ Object
- #start ⇒ Object
-
#verify(cert) ⇒ Object
Called from class level callback function.
Constructor Details
#initialize(server, transport, options = {}) ⇒ Box
Returns a new instance of Box.
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
# File 'lib/ruby-tls/ssl.rb', line 480 def initialize(server, transport, = {}) @ready = true @handshake_completed = false @handshake_signaled = false @negotiated = false @transport = transport @read_buffer = FFI::MemoryPointer.new(:char, READ_BUFFER, false) @is_server = server @context = Context.new(server, ) @bioRead = SSL.BIO_new(SSL.BIO_s_mem) @bioWrite = SSL.BIO_new(SSL.BIO_s_mem) @ssl = SSL.SSL_new(@context.ssl_ctx) SSL.SSL_set_bio(@ssl, @bioRead, @bioWrite) @write_queue = [] InstanceLookup[@ssl.address] = self @alpn_fallback = [:fallback] if [:verify_peer] SSL.SSL_set_verify(@ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, VerifyCB) end # Add Server Name Indication (SNI) for client connections if [:host_name] if server @hosts = ::Concurrent::Map.new @hosts[[:host_name].to_s] = @context @context.add_server_name_indication else SSL.SSL_set_tlsext_host_name(@ssl, [:host_name]) end end SSL.SSL_connect(@ssl) unless server end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
544 545 546 |
# File 'lib/ruby-tls/ssl.rb', line 544 def context @context end |
#handshake_completed ⇒ Object (readonly)
Returns the value of attribute handshake_completed.
545 546 547 |
# File 'lib/ruby-tls/ssl.rb', line 545 def handshake_completed @handshake_completed end |
#hosts ⇒ Object (readonly)
Returns the value of attribute hosts.
546 547 548 |
# File 'lib/ruby-tls/ssl.rb', line 546 def hosts @hosts end |
#is_server ⇒ Object (readonly)
Returns the value of attribute is_server.
544 545 546 |
# File 'lib/ruby-tls/ssl.rb', line 544 def is_server @is_server end |
Instance Method Details
#add_host(host_name:, **options) ⇒ Object
521 522 523 524 525 526 527 528 |
# File 'lib/ruby-tls/ssl.rb', line 521 def add_host(host_name:, **) raise 'Server Name Indication (SNI) not configured for default host' unless @hosts raise 'only valid for server mode context' unless @is_server context = Context.new(true, ) @hosts[host_name.to_s] = context context.add_server_name_indication nil end |
#cleanup ⇒ Object
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
# File 'lib/ruby-tls/ssl.rb', line 650 def cleanup @ready = false InstanceLookup.delete @ssl.address if (SSL.SSL_get_shutdown(@ssl) & SSL_RECEIVED_SHUTDOWN) != 0 SSL.SSL_shutdown @ssl else SSL.SSL_clear @ssl end SSL.SSL_free @ssl if @hosts @hosts.each_value do |context| context.cleanup end @hosts = nil else @context.cleanup end end |
#decrypt(data) ⇒ Object
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
# File 'lib/ruby-tls/ssl.rb', line 589 def decrypt(data) return unless @ready put_cipher_text data if not SSL.SSL_is_init_finished(@ssl) resp = @is_server ? SSL.SSL_accept(@ssl) : SSL.SSL_connect(@ssl) if resp < 0 err_code = SSL.SSL_get_error(@ssl, resp) if err_code != SSL_ERROR_WANT_READ @transport.close_cb if err_code == SSL_ERROR_SSL return end end @handshake_completed = true signal_handshake unless @handshake_signaled end while true do size = get_plain_text(@read_buffer, READ_BUFFER) if size > 0 @transport.dispatch_cb @read_buffer.read_string(size) else break end end dispatch_cipher_text end |
#encrypt(data) ⇒ Object
576 577 578 579 580 581 582 583 584 585 |
# File 'lib/ruby-tls/ssl.rb', line 576 def encrypt(data) return unless @ready wrote = put_plain_text data if wrote < 0 @transport.close_cb else dispatch_cipher_text end end |
#get_peer_cert ⇒ Object
549 550 551 552 |
# File 'lib/ruby-tls/ssl.rb', line 549 def get_peer_cert return '' unless @ready SSL.SSL_get_peer_certificate(@ssl) end |
#negotiated ⇒ Object
645 646 647 |
# File 'lib/ruby-tls/ssl.rb', line 645 def negotiated @negotiated = true end |
#negotiated_protocol ⇒ Object
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'lib/ruby-tls/ssl.rb', line 554 def negotiated_protocol return nil unless @context.alpn_set proto = FFI::MemoryPointer.new(:pointer, 1, true) len = FFI::MemoryPointer.new(:uint, 1, true) SSL.SSL_get0_alpn_selected(@ssl, proto, len) resp = proto.get_pointer(0) if resp.address == 0 :failed else length = len.get_uint(0) resp.read_string(length).to_sym end end |
#remove_host(host_name) ⇒ Object
Careful with this. If you remove all the hosts you’ll end up with a segfault
532 533 534 535 536 537 538 539 540 541 |
# File 'lib/ruby-tls/ssl.rb', line 532 def remove_host(host_name) raise 'Server Name Indication (SNI) not configured for default host' unless @hosts raise 'only valid for server mode context' unless @is_server context = @hosts[host_name.to_s] if context @hosts.delete(host_name.to_s) context.cleanup end nil end |
#signal_handshake ⇒ Object
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
# File 'lib/ruby-tls/ssl.rb', line 621 def signal_handshake @handshake_signaled = true # Check protocol support here if @context.alpn_set proto = negotiated_protocol if proto == :failed if @negotiated # We should shutdown if this is the case @transport.close_cb return elsif @alpn_fallback # Client or Server with a client that doesn't support ALPN proto = @alpn_fallback.to_sym end end else proto = nil end @transport.handshake_cb(proto) end |
#start ⇒ Object
570 571 572 573 574 |
# File 'lib/ruby-tls/ssl.rb', line 570 def start return unless @ready dispatch_cipher_text end |
#verify(cert) ⇒ Object
Called from class level callback function
674 675 676 |
# File 'lib/ruby-tls/ssl.rb', line 674 def verify(cert) @transport.verify_cb(cert) == true ? 1 : 0 end |