net-ssh 6.3.0.beta1 → 7.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  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 +4 -10
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.rubocop.yml +2 -1
  9. data/.rubocop_todo.yml +244 -237
  10. data/Dockerfile +27 -0
  11. data/Dockerfile.openssl3 +17 -0
  12. data/README.md +7 -1
  13. data/Rakefile +4 -0
  14. data/docker-compose.yml +23 -0
  15. data/lib/net/ssh/authentication/agent.rb +13 -13
  16. data/lib/net/ssh/authentication/certificate.rb +4 -4
  17. data/lib/net/ssh/authentication/ed25519.rb +5 -5
  18. data/lib/net/ssh/authentication/key_manager.rb +18 -5
  19. data/lib/net/ssh/authentication/methods/abstract.rb +12 -2
  20. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -3
  21. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
  22. data/lib/net/ssh/authentication/methods/none.rb +1 -1
  23. data/lib/net/ssh/authentication/methods/password.rb +1 -1
  24. data/lib/net/ssh/authentication/methods/publickey.rb +56 -14
  25. data/lib/net/ssh/authentication/pageant.rb +8 -8
  26. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -2
  27. data/lib/net/ssh/authentication/session.rb +5 -3
  28. data/lib/net/ssh/buffer.rb +41 -26
  29. data/lib/net/ssh/buffered_io.rb +6 -6
  30. data/lib/net/ssh/config.rb +4 -4
  31. data/lib/net/ssh/connection/channel.rb +13 -13
  32. data/lib/net/ssh/connection/event_loop.rb +8 -8
  33. data/lib/net/ssh/connection/session.rb +13 -13
  34. data/lib/net/ssh/errors.rb +2 -2
  35. data/lib/net/ssh/key_factory.rb +7 -7
  36. data/lib/net/ssh/known_hosts.rb +5 -4
  37. data/lib/net/ssh/prompt.rb +1 -1
  38. data/lib/net/ssh/proxy/http.rb +1 -1
  39. data/lib/net/ssh/proxy/https.rb +2 -2
  40. data/lib/net/ssh/proxy/socks4.rb +1 -1
  41. data/lib/net/ssh/proxy/socks5.rb +1 -1
  42. data/lib/net/ssh/service/forward.rb +4 -4
  43. data/lib/net/ssh/test/channel.rb +3 -3
  44. data/lib/net/ssh/test/extensions.rb +6 -6
  45. data/lib/net/ssh/test/packet.rb +1 -1
  46. data/lib/net/ssh/test/script.rb +3 -3
  47. data/lib/net/ssh/test/socket.rb +1 -1
  48. data/lib/net/ssh/test.rb +3 -3
  49. data/lib/net/ssh/transport/algorithms.rb +12 -12
  50. data/lib/net/ssh/transport/cipher_factory.rb +15 -15
  51. data/lib/net/ssh/transport/ctr.rb +3 -3
  52. data/lib/net/ssh/transport/hmac/abstract.rb +4 -4
  53. data/lib/net/ssh/transport/hmac.rb +12 -12
  54. data/lib/net/ssh/transport/identity_cipher.rb +1 -1
  55. data/lib/net/ssh/transport/kex/abstract.rb +3 -3
  56. data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
  57. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +1 -1
  58. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
  59. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -1
  60. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
  61. data/lib/net/ssh/transport/kex.rb +7 -7
  62. data/lib/net/ssh/transport/key_expander.rb +1 -1
  63. data/lib/net/ssh/transport/openssl.rb +32 -11
  64. data/lib/net/ssh/transport/packet_stream.rb +1 -1
  65. data/lib/net/ssh/transport/session.rb +6 -6
  66. data/lib/net/ssh/transport/state.rb +1 -1
  67. data/lib/net/ssh/version.rb +2 -2
  68. data/lib/net/ssh.rb +3 -3
  69. data/net-ssh.gemspec +2 -2
  70. data.tar.gz.sig +0 -0
  71. metadata +13 -7
  72. metadata.gz.sig +1 -2
  73. data/.travis.yml +0 -51
