Class: Net::SSH::Transport::Algorithms

Inherits:
Object
  • Object
show all
Includes:
Loggable, Constants
Defined in:
lib/net/ssh/transport/algorithms.rb

Overview

Implements the higher-level logic behind an SSH key-exchange. It handles both the initial exchange, as well as subsequent re-exchanges (as needed). It also encapsulates the negotiation of the algorithms, and provides a single point of access to the negotiated algorithms.

You will never instantiate or reference this directly. It is used internally by the transport layer.

Constant Summary collapse

DEFAULT_ALGORITHMS =

Define the default algorithms, in order of preference, supported by Net::SSH.

{
  host_key: %w[ecdsa-sha2-nistp521-cert-v01@openssh.com
               ecdsa-sha2-nistp384-cert-v01@openssh.com
               ecdsa-sha2-nistp256-cert-v01@openssh.com
               ecdsa-sha2-nistp521
               ecdsa-sha2-nistp384
               ecdsa-sha2-nistp256
               ssh-rsa-cert-v01@openssh.com
               ssh-rsa-cert-v00@openssh.com
               ssh-rsa
               rsa-sha2-256
               rsa-sha2-512],

  kex: %w[ecdh-sha2-nistp521
          ecdh-sha2-nistp384
          ecdh-sha2-nistp256
          diffie-hellman-group-exchange-sha256
          diffie-hellman-group14-sha256
          diffie-hellman-group14-sha1],

  encryption: %w[aes256-ctr
                 aes192-ctr
                 aes128-ctr
                 aes256-gcm@openssh.com
                 aes128-gcm@openssh.com],

  hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
           hmac-sha2-512 hmac-sha2-256
           hmac-sha1]
}.freeze
ALGORITHMS =

Define all algorithms, with the deprecated, supported by Net::SSH.

{
  host_key: DEFAULT_ALGORITHMS[:host_key] + %w[ssh-dss],

  kex: DEFAULT_ALGORITHMS[:kex] +
       %w[diffie-hellman-group-exchange-sha1
          diffie-hellman-group1-sha1],

  encryption: DEFAULT_ALGORITHMS[:encryption] +
              %w[aes256-cbc aes192-cbc aes128-cbc
                 rijndael-cbc@lysator.liu.se
                 blowfish-ctr blowfish-cbc
                 cast128-ctr cast128-cbc
                 3des-ctr 3des-cbc
                 idea-cbc
                 none],

  hmac: DEFAULT_ALGORITHMS[:hmac] +
        %w[hmac-sha2-512-96 hmac-sha2-256-96
           hmac-sha1-96
           hmac-ripemd160 hmac-ripemd160@openssh.com
           hmac-md5 hmac-md5-96
           none],

  compression: %w[none zlib@openssh.com zlib],
  language: %w[]
}.freeze

Constants included from Constants

Constants::DEBUG, Constants::DISCONNECT, Constants::IGNORE, Constants::KEXDH_GEX_GROUP, Constants::KEXDH_GEX_INIT, Constants::KEXDH_GEX_REPLY, Constants::KEXDH_GEX_REQUEST, Constants::KEXDH_INIT, Constants::KEXDH_REPLY, Constants::KEXECDH_INIT, Constants::KEXECDH_REPLY, Constants::KEXINIT, Constants::NEWKEYS, Constants::SERVICE_ACCEPT, Constants::SERVICE_REQUEST, Constants::UNIMPLEMENTED

Instance Attribute Summary collapse

Attributes included from Loggable

#logger

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Loggable

#debug, #error, #fatal, #info, #lwarn

Constructor Details

#initialize(session, options = {}) ⇒ Algorithms

Instantiates a new Algorithms object, and prepares the hash of preferred algorithms based on the options parameter and the ALGORITHMS constant.



158
159
160
161
162
163
164
165
166
# File 'lib/net/ssh/transport/algorithms.rb', line 158

def initialize(session, options = {})
  @session = session
  @logger = session.logger
  @options = options
  @algorithms = {}
  @pending = @initialized = false
  @client_packet = @server_packet = nil
  prepare_preferred_algorithms!
end

Instance Attribute Details

#algorithmsObject (readonly)

The hash of algorithms preferred by the client, which will be told to the server during algorithm negotiation.



144
145
146
# File 'lib/net/ssh/transport/algorithms.rb', line 144

def algorithms
  @algorithms
end

#compression_clientObject (readonly)

The type of compression to use to compress packets being sent by the client.



131
132
133
# File 'lib/net/ssh/transport/algorithms.rb', line 131

def compression_client
  @compression_client
end

#compression_serverObject (readonly)

The type of compression to use to decompress packets arriving from the server.



134
135
136
# File 'lib/net/ssh/transport/algorithms.rb', line 134

def compression_server
  @compression_server
end

#encryption_clientObject (readonly)

The type of the cipher to use to encrypt packets sent from the client to the server.



119
120
121
# File 'lib/net/ssh/transport/algorithms.rb', line 119

def encryption_client
  @encryption_client
end

#encryption_serverObject (readonly)

The type of the cipher to use to decrypt packets arriving from the server.



