Class: OverSIP::SIP::TlsClient

Inherits:
TcpClient show all
Defined in:
lib/oversip/sip/listeners/tls_client.rb

Direct Known Subclasses

IPv4TlsClient, IPv6TlsClient

Constant Summary collapse

TLS_HANDSHAKE_MAX_TIME =
4

Constants inherited from TcpReactor

OverSIP::SIP::TcpReactor::HEADERS_MAX_SIZE

Constants included from MessageProcessor

MessageProcessor::MSG_TYPE

Constants included from Logger

Logger::SYSLOG_POSIXMQ_MAPPING

Instance Attribute Summary collapse

Attributes inherited from TcpClient

#connected, #pending_client_transactions, #server_class

Instance Method Summary collapse

Methods inherited from TcpClient

#remote_desc

Methods inherited from TcpReactor

#get_body, #parse_headers, #receive_data

Methods inherited from Reactor

#receive_senderror, reliable_transport_listener?

Methods included from Logger

close, #fatal, fg_system_msg2str, init_logger_mq, load_methods, #log_id, syslog_system_msg2str, syslog_user_msg2str

Constructor Details

#initialize(ip, port) ⇒ TlsClient

Returns a new instance of TlsClient.



11
12
13
14
# File 'lib/oversip/sip/listeners/tls_client.rb', line 11

def initialize ip, port
  super
  @pending_messages = []
end

Instance Attribute Details

#tls_validation=(value) ⇒ Object (writeonly)

Sets the attribute tls_validation

Parameters:

  • value

    the value to set the attribute tls_validation to.



8
9
10
# File 'lib/oversip/sip/listeners/tls_client.rb', line 8

def tls_validation=(value)
  @tls_validation = value
end

Instance Method Details

#connection_completedObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/oversip/sip/listeners/tls_client.rb', line 17

def connection_completed
  @server_pems = []
  @server_last_pem = false

  start_tls({
    :verify_peer => @tls_validation,
    :cert_chain_file => ::OverSIP.tls_public_cert,
    :private_key_file => ::OverSIP.tls_private_cert
  })

  # If the remote server 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

#send_sip_msg(msg, ip = nil, port = nil) ⇒ Object

In TLS client, we must wait until ssl_handshake_completed is completed before sending data. If not, data will be sent in plain TCP.

http://dev.sipdoc.net/issues/457


100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/oversip/sip/listeners/tls_client.rb', line 100

def send_sip_msg msg, ip=nil, port=nil
  if self.error?
    log_system_notice "SIP message could not be sent, connection is closed"
    return false
  end

  if @connected
    send_data msg
  else
    log_system_debug "TLS handshake not completed yet, waiting before sending the message"  if $oversip_debug
    @pending_messages << msg
  end
  true
end

#ssl_handshake_completedObject

This is called after all the calls to ssl_verify_peer().



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/oversip/sip/listeners/tls_client.rb', line 56

def ssl_handshake_completed
  log_system_info "TLS connection established to " << remote_desc

  # @connected in TlsClient means "TLS connection" rather than
  # just "TCP connection".
  @connected = true
  @timer_tls_handshake.cancel  if @timer_tls_handshake

  if @tls_validation
    validated, cert, tls_error, tls_error_string = ::OverSIP::TLS.validate @server_pems.pop, @server_pems
    if validated
      log_system_info "server provides a valid TLS certificate"
      sip_identities = ::OverSIP::TLS.get_sip_identities(cert)
      log_system_debug "SIP identities in peer cert: #{sip_identities.keys}"  if $oversip_debug
    else
      log_system_notice "server's TLS certificate validation failed (TLS error: #{tls_error.inspect}, description: #{tls_error_string.inspect})"
      @pending_client_transactions.each do |client_transaction|
        client_transaction.tls_validation_failed
      end
      @pending_client_transactions.clear
      @pending_messages.clear
      close_connection
      @state = :ignore
      return
    end
  end

  @pending_client_transactions.clear
  @pending_messages.each do |msg|
    send_data msg
  end
  @pending_messages.clear
end

#ssl_verify_peer(pem) ⇒ Object

Called for every certificate provided by the peer. This is just called in case @tls_validation is true.



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/oversip/sip/listeners/tls_client.rb', line 41

def ssl_verify_peer pem
  # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194.
  return true  if @server_last_pem == pem

  @server_last_pem = pem
  @server_pems << pem

  log_system_debug "received certificate num #{@server_pems.size} from server"  if $oversip_debug

  # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true.
  return true
end

#unbind(cause = nil) ⇒ Object



90
91
92
93
94
# File 'lib/oversip/sip/listeners/tls_client.rb', line 90

def unbind cause=nil
  super
  @timer_tls_handshake.cancel  if @timer_tls_handshake
  @pending_messages.clear
end