data/Dockerfile ADDED
@@ -0,0 +1,27 @@
1
+ ARG RUBY_VERSION=3.1
2
+ FROM ruby:${RUBY_VERSION}
3
+
4
+ RUN apt update && apt install -y openssh-server sudo netcat \
5
+ && useradd --create-home --shell '/bin/bash' --comment 'NetSSH' 'net_ssh_1' \
6
+ && useradd --create-home --shell '/bin/bash' --comment 'NetSSH' 'net_ssh_2' \
7
+ && echo net_ssh_1:foopwd | chpasswd \
8
+ && echo net_ssh_2:foo2pwd | chpasswd \
9
+ && mkdir -p /home/net_ssh_1/.ssh \
10
+ && mkdir -p /home/net_ssh_2/.ssh \
11
+ && echo "net_ssh_1 ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \
12
+ && echo "net_ssh_2 ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \
13
+ && ssh-keygen -f /etc/ssh/users_ca -N ''
14
+
15
+ ENV INSTALL_PATH="/netssh"
16
+
17
+ WORKDIR $INSTALL_PATH
18
+
19
+ COPY Gemfile net-ssh.gemspec $INSTALL_PATH/
20
+
21
+ COPY lib/net/ssh/version.rb $INSTALL_PATH/lib/net/ssh/version.rb
22
+
23
+ RUN gem install bundler && bundle install
24
+
25
+ COPY . $INSTALL_PATH/
26
+
27
+ CMD service ssh start && rake test && NET_SSH_NO_ED25519=1 rake test
@@ -0,0 +1,17 @@
1
+ FROM ubuntu:22.04
2
+
3
+ ENV INSTALL_PATH="/netssh"
4
+
5
+ RUN apt update && apt install -y openssl ruby ruby-dev git build-essential
6
+
7
+ WORKDIR $INSTALL_PATH
8
+
9
+ COPY Gemfile net-ssh.gemspec $INSTALL_PATH/
10
+
11
+ COPY lib/net/ssh/version.rb $INSTALL_PATH/lib/net/ssh/version.rb
12
+
13
+ RUN ls -l && gem install bundler && bundle install
14
+
15
+ COPY . $INSTALL_PATH/
16
+
17
+ CMD openssl version && ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION' && rake test
data/README.md CHANGED
@@ -211,13 +211,19 @@ Run the test suite from the net-ssh directory with the following command:
211
211
  bundle exec rake test
212
212
  ```
213
213
 
214
+ NOTE : you can run test on all ruby versions with docker :
215
+
216
+ ```
217
+ docker-compose up --build
218
+ ```
219
+
214
220
  Run a single test file like this:
215
221
 
216
222
  ```sh
217
223
  ruby -Ilib -Itest test/transport/test_server_version.rb
