net-ssh 4.2.0 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/config/rubocop_linter_action.yml +4 -0
  5. data/.github/workflows/ci-with-docker.yml +44 -0
  6. data/.github/workflows/ci.yml +87 -0
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.gitignore +7 -0
  9. data/.rubocop.yml +19 -2
  10. data/.rubocop_todo.yml +619 -667
  11. data/CHANGES.txt +110 -1
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +3 -7
  15. data/{Gemfile.norbnacl → Gemfile.noed25519} +3 -1
  16. data/Manifest +4 -5
  17. data/README.md +293 -0
  18. data/Rakefile +45 -29
  19. data/appveyor.yml +8 -6
  20. data/docker-compose.yml +23 -0
  21. data/lib/net/ssh/authentication/agent.rb +248 -223
  22. data/lib/net/ssh/authentication/certificate.rb +178 -164
  23. data/lib/net/ssh/authentication/constants.rb +17 -15
  24. data/lib/net/ssh/authentication/ed25519.rb +141 -116
  25. data/lib/net/ssh/authentication/ed25519_loader.rb +28 -28
  26. data/lib/net/ssh/authentication/key_manager.rb +79 -36
  27. data/lib/net/ssh/authentication/methods/abstract.rb +62 -47
  28. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  29. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -3
  30. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  31. data/lib/net/ssh/authentication/methods/password.rb +15 -16
  32. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  33. data/lib/net/ssh/authentication/pageant.rb +468 -465
  34. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  35. data/lib/net/ssh/authentication/session.rb +131 -122
  36. data/lib/net/ssh/buffer.rb +385 -332
  37. data/lib/net/ssh/buffered_io.rb +150 -151
  38. data/lib/net/ssh/config.rb +316 -239
  39. data/lib/net/ssh/connection/channel.rb +635 -613
  40. data/lib/net/ssh/connection/constants.rb +29 -29
  41. data/lib/net/ssh/connection/event_loop.rb +104 -95
  42. data/lib/net/ssh/connection/keepalive.rb +55 -51
  43. data/lib/net/ssh/connection/session.rb +614 -611
  44. data/lib/net/ssh/connection/term.rb +125 -123
  45. data/lib/net/ssh/errors.rb +101 -99
  46. data/lib/net/ssh/key_factory.rb +194 -108
  47. data/lib/net/ssh/known_hosts.rb +212 -134
  48. data/lib/net/ssh/loggable.rb +50 -49
  49. data/lib/net/ssh/packet.rb +83 -79
  50. data/lib/net/ssh/prompt.rb +51 -51
  51. data/lib/net/ssh/proxy/command.rb +105 -91
  52. data/lib/net/ssh/proxy/errors.rb +12 -10
  53. data/lib/net/ssh/proxy/http.rb +81 -81
  54. data/lib/net/ssh/proxy/https.rb +37 -36
  55. data/lib/net/ssh/proxy/jump.rb +49 -48
  56. data/lib/net/ssh/proxy/socks4.rb +2 -6
  57. data/lib/net/ssh/proxy/socks5.rb +14 -17
  58. data/lib/net/ssh/service/forward.rb +365 -362
  59. data/lib/net/ssh/test/channel.rb +145 -143
  60. data/lib/net/ssh/test/extensions.rb +131 -127
  61. data/lib/net/ssh/test/kex.rb +34 -32
  62. data/lib/net/ssh/test/local_packet.rb +46 -44
  63. data/lib/net/ssh/test/packet.rb +87 -84
  64. data/lib/net/ssh/test/remote_packet.rb +32 -30
  65. data/lib/net/ssh/test/script.rb +155 -155
  66. data/lib/net/ssh/test/socket.rb +49 -48
  67. data/lib/net/ssh/test.rb +82 -80
  68. data/lib/net/ssh/transport/algorithms.rb +433 -364
  69. data/lib/net/ssh/transport/cipher_factory.rb +95 -91
  70. data/lib/net/ssh/transport/constants.rb +32 -24
  71. data/lib/net/ssh/transport/ctr.rb +37 -15
  72. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  73. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  80. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  81. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  82. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  83. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  84. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  85. data/lib/net/ssh/transport/hmac.rb +14 -12
  86. data/lib/net/ssh/transport/identity_cipher.rb +54 -52
  87. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  88. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  89. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  90. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -63
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  96. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  97. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  99. data/lib/net/ssh/transport/kex.rb +15 -12
  100. data/lib/net/ssh/transport/key_expander.rb +24 -21
  101. data/lib/net/ssh/transport/openssl.rb +158 -133
  102. data/lib/net/ssh/transport/packet_stream.rb +223 -191
  103. data/lib/net/ssh/transport/server_version.rb +55 -56
  104. data/lib/net/ssh/transport/session.rb +306 -259
  105. data/lib/net/ssh/transport/state.rb +178 -176
  106. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  107. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  108. data/lib/net/ssh/verifiers/always.rb +58 -0
  109. data/lib/net/ssh/verifiers/never.rb +19 -0
  110. data/lib/net/ssh/version.rb +55 -53
  111. data/lib/net/ssh.rb +47 -34
  112. data/net-ssh-public_cert.pem +18 -19
  113. data/net-ssh.gemspec +12 -11
  114. data/support/ssh_tunnel_bug.rb +5 -5
  115. data.tar.gz.sig +0 -0
  116. metadata +78 -73
  117. metadata.gz.sig +0 -0
  118. data/.travis.yml +0 -51
  119. data/Gemfile.norbnacl.lock +0 -41
  120. data/README.rdoc +0 -169
  121. data/lib/net/ssh/ruby_compat.rb +0 -24
  122. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  123. data/lib/net/ssh/verifiers/null.rb +0 -12
  124. data/lib/net/ssh/verifiers/secure.rb +0 -52
  125. data/lib/net/ssh/verifiers/strict.rb +0 -24
  126. data/support/arcfour_check.rb +0 -20