122
123
124
# File 'lib/net/ssh/transport/algorithms.rb', line 122

def encryption_server
  @encryption_server
end

#hmac_clientObject (readonly)

The type of HMAC to use to sign packets sent by the client.



125
126
127
# File 'lib/net/ssh/transport/algorithms.rb', line 125

def hmac_client
  @hmac_client
end

#hmac_serverObject (readonly)

The type of HMAC to use to validate packets arriving from the server.



128
129
130
# File 'lib/net/ssh/transport/algorithms.rb', line 128

def hmac_server
  @hmac_server
end

#host_keyObject (readonly)

The type of host key that will be used for this session.



115
116
117
# File 'lib/net/ssh/transport/algorithms.rb', line 115

def host_key
  @host_key
end

#kexObject (readonly)

The kex algorithm to use settled on between the client and server.



112
113
114
# File 'lib/net/ssh/transport/algorithms.rb', line 112

def kex
  @kex
end

#language_clientObject (readonly)

The language that will be used in messages sent by the client.



137
138
139
# File 'lib/net/ssh/transport/algorithms.rb', line 137

def language_client
  @language_client
end

#language_serverObject (readonly)

The language that will be used in messages sent from the server.



140
141
142
# File 'lib/net/ssh/transport/algorithms.rb', line 140

def language_server
  @language_server
end

#optionsObject (readonly)

The hash of options used to initialize this object



109
110
111
# File 'lib/net/ssh/transport/algorithms.rb', line 109

def options
  @options
end

#sessionObject (readonly)

The underlying transport layer session that supports this object



106
107
108
# File 'lib/net/ssh/transport/algorithms.rb', line 106

def session
  @session
end

#session_idObject (readonly)

The session-id for this session, as decided during the initial key exchange.



147
148
149
# File 'lib/net/ssh/transport/algorithms.rb', line 147

def session_id
  @session_id
end

Class Method Details

.allowed_packet?(packet) ⇒ Boolean

Returns true if the given packet can be processed during a key-exchange.

Returns:

  • (Boolean)


150
151
152
153
154
# File 'lib/net/ssh/transport/algorithms.rb', line 150

def self.allowed_packet?(packet)
  (1..4).include?(packet.type) ||
  (6..19).include?(packet.type) ||
  (21..49).include?(packet.type)
end

Instance Method Details

#[](key) ⇒ Object

A convenience method for accessing the list of preferred types for a specific algorithm (see #algorithms).



202
203
204
# File 'lib/net/ssh/transport/algorithms.rb', line 202

def [](key)
  algorithms[key]
end

#accept_kexinit(packet) ⇒ Object

Called by the transport layer when a KEXINIT packet is received, indicating that the server wants to exchange keys. This can be spontaneous, or it can be in response to a client-initiated rekey request (see #rekey!). Either way, this will block until the key exchange completes.



189
190
191
192
193
194
195
196
197
198
# File 'lib/net/ssh/transport/algorithms.rb', line 189

def accept_kexinit(packet)
  info { "got KEXINIT from server" }
  @server_data = parse_server_algorithm_packet(packet)
  @server_packet = @server_data[:raw]
  if !pending?
    send_kexinit
  else
    proceed!
  end
end

#allow?(packet) ⇒ Boolean

Returns true if no exchange is pending, and otherwise returns true or false depending on whether the given packet is of a type that is allowed during a key exchange.

Returns:

  • (Boolean)


218
219
220
# File 'lib/net/ssh/transport/algorithms.rb', line 218

def allow?(packet)
  !pending? || Algorithms.allowed_packet?(packet)
end

#host_key_formatObject



227
228
229
230
231
232
233
234
# File 'lib/net/ssh/transport/algorithms.rb', line 227

def host_key_format
  case host_key
  when /^([a-z0-9-]+)-cert-v\d{2}@openssh.com$/
    Regexp.last_match[1]
  else
    host_key
  end
end

#initialized?Boolean

Returns true if the algorithms have been negotiated at all.

Returns:

  • (Boolean)


223
224
225
# File 'lib/net/ssh/transport/algorithms.rb', line 223

def initialized?
  @initialized
end

#pending?Boolean

Returns true if a key-exchange is pending. This will be true from the moment either the client or server requests the key exchange, until the exchange completes. While an exchange is pending, only a limited number of packets are allowed, so event processing essentially stops during this period.

Returns:

  • (Boolean)


211
212
213
# File 'lib/net/ssh/transport/algorithms.rb', line 211

def pending?
  @pending
end

#rekey!Object

Request a rekey operation. This will return immediately, and does not actually perform the rekey operation. It does cause the session to change state, however--until the key exchange finishes, no new packets will be processed.



179
180
181
182
183
# File 'lib/net/ssh/transport/algorithms.rb', line 179

def rekey!
  @client_packet = @server_packet = nil
  @initialized = false
  send_kexinit
end

#startObject

Start the algorithm negotation

Raises:

  • (ArgumentError)


169
170
171
172
173
# File 'lib/net/ssh/transport/algorithms.rb', line 169

def start
  raise ArgumentError, "Cannot call start if it's negotiation started or done" if @pending || @initialized

  send_kexinit
end