218
224
  ```
219
225
 
220
- To run integration tests see test/integration/README.txt
226
+ To run integration tests see [here](test/integration/README.md)
221
227
 
222
228
  ### BUILDING GEM
223
229
 
data/Rakefile CHANGED
@@ -95,6 +95,10 @@ Rake::TestTask.new do |t|
95
95
  t.test_files = test_files
96
96
  end
97
97
 
98
+ # We need to enable the OpenSSL 3.0 legacy providers for our test suite
99
+ require 'openssl'
100
+ ENV['OPENSSL_CONF'] = 'test/openssl3.conf' if OpenSSL::OPENSSL_LIBRARY_VERSION.start_with? "OpenSSL 3"
101
+
98
102
  desc "Run tests of Net::SSH:Test"
99
103
  Rake::TestTask.new do |t|
100
104
  t.name = "test_test"
@@ -0,0 +1,23 @@
1
+ version: '3'
2
+
3
+ services:
4
+ ruby-3.1:
5
+ build:
6
+ context: .
7
+ args:
8
+ RUBY_VERSION: 3.1
9
+ ruby-3.0:
10
+ build:
11
+ context: .
12
+ args:
13
+ RUBY_VERSION: 3.0
14
+ ruby-2.7:
15
+ build:
16
+ context: .
17
+ args:
18
+ RUBY_VERSION: 2.7
19
+ ruby-2.6:
20
+ build:
21
+ context: .
22
+ args:
23
+ RUBY_VERSION: 2.6
@@ -65,7 +65,7 @@ module Net
65
65
 
66
66
  # Instantiates a new agent object, connects to a running SSH agent,
67
67
  # negotiates the agent protocol version, and returns the agent object.
68
- def self.connect(logger=nil, agent_socket_factory = nil, identity_agent = nil)
68
+ def self.connect(logger = nil, agent_socket_factory = nil, identity_agent = nil)
69
69
  agent = new(logger)
70
70
  agent.connect!(agent_socket_factory, identity_agent)
71
71
  agent.negotiate!
@@ -74,7 +74,7 @@ module Net
74
74
 
75
75
  # Creates a new Agent object, using the optional logger instance to
76
76
  # report status.
77
- def initialize(logger=nil)
77
+ def initialize(logger = nil)
78
78
  self.logger = logger
79
79
  end
80
80
 
@@ -88,9 +88,9 @@ module Net
88
88
  if agent_socket_factory
89
89
  agent_socket_factory.call
90
90
  elsif identity_agent
91
- unix_socket_class.open(identity_agent)
91
+ unix_socket_class.open(File.expand_path(identity_agent))
92
92
  elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class
93
- unix_socket_class.open(ENV['SSH_AUTH_SOCK'])
93
+ unix_socket_class.open(File.expand_path(ENV['SSH_AUTH_SOCK']))
94
94
  elsif Gem.win_platform? && RUBY_ENGINE != "jruby"
95
95
  Pageant::Socket.open
96
96
  else
@@ -177,7 +177,7 @@ module Net
177
177
 
178
178
  req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED
179
179
  type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key),
180
- :string, comment, :raw, constraints)
180
+ :string, comment, :raw, constraints)
181
181
  raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS
182
182
  end
183
183
 
@@ -251,31 +251,31 @@ module Net
251
251
  case priv_key.ssh_type
252
252
  when /^ssh-dss$/
253
253
  Net::SSH::Buffer.from(:bignum, priv_key.p, :bignum, priv_key.q, :bignum, priv_key.g,
254
- :bignum, priv_key.pub_key, :bignum, priv_key.priv_key).to_s
254
+ :bignum, priv_key.pub_key, :bignum, priv_key.priv_key).to_s
255
255
  when /^ssh-dss-cert-v01@openssh\.com$/
256
256
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.priv_key).to_s
257
257
  when /^ecdsa\-sha2\-(\w*)$/
258
258
  curve_name = OpenSSL::PKey::EC::CurveNameAliasInv[priv_key.group.curve_name]
259
259
  Net::SSH::Buffer.from(:string, curve_name, :mstring, priv_key.public_key.to_bn.to_s(2),
260
- :bignum, priv_key.private_key).to_s
260
+ :bignum, priv_key.private_key).to_s
261
261
  when /^ecdsa\-sha2\-(\w*)-cert-v01@openssh\.com$/
262
262
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.private_key).to_s
263
263
  when /^ssh-ed25519$/
264
264
  Net::SSH::Buffer.from(:string, priv_key.public_key.verify_key.to_bytes,
265
- :string, priv_key.sign_key.keypair).to_s
265
+ :string, priv_key.sign_key.keypair).to_s
266
266
  when /^ssh-ed25519-cert-v01@openssh\.com$/
267
267
  # Unlike the other certificate types, the public key is included after the certifiate.
268
268
  Net::SSH::Buffer.from(:string, priv_key.to_blob,
269
- :string, priv_key.key.public_key.verify_key.to_bytes,
270
- :string, priv_key.key.sign_key.keypair).to_s
269
+ :string, priv_key.key.public_key.verify_key.to_bytes,
270
+ :string, priv_key.key.sign_key.keypair).to_s
271
271
  when /^ssh-rsa$/
272
272
  # `n` and `e` are reversed compared to the ordering in `OpenSSL::PKey::RSA#to_blob`.
273
273
  Net::SSH::Buffer.from(:bignum, priv_key.n, :bignum, priv_key.e, :bignum, priv_key.d,
274
- :bignum, priv_key.iqmp, :bignum, priv_key.p, :bignum, priv_key.q).to_s
274
+ :bignum, priv_key.iqmp, :bignum, priv_key.p, :bignum, priv_key.q).to_s
275
275
  when /^ssh-rsa-cert-v01@openssh\.com$/