@@ -3,62 +3,77 @@ require 'net/ssh/errors'
3
3
  require 'net/ssh/loggable'
4
4
  require 'net/ssh/authentication/constants'
5
5
 
6
- module Net; module SSH; module Authentication; module Methods
6
+ module Net
7
+ module SSH
8
+ module Authentication
9
+ module Methods
10
+ # The base class of all user authentication methods. It provides a few
11
+ # bits of common functionality.
12
+ class Abstract
13
+ include Loggable
14
+ include Constants
7
15
 
8
- # The base class of all user authentication methods. It provides a few
9
- # bits of common functionality.
10
- class Abstract
11
- include Constants, Loggable
16
+ # The authentication session object
17
+ attr_reader :session
12
18
 
13
- # The authentication session object
14
- attr_reader :session
19
+ # The key manager object. Not all authentication methods will require
20
+ # this.
21
+ attr_reader :key_manager
15
22
 
16
- # The key manager object. Not all authentication methods will require
17
- # this.
18
- attr_reader :key_manager
23
+ # So far only affects algorithms used for rsa keys, but can be
24
+ # extended to other keys, e.g after reading of
25
+ # PubkeyAcceptedAlgorithms option from ssh_config file is implemented.
26
+ attr_reader :pubkey_algorithms
19
27
 
20
- # Instantiates a new authentication method.
21
- def initialize(session, options={})
22
- @session = session
23
- @key_manager = options[:key_manager]
24
- @options = options
25
- @prompt = options[:password_prompt]
26
- self.logger = session.logger
27
- end
28
+ # Instantiates a new authentication method.
29
+ def initialize(session, options = {})
30
+ @session = session
31
+ @key_manager = options[:key_manager]
32
+ @options = options
33
+ @prompt = options[:password_prompt]
34
+ @pubkey_algorithms = options[:pubkey_algorithms] \
35
+ || %w[rsa-sha2-256-cert-v01@openssh.com
36
+ ssh-rsa-cert-v01@openssh.com
37
+ rsa-sha2-256
38
+ ssh-rsa]
39
+ self.logger = session.logger
40
+ end
28
41
 
29
- # Returns the session-id, as generated during the first key exchange of
30
- # an SSH connection.
31
- def session_id
32
- session.transport.algorithms.session_id
33
- end
42
+ # Returns the session-id, as generated during the first key exchange of
43
+ # an SSH connection.
44
+ def session_id
45
+ session.transport.algorithms.session_id
46
+ end
34
47
 
35
- # Sends a message via the underlying transport layer abstraction. This
36
- # will block until the message is completely sent.
37
- def send_message(msg)
38
- session.transport.send_message(msg)
39
- end
48
+ # Sends a message via the underlying transport layer abstraction. This
49
+ # will block until the message is completely sent.
50
+ def send_message(msg)
51
+ session.transport.send_message(msg)
52
+ end
40
53
 
