module OverSIP::WebSocket class TlsServer < TcpServer TLS_HANDSHAKE_MAX_TIME = 8 def post_init @client_pems = [] @client_last_pem = false start_tls({ :verify_peer => true, :cert_chain_file => ::OverSIP.tls_public_cert, :private_key_file => ::OverSIP.tls_private_cert }) # If the remote client does never send us a TLS certificate # after the TCP connection we would leak by storing more and # more messages in @pending_messages array. @timer_tls_handshake = ::EM::Timer.new(TLS_HANDSHAKE_MAX_TIME) do unless @connected log_system_notice "TLS handshake not performed within #{TLS_HANDSHAKE_MAX_TIME} seconds, closing the connection" close_connection end end end def ssl_verify_peer pem # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194. return true if @client_last_pem == pem @client_last_pem = pem @client_pems << pem log_system_debug "received certificate num #{@client_pems.size} from client" if $oversip_debug # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true. return true end def ssl_handshake_completed log_system_info "TLS connection established from " << remote_desc # TODO: What to do it falidation fails? always do validation? validated, cert, tls_error, tls_error_string = ::OverSIP::TLS.validate @client_pems.pop, @client_pems if validated log_system_info "client provides a valid TLS certificate" else log_system_notice "client's TLS certificate validation failed (TLS error: #{tls_error.inspect}, description: #{tls_error_string.inspect})" end # @connected in TlsServer means "TLS connection" rather than # just "TCP connection". @connected = true @timer_tls_handshake.cancel if @timer_tls_handshake end def unbind cause=nil @timer_tls_handshake.cancel if @timer_tls_handshake super end end end