276
276
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.d,
277
- :bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
278
- :bignum, priv_key.key.q).to_s
277
+ :bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
278
+ :bignum, priv_key.key.q).to_s
279
279
  end
280
280
  end
281
281
  end
@@ -66,8 +66,8 @@ module Net
66
66
  ).to_s
67
67
  end
68
68
 
69
- def ssh_do_sign(data)
70
- key.ssh_do_sign(data)
69
+ def ssh_do_sign(data, sig_alg = nil)
70
+ key.ssh_do_sign(data, sig_alg)
71
71
  end
72
72
 
73
73
  def ssh_do_verify(sig, data, options = {})
@@ -83,7 +83,7 @@ module Net
83
83
  end
84
84
 
85
85
  # Signs the certificate with key.
86
- def sign!(key, sign_nonce=nil)
86
+ def sign!(key, sign_nonce = nil)
87
87
  # ssh-keygen uses 32 bytes of nonce.
88
88
  self.nonce = sign_nonce || SecureRandom.random_bytes(32)
89
89
  self.signature_key = key
@@ -94,7 +94,7 @@ module Net
94
94
  self
95
95
  end
96
96
 
97
- def sign(key, sign_nonce=nil)
97
+ def sign(key, sign_nonce = nil)
98
98
  cert = clone
99
99
  cert.sign!(key, sign_nonce)
100
100
  end
@@ -14,7 +14,7 @@ module Net
14
14
  module Authentication
15
15
  module ED25519
16
16
  class SigningKeyFromFile < SimpleDelegator
17
- def initialize(pk,sk)
17
+ def initialize(pk, sk)
18
18
  key = ::Ed25519::SigningKey.from_keypair(sk)
19
19
  raise ArgumentError, "pk does not match sk" unless pk == key.verify_key.to_bytes
20
20
 
@@ -116,7 +116,7 @@ module Net
116
116
  end
117
117
 
118
118
  def to_blob
119
- Net::SSH::Buffer.from(:mstring,"ssh-ed25519".dup,:string,@verify_key.to_bytes).to_s
119
+ Net::SSH::Buffer.from(:mstring, "ssh-ed25519".dup, :string, @verify_key.to_bytes).to_s
120
120
  end
121
121
 
122
122
  def ssh_type
@@ -128,7 +128,7 @@ module Net
128
128
  end
129
129
 
130
130
  def ssh_do_verify(sig, data, options = {})
131
- @verify_key.verify(sig,data)
131
+ @verify_key.verify(sig, data)
132
132
  end
133
133
 
134
134
  def to_pem
@@ -152,7 +152,7 @@ module Net
152
152
  _comment = buffer.read_string
153
153
 
154
154
  @pk = pk
155
- @sign_key = SigningKeyFromFile.new(pk,sk)
155
+ @sign_key = SigningKeyFromFile.new(pk, sk)
156
156
  end
157
157
 
158
158
  def to_blob
@@ -171,7 +171,7 @@ module Net
171
171
  PubKey.new(@pk)
172
172
  end
173
173
 
174
- def ssh_do_sign(data)
174
+ def ssh_do_sign(data, sig_alg = nil)
175
175
  @sign_key.sign(data)
176
176
  end
177
177
 
@@ -41,7 +41,7 @@ module Net
41
41
  # Create a new KeyManager. By default, the manager will
42
42
  # use the ssh-agent if it is running and the `:use_agent` option
43
43
  # is not false.
44
- def initialize(logger, options={})
44
+ def initialize(logger, options = {})
45
45
  self.logger = logger
46
46
  @key_files = []
47
47
  @key_data = []
@@ -158,7 +158,7 @@ module Net
158
158
  # Regardless of the identity's origin or who does the signing, this
159
159
  # will always return the signature in an SSH2-specified "signature
160
160
  # blob" format.
161
- def sign(identity, data)
161
+ def sign(identity, data, sig_alg = nil)
162
162
  info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
163
163
 
164
164
  if info[:key].nil? && info[:from] == :file
@@ -170,14 +170,27 @@ module Net
170
170
  end
171
171
 
172
172
  if info[:key]