41
- # Creates a new USERAUTH_REQUEST packet. The extra arguments on the end
42
- # must be either boolean values or strings, and are tacked onto the end
43
- # of the packet. The new packet is returned, ready for sending.
44
- def userauth_request(username, next_service, auth_method, *others)
45
- buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
46
- :string, username, :string, next_service, :string, auth_method)
54
+ # Creates a new USERAUTH_REQUEST packet. The extra arguments on the end
55
+ # must be either boolean values or strings, and are tacked onto the end
56
+ # of the packet. The new packet is returned, ready for sending.
57
+ def userauth_request(username, next_service, auth_method, *others)
58
+ buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
59
+ :string, username, :string, next_service, :string, auth_method)
47
60
 
48
- others.each do |value|
49
- case value
50
- when true, false then buffer.write_bool(value)
51
- when String then buffer.write_string(value)
52
- else raise ArgumentError, "don't know how to write #{value.inspect}"
53
- end
54
- end
61
+ others.each do |value|
62
+ case value
63
+ when true, false then buffer.write_bool(value)
64
+ when String then buffer.write_string(value)
65
+ else raise ArgumentError, "don't know how to write #{value.inspect}"
66
+ end
67
+ end
55
68
 
56
- buffer
57
- end
69
+ buffer
70
+ end
58
71
 
59
- private
72
+ private
60
73
 
61
- attr_reader :prompt
74
+ attr_reader :prompt
75
+ end
76
+ end
77
+ end
62
78
  end
63
-
64
- end; end; end; end
79
+ end
@@ -4,19 +4,18 @@ module Net
4
4
  module SSH
5
5
  module Authentication
6
6
  module Methods
7
-
8
7
  # Implements the host-based SSH authentication method.
9
8
  class Hostbased < Abstract
10
9
  include Constants
11
10
 
12
11
  # Attempts to perform host-based authorization of the user by trying
13
12
  # all known keys.
14
- def authenticate(next_service, username, password=nil)
13
+ def authenticate(next_service, username, password = nil)
15
14
  return false unless key_manager
16
15
 
17
16
  key_manager.each_identity do |identity|
18
17
  return true if authenticate_with(identity, next_service,
19
- username, key_manager)
18
+ username, key_manager)
20
19
  end
21
20
 
22
21
  return false
@@ -24,51 +23,49 @@ module Net
24
23
 
25
24
  private
26
25
 
27
- # Returns the hostname as reported by the underlying socket.
28
- def hostname
29
- session.transport.socket.client_name
30
- end
31
-
32
- # Attempts to perform host-based authentication of the user, using
33
- # the given host identity (key).
34
- def authenticate_with(identity, next_service, username, key_manager)
35
- debug { "trying hostbased (#{identity.fingerprint})" }
36
- client_username = ENV['USER'] || username
26
+ # Returns the hostname as reported by the underlying socket.
27
+ def hostname
28
+ session.transport.socket.client_name
29
+ end
37
30
 
38
- req = build_request(identity, next_service, username, "#{hostname}.", client_username)
39
- sig_data = Buffer.from(:string, session_id, :raw, req)
31
+ # Attempts to perform host-based authentication of the user, using
32
+ # the given host identity (key).
33
+ def authenticate_with(identity, next_service, username, key_manager)
34
+ debug { "trying hostbased (#{identity.fingerprint})" }
35
+ client_username = ENV['USER'] || username
40
36
 
41
- sig = key_manager.sign(identity, sig_data.to_s)
37
+ req = build_request(identity, next_service, username, "#{hostname}.", client_username)
38
+ sig_data = Buffer.from(:string, session_id, :raw, req)
42
39
 
43
- message = Buffer.from(:raw, req, :string, sig)
40
+ sig = key_manager.sign(identity, sig_data.to_s)
44
41
 
45
- send_message(message)
46
- message = session.next_message
42
+ message = Buffer.from(:raw, req, :string, sig)
47
43
 
48
- case message.type
49
- when USERAUTH_SUCCESS
50
- info { "hostbased succeeded (#{identity.fingerprint})" }
51
- return true
52
- when USERAUTH_FAILURE
53
- info { "hostbased failed (#{identity.fingerprint})" }
44
+ send_message(message)
45
+ message = session.next_message
54
46
 