173
- return Net::SSH::Buffer.from(:string, identity.ssh_signature_type,
174
- :mstring, info[:key].ssh_do_sign(data.to_s)).to_s
173
+ if sig_alg.nil?
174
+ signed = info[:key].ssh_do_sign(data.to_s)
175
+ sig_alg = identity.ssh_signature_type
176
+ else
177
+ signed = info[:key].ssh_do_sign(data.to_s, sig_alg)
178
+ end
179
+ return Net::SSH::Buffer.from(:string, sig_alg,
180
+ :mstring, signed).to_s
175
181
  end
176
182
 
177
183
  if info[:from] == :agent
178
184
  raise KeyManagerError, "the agent is no longer available" unless agent
179
185
 
180
- return agent.sign(info[:identity], data.to_s)
186
+ case sig_alg
187
+ when "rsa-sha2-512"
188
+ return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_512)
189
+ when "rsa-sha2-256"
190
+ return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_256)
191
+ else
192
+ return agent.sign(info[:identity], data.to_s)
193
+ end
181
194
  end
182
195
 
183
196
  raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
@@ -20,12 +20,22 @@ module Net
20
20
  # this.
21
21
  attr_reader :key_manager
22
22
 
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
27
+
23
28
  # Instantiates a new authentication method.
24
- def initialize(session, options={})
29
+ def initialize(session, options = {})
25
30
  @session = session
26
31
  @key_manager = options[:key_manager]
27
32
  @options = options
28
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]
29
39
  self.logger = session.logger
30
40
  end
31
41
 
@@ -46,7 +56,7 @@ module Net
46
56
  # of the packet. The new packet is returned, ready for sending.
47
57
  def userauth_request(username, next_service, auth_method, *others)
48
58
  buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
49
- :string, username, :string, next_service, :string, auth_method)
59
+ :string, username, :string, next_service, :string, auth_method)
50
60
 
51
61
  others.each do |value|
52
62
  case value
@@ -10,12 +10,12 @@ module Net
10
10
 
11
11
  # Attempts to perform host-based authorization of the user by trying
12
12
  # all known keys.
13
- def authenticate(next_service, username, password=nil)
13
+ def authenticate(next_service, username, password = nil)
14
14
  return false unless key_manager
15
15
 
16
16
  key_manager.each_identity do |identity|
17
17
  return true if authenticate_with(identity, next_service,
18
- username, key_manager)
18
+ username, key_manager)
19
19
  end
20
20
 
21
21
  return false
@@ -63,7 +63,7 @@ module Net
63
63
  # Build the "core" hostbased request string.
64
64
  def build_request(identity, next_service, username, hostname, client_username)
65
65
  userauth_request(username, next_service, "hostbased", identity.ssh_type,
66
- Buffer.from(:key, identity).to_s, hostname, client_username).to_s
66
+ Buffer.from(:key, identity).to_s, hostname, client_username).to_s
67
67
  end
68
68
  end
69
69
  end
@@ -11,7 +11,7 @@ module Net
11
11
  USERAUTH_INFO_RESPONSE = 61
12
12
 
13
13
  # Attempt to authenticate the given user for the given service.
14
- def authenticate(next_service, username, password=nil)
14
+ def authenticate(next_service, username, password = nil)
15
15
  debug { "trying keyboard-interactive" }
16
16
  send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
17
17
 
@@ -8,7 +8,7 @@ module Net
8
8
  # Implements the "none" SSH authentication method.
9
9
  class None < Abstract
10
10
  # Attempt to authenticate as "none"
11
- def authenticate(next_service, user="", password="")
11
+ def authenticate(next_service, user = "", password = "")
12
12
  send_message(userauth_request(user, next_service, "none"))
13
13
  message = session.next_message
14
14
 
@@ -10,7 +10,7 @@ module Net
10
10
  class Password < Abstract
11
11
  # Attempt to authenticate the given user for the given service. If
12
12
  # the password parameter is nil, this will ask for password
13
- def authenticate(next_service, username, password=nil)
13
+ def authenticate(next_service, username, password = nil)
14
14
  clear_prompter!
15
15
  retries = 0
16
16
  max_retries = get_max_retries
@@ -12,7 +12,7 @@ module Net
12
12
  # username, trying each identity known to the key manager. If any of