55
- raise Net::SSH::Authentication::DisallowedMethod unless
56
- message[:authentications].split(/,/).include? 'hostbased'
47
+ case message.type
48
+ when USERAUTH_SUCCESS
49
+ info { "hostbased succeeded (#{identity.fingerprint})" }
50
+ return true
51
+ when USERAUTH_FAILURE
52
+ info { "hostbased failed (#{identity.fingerprint})" }
57
53
 
58
- return false
59
- else
60
- raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
61
- end
62
- end
54
+ raise Net::SSH::Authentication::DisallowedMethod unless
55
+ message[:authentications].split(/,/).include? 'hostbased'
63
56
 
64
- # Build the "core" hostbased request string.
65
- def build_request(identity, next_service, username, hostname, client_username)
66
- userauth_request(username, next_service, "hostbased", identity.ssh_type,
67
- Buffer.from(:key, identity).to_s, hostname, client_username).to_s
57
+ return false
58
+ else
59
+ raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
68
60
  end
61
+ end
69
62
 
63
+ # Build the "core" hostbased request string.
64
+ def build_request(identity, next_service, username, hostname, client_username)
65
+ userauth_request(username, next_service, "hostbased", identity.ssh_type,
66
+ Buffer.from(:key, identity).to_s, hostname, client_username).to_s
67
+ end
70
68
  end
71
-
72
69
  end
73
70
  end
74
71
  end
@@ -5,14 +5,13 @@ module Net
5
5
  module SSH
6
6
  module Authentication
7
7
  module Methods
8
-
9
8
  # Implements the "keyboard-interactive" SSH authentication method.
10
9
  class KeyboardInteractive < Abstract
11
10
  USERAUTH_INFO_REQUEST = 60
12
11
  USERAUTH_INFO_RESPONSE = 61
13
12
 
14
13
  # Attempt to authenticate the given user for the given service.
15
- def authenticate(next_service, username, password=nil)
14
+ def authenticate(next_service, username, password = nil)
16
15
  debug { "trying keyboard-interactive" }
17
16
  send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
18
17
 
@@ -32,6 +31,7 @@ module Net
32
31
  message[:authentications].split(/,/).include? 'keyboard-interactive'
33
32
 
34
33
  return false unless interactive?
34
+
35
35
  password = nil
36
36
  debug { "retrying keyboard-interactive" }
37
37
  send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
@@ -45,7 +45,7 @@ module Net
45
45
  end
46
46
 
47
47
  _ = message.read_string # lang_tag
48
- responses =[]
48
+ responses = []
49
49
 
50
50
  message.read_long.times do
51
51
  text = message.read_string
@@ -5,32 +5,29 @@ module Net
5
5
  module SSH
6
6
  module Authentication
7
7
  module Methods
8
-
9
8
  # Implements the "none" SSH authentication method.
10
9
  class None < Abstract
11
10
  # Attempt to authenticate as "none"
12
- def authenticate(next_service, user="", password="")
13
- send_message(userauth_request(user, next_service, "none"))
11
+ def authenticate(next_service, user = "", password = "")
12
+ send_message(userauth_request(user, next_service, "none"))
14
13
  message = session.next_message
15
-
14
+
16
15
  case message.type
17
- when USERAUTH_SUCCESS
18
- debug { "none succeeded" }
19
- return true
20
- when USERAUTH_FAILURE
21
- debug { "none failed" }
22
-
23
- raise Net::SSH::Authentication::DisallowedMethod unless
24
- message[:authentications].split(/,/).include? 'none'
25
-
26
- return false
27
- else
28
- raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
29
- end
30
-
16
+ when USERAUTH_SUCCESS
17
+ debug { "none succeeded" }
18
+ return true
19
+ when USERAUTH_FAILURE
20
+ debug { "none failed" }
21
+
22
+ raise Net::SSH::Authentication::DisallowedMethod unless
23
+ message[:authentications].split(/,/).include? 'none'
24
+
25
+ return false
26
+ else
27
+ raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
28
+ end
31
29
  end
32
30
  end
33
-
34
31
  end
35
32
  end
36
33
  end
@@ -6,15 +6,14 @@ module Net
6
6
  module SSH
7
7
  module Authentication
8
8
  module Methods
9
-
10
9
  # Implements the "password" SSH authentication method.
11
10
  class Password < Abstract
12
11
  # Attempt to authenticate the given user for the given service. If
13
12
  # the password parameter is nil, this will ask for password