13
13
  # them succeed, returns +true+, otherwise returns +false+. This
14
14
  # requires the presence of a key manager.
15
- def authenticate(next_service, username, password=nil)
15
+ def authenticate(next_service, username, password = nil)
16
16
  return false unless key_manager
17
17
 
18
18
  key_manager.each_identity do |identity|
@@ -26,41 +26,40 @@ module Net
26
26
 
27
27
  # Builds a packet that contains the request formatted for sending
28
28
  # a public-key request to the server.
29
- def build_request(pub_key, username, next_service, has_sig)
29
+ def build_request(pub_key, username, next_service, alg, has_sig)
30
30
  blob = Net::SSH::Buffer.new
31
31
  blob.write_key pub_key
32
32
 
33
33
  userauth_request(username, next_service, "publickey", has_sig,
34
- pub_key.ssh_type, blob.to_s)
34
+ alg, blob.to_s)
35
35
  end
36
36
 
37
37
  # Builds and sends a request formatted for a public-key
38
38
  # authentication request.
39
- def send_request(pub_key, username, next_service, signature=nil)
40
- msg = build_request(pub_key, username, next_service, !signature.nil?)
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?)
41
42
  msg.write_string(signature) if signature
42
43
  send_message(msg)
43
44
  end
44
45
 
45
- # Attempts to perform public-key authentication for the given
46
- # username, with the given identity (public key). Returns +true+ if
47
- # successful, or +false+ otherwise.
48
- def authenticate_with(identity, next_service, username)
46
+ def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil)
49
47
  debug { "trying publickey (#{identity.fingerprint})" }
50
- send_request(identity, username, next_service)
48
+ send_request(identity, username, next_service, alg)
51
49
 
52
50
  message = session.next_message
53
51
 
54
52
  case message.type
55
53
  when USERAUTH_PK_OK
56
- buffer = build_request(identity, username, next_service, true)
54
+ buffer = build_request(identity, username, next_service, alg,
55
+ true)
57
56
  sig_data = Net::SSH::Buffer.new
58
57
  sig_data.write_string(session_id)
59
58
  sig_data.append(buffer.to_s)
60
59
 
61
- sig_blob = key_manager.sign(identity, sig_data)
60
+ sig_blob = key_manager.sign(identity, sig_data, sig_alg)
62
61
 
63
- send_request(identity, username, next_service, sig_blob.to_s)
62
+ send_request(identity, username, next_service, alg, sig_blob.to_s)
64
63
  message = session.next_message
65
64
 
66
65
  case message.type
@@ -76,7 +75,7 @@ module Net
76
75
  return false
77
76
  else
78
77
  raise Net::SSH::Exception,
79
- "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
78
+ "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
80
79
  end
81
80
 
82
81
  when USERAUTH_FAILURE
@@ -88,6 +87,49 @@ module Net
88
87
  raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
89
88
  end
90
89
  end
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
134
  end
93
135
  end
@@ -50,13 +50,13 @@ module Net
50
50
  SIZEOF_DWORD = DL.sizeof('L')
51
51
  elsif RUBY_VERSION < "2.1"
52
52
  extend DL::Importer
53
- dlload 'user32.dll','kernel32.dll', 'advapi32.dll'
53
+ dlload 'user32.dll', 'kernel32.dll', 'advapi32.dll'
54
54
  include DL::Win32Types
55
55
 
56
56
  SIZEOF_DWORD = DL::SIZEOF_LONG
57
57
  else
58
58
  extend Fiddle::Importer
59
- dlload 'user32.dll','kernel32.dll', 'advapi32.dll'
59
+ dlload 'user32.dll', 'kernel32.dll', 'advapi32.dll'
60
60
  include Fiddle::Win32Types
61
61
  SIZEOF_DWORD = Fiddle::SIZEOF_LONG
62
62
  end
@@ -240,7 +240,7 @@ module Net
240
240
  end
241
241
 
242
242
  def self.set_ptr_data(ptr, data)
243
- DL::CPtr.new(ptr)[0,data.size] = data
243
+ DL::CPtr.new(ptr)[0, data.size] = data
244
244
  end
245
245
  end
246
246
 
@@ -281,7 +281,7 @@ module Net
281
281
 
282
282
  def self.ptr_to_dword(ptr)
283
283
  first = ptr.ptr.to_i
284
- second = ptr_to_s(ptr,Win::SIZEOF_DWORD).unpack('L')[0]
284
+ second = ptr_to_s(ptr, Win::SIZEOF_DWORD).unpack('L')[0]
285
285
  raise "Error" unless first == second
286
286
 
287
287
  first
@@ -296,7 +296,7 @@ module Net
296
296
  end
297
297
 
298
298
  def self.get_sid(user)
299
- ptr_to_s(user.to_ptr.ptr,Win::SIZEOF_DWORD).unpack('L')[0]
299
+ ptr_to_s(user.to_ptr.ptr, Win::SIZEOF_DWORD).unpack('L')[0]
300
300
  end
301
301
 
302
302
  def self.get_sid_ptr(user)
@@ -332,7 +332,7 @@ module Net
332
332
  token_handle = open_process_token(Win.GetCurrentProcess,
333
333
  Win::TOKEN_QUERY)
334
334
  token_user = get_token_information(token_handle,
335
- Win::TOKEN_USER_INFORMATION_CLASS)
335
+ Win::TOKEN_USER_INFORMATION_CLASS)
336
336
  return token_user
337
337
  end
338
338
 
@@ -404,7 +404,7 @@ module Net
404
404
 
405
405
  if @win.to_i == 0
406
406
  raise Net::SSH::Exception,
407
- "pageant process not running"
407
+ "pageant process not running"
408
408
  end
409
409
 
410
410
  @input_buffer = Net::SSH::Buffer.new
@@ -458,7 +458,7 @@ module Net
458
458
 
459
459
  if filemap == 0 || filemap == Win::INVALID_HANDLE_VALUE
460
460
  raise Net::SSH::Exception,
461
- "Creation of file mapping failed with error: #{Win.GetLastError}"
461
+ "Creation of file mapping failed with error: #{Win.GetLastError}"
462
462
  end
463
463
 
464
464
  ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
@@ -22,12 +22,12 @@ module Net
22
22
  # returned by OpenSSH's <tt>`ssh-add -l -E SHA256`</tt>, i.e.,
23
23
  # trailing base64 padding '=' characters are stripped and the
24
24
  # literal string +SHA256:+ is prepended.
25
- def fingerprint(algorithm='MD5')
25
+ def fingerprint(algorithm = 'MD5')
26
26
  @fingerprint ||= {}
27
27
  @fingerprint[algorithm] ||= PubKeyFingerprint.fingerprint(to_blob, algorithm)
28
28
  end
29
29
 
30
- def self.fingerprint(blob, algorithm='MD5')
30
+ def self.fingerprint(blob, algorithm = 'MD5')
31
31
  case algorithm.to_s.upcase
32
32
  when 'MD5'
33
33
  OpenSSL::Digest.hexdigest(algorithm, blob).scan(/../).join(":")
@@ -41,7 +41,7 @@ module Net
41
41
 
42
42
  # Instantiates a new Authentication::Session object over the given
43
43
  # transport layer abstraction.
44
- def initialize(transport, options={})
44
+ def initialize(transport, options = {})
45
45
  self.logger = transport.logger
46
46
  @transport = transport
47
47
 
@@ -54,7 +54,7 @@ module Net
54
54
  # Attempts to authenticate the given user, in preparation for the next
55
55
  # service request. Returns true if an authentication method succeeds in
56
56
  # authenticating the user, and false otherwise.
57
- def authenticate(next_service, username, password=nil)
57
+ def authenticate(next_service, username, password = nil)
58
58
  debug { "beginning authentication of `#{username}'" }
59
59
 
60
60
  transport.send_message(transport.service_request("ssh-userauth"))
@@ -76,7 +76,9 @@ module Net
76
76
  debug { "trying #{name}" }
77
77
  begin
78
78
  auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
79
- method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
79
+ method = auth_class.new(self,
80
+ key_manager: key_manager, password_prompt: options[:password_prompt],
81
+ pubkey_algorithms: options[:pubkey_algorithms] || nil)
80
82
  rescue NameError
81
83
  debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
82
84
  next