14
- def authenticate(next_service, username, password=nil)
13
+ def authenticate(next_service, username, password = nil)
15
14
  clear_prompter!
16
15
  retries = 0
17
- max_retries = get_max_retries
16
+ max_retries = get_max_retries
18
17
  return false if !password && max_retries == 0
19
18
 
20
19
  begin
@@ -29,22 +28,23 @@ module Net
29
28
 
30
29
  raise Net::SSH::Authentication::DisallowedMethod unless
31
30
  message[:authentications].split(/,/).include? 'password'
31
+
32
32
  password = nil
33
33
  end
34
34
  end until (message.type != USERAUTH_FAILURE || retries >= max_retries)
35
35
 
36
36
  case message.type
37
- when USERAUTH_SUCCESS
38
- debug { "password succeeded" }
39
- @prompter.success if @prompter
40
- return true
41
- when USERAUTH_FAILURE
42
- return false
43
- when USERAUTH_PASSWD_CHANGEREQ
44
- debug { "password change request received, failing" }
45
- return false
46
- else
47
- raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
37
+ when USERAUTH_SUCCESS
38
+ debug { "password succeeded" }
39
+ @prompter.success if @prompter
40
+ return true
41
+ when USERAUTH_FAILURE
42
+ return false
43
+ when USERAUTH_PASSWD_CHANGEREQ
44
+ debug { "password change request received, failing" }
45
+ return false
46
+ else
47
+ raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
48
48
  end
49
49
  end
50
50
 
@@ -59,7 +59,7 @@ module Net
59
59
 
60
60
  def ask_password(username)
61
61
  host = session.transport.host
62
- prompt_info = {type: 'password', user: username, host: host}
62
+ prompt_info = { type: 'password', user: username, host: host }
63
63
  if @prompt_info != prompt_info
64
64
  @prompt_info = prompt_info
65
65
  @prompter = prompt.start(prompt_info)
@@ -74,7 +74,6 @@ module Net
74
74
  options[:non_interactive] ? 0 : result
75
75
  end
76
76
  end
77
-
78
77
  end
79
78
  end
80
79
  end
@@ -6,14 +6,13 @@ module Net
6
6
  module SSH
7
7
  module Authentication
8
8
  module Methods
9
-
10
9
  # Implements the "publickey" SSH authentication method.
11
10
  class Publickey < Abstract
12
11
  # Attempts to perform public-key authentication for the given
13
12
  # username, trying each identity known to the key manager. If any of
14
13
  # them succeed, returns +true+, otherwise returns +false+. This
15
14
  # requires the presence of a key manager.
16
- def authenticate(next_service, username, password=nil)
15
+ def authenticate(next_service, username, password = nil)
17
16
  return false unless key_manager
18
17
 
19
18
  key_manager.each_identity do |identity|
@@ -25,71 +24,113 @@ module Net
25
24
 
26
25
  private
27
26
 
28
- # Builds a packet that contains the request formatted for sending
29
- # a public-key request to the server.
30
- def build_request(pub_key, username, next_service, has_sig)
31
- blob = Net::SSH::Buffer.new
32
- blob.write_key pub_key
27
+ # Builds a packet that contains the request formatted for sending
28
+ # a public-key request to the server.
29
+ def build_request(pub_key, username, next_service, alg, has_sig)
30
+ blob = Net::SSH::Buffer.new
31
+ blob.write_key pub_key
33
32
 
34
- userauth_request(username, next_service, "publickey", has_sig,
35
- pub_key.ssh_type, blob.to_s)
36
- end
33
+ userauth_request(username, next_service, "publickey", has_sig,
34
+ alg, blob.to_s)
35
+ end
37
36
 
38
- # Builds and sends a request formatted for a public-key
39
- # authentication request.
40
- def send_request(pub_key, username, next_service, signature=nil)
41
- msg = build_request(pub_key, username, next_service, !signature.nil?)
42
- msg.write_string(signature) if signature
43
- send_message(msg)
44
- end
37
+ # Builds and sends a request formatted for a public-key
38
+ # authentication request.
39
+ def send_request(pub_key, username, next_service, alg, signature = nil)
40
+ msg = build_request(pub_key, username, next_service, alg,
41
+ !signature.nil?)
42
+ msg.write_string(signature) if signature
43
+ send_message(msg)
44
+ end
45
+
46
+ def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil)
47
+ debug { "trying publickey (#{identity.fingerprint})" }
48
+ send_request(identity, username, next_service, alg)
45
49
 
46
- # Attempts to perform public-key authentication for the given
47
- # username, with the given identity (public key). Returns +true+ if
48
- # successful, or +false+ otherwise.
49
- def authenticate_with(identity, next_service, username)
50
- debug { "trying publickey (#{identity.fingerprint})" }
51
- send_request(identity, username, next_service)
50
+ message = session.next_message
52
51
 
52
+ case message.type
53
+ when USERAUTH_PK_OK
54
+ buffer = build_request(identity, username, next_service, alg,
55
+ true)
56
+ sig_data = Net::SSH::Buffer.new
57
+ sig_data.write_string(session_id)
58
+ sig_data.append(buffer.to_s)
59
+
60
+ sig_blob = key_manager.sign(identity, sig_data, sig_alg)
61
+
62
+ send_request(identity, username, next_service, alg, sig_blob.to_s)
53
63
  message = session.next_message
54
64
 
55
65
  case message.type
56
- when USERAUTH_PK_OK
57
- buffer = build_request(identity, username, next_service, true)
58
- sig_data = Net::SSH::Buffer.new
59
- sig_data.write_string(session_id)
60
- sig_data.append(buffer.to_s)
61
-
62
- sig_blob = key_manager.sign(identity, sig_data)
63
-
64
- send_request(identity, username, next_service, sig_blob.to_s)
65
- message = session.next_message
66
-
67
- case message.type
68
- when USERAUTH_SUCCESS
69
- debug { "publickey succeeded (#{identity.fingerprint})" }
70
- return true
71
- when USERAUTH_FAILURE
72
- debug { "publickey failed (#{identity.fingerprint})" }
73
-
74
- raise Net::SSH::Authentication::DisallowedMethod unless
75
- message[:authentications].split(/,/).include? 'publickey'
76
-
77
- return false
78
- else
79
- raise Net::SSH::Exception,
80
- "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
81
- end
66
+ when USERAUTH_SUCCESS
67
+ debug { "publickey succeeded (#{identity.fingerprint})" }
68
+ return true
69
+ when USERAUTH_FAILURE
70
+ debug { "publickey failed (#{identity.fingerprint})" }
71
+
72
+ raise Net::SSH::Authentication::DisallowedMethod unless
73
+ message[:authentications].split(/,/).include? 'publickey'
74
+
75
+ return false
76
+ else
77
+ raise Net::SSH::Exception,
78
+ "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
79
+ end
82
80
 
83
- when USERAUTH_FAILURE
84
- return false
81
+ when USERAUTH_FAILURE
82
+ return false
83
+ when USERAUTH_SUCCESS
84
+ return true
85
85
 
86
- else
87
- raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
88
- end
86
+ else
87
+ raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
89
88
  end
89
+ end
90
90
 
91
+ # Attempts to perform public-key authentication for the given
92
+ # username, with the given identity (public key). Returns +true+ if
93
+ # successful, or +false+ otherwise.
94
+ def authenticate_with(identity, next_service, username)
95
+ type = identity.ssh_type
96
+ if type == "ssh-rsa"
97
+ pubkey_algorithms.each do |pk_alg|
98
+ case pk_alg
99
+ when "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa"
100
+ if authenticate_with_alg(identity, next_service, username, pk_alg, pk_alg)
101
+ # success
102
+ return true
103
+ end
104
+ end
105
+ end
106
+ elsif type == "ssh-rsa-cert-v01@openssh.com"
107
+ pubkey_algorithms.each do |pk_alg|
108
+ case pk_alg
109
+ when "rsa-sha2-512-cert-v01@openssh.com"
110
+ if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-512")
111
+ # success
112
+ return true
113
+ end
114
+ when "rsa-sha2-256-cert-v01@openssh.com"
115
+ if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-256")
116
+ # success
117
+ return true
118
+ end
119
+ when "ssh-rsa-cert-v01@openssh.com"
120
+ if authenticate_with_alg(identity, next_service, username, pk_alg)
121
+ # success
122
+ return true
123
+ end
124
+ end
125
+ end
126
+ elsif authenticate_with_alg(identity, next_service, username, type)
127
+ # success
128
+ return true
129
+ end
130
+ # failure
131
+ return false
132
+ end
91
133
  end
92
-
93
134
  end
94
135
  end
95
136
  end