net-ssh 6.2.0.rc2 → 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 (105) 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 +22 -11
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.rubocop.yml +12 -1
  9. data/.rubocop_todo.yml +470 -262
  10. data/CHANGES.txt +6 -0
  11. data/Dockerfile +27 -0
  12. data/Dockerfile.openssl3 +17 -0
  13. data/Gemfile +2 -0
  14. data/Gemfile.noed25519 +2 -0
  15. data/README.md +9 -3
  16. data/Rakefile +5 -0
  17. data/docker-compose.yml +23 -0
  18. data/lib/net/ssh/authentication/agent.rb +17 -15
  19. data/lib/net/ssh/authentication/certificate.rb +7 -5
  20. data/lib/net/ssh/authentication/constants.rb +0 -1
  21. data/lib/net/ssh/authentication/ed25519.rb +10 -6
  22. data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
  23. data/lib/net/ssh/authentication/key_manager.rb +46 -34
  24. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  25. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  26. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
  27. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  28. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  29. data/lib/net/ssh/authentication/methods/publickey.rb +56 -16
  30. data/lib/net/ssh/authentication/pageant.rb +97 -97
  31. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -2
  32. data/lib/net/ssh/authentication/session.rb +18 -17
  33. data/lib/net/ssh/buffer.rb +50 -30
  34. data/lib/net/ssh/buffered_io.rb +24 -25
  35. data/lib/net/ssh/config.rb +33 -20
  36. data/lib/net/ssh/connection/channel.rb +84 -83
  37. data/lib/net/ssh/connection/constants.rb +0 -4
  38. data/lib/net/ssh/connection/event_loop.rb +30 -24
  39. data/lib/net/ssh/connection/keepalive.rb +12 -12
  40. data/lib/net/ssh/connection/session.rb +108 -107
  41. data/lib/net/ssh/connection/term.rb +56 -58
  42. data/lib/net/ssh/errors.rb +12 -12
  43. data/lib/net/ssh/key_factory.rb +7 -8
  44. data/lib/net/ssh/known_hosts.rb +84 -15
  45. data/lib/net/ssh/loggable.rb +8 -9
  46. data/lib/net/ssh/packet.rb +1 -1
  47. data/lib/net/ssh/prompt.rb +9 -11
  48. data/lib/net/ssh/proxy/command.rb +1 -1
  49. data/lib/net/ssh/proxy/errors.rb +2 -4
  50. data/lib/net/ssh/proxy/http.rb +18 -20
  51. data/lib/net/ssh/proxy/https.rb +8 -10
  52. data/lib/net/ssh/proxy/jump.rb +8 -10
  53. data/lib/net/ssh/proxy/socks4.rb +2 -4
  54. data/lib/net/ssh/proxy/socks5.rb +3 -5
  55. data/lib/net/ssh/service/forward.rb +7 -7
  56. data/lib/net/ssh/test/channel.rb +23 -25
  57. data/lib/net/ssh/test/extensions.rb +35 -35
  58. data/lib/net/ssh/test/kex.rb +6 -8
  59. data/lib/net/ssh/test/local_packet.rb +0 -2
  60. data/lib/net/ssh/test/packet.rb +3 -3
  61. data/lib/net/ssh/test/remote_packet.rb +5 -7
  62. data/lib/net/ssh/test/script.rb +24 -26
  63. data/lib/net/ssh/test/socket.rb +12 -15
  64. data/lib/net/ssh/test.rb +4 -5
  65. data/lib/net/ssh/transport/algorithms.rb +14 -13
  66. data/lib/net/ssh/transport/cipher_factory.rb +28 -28
  67. data/lib/net/ssh/transport/constants.rb +3 -3
  68. data/lib/net/ssh/transport/ctr.rb +7 -7
  69. data/lib/net/ssh/transport/hmac/abstract.rb +4 -5
  70. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  71. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  72. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  73. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  76. data/lib/net/ssh/transport/hmac.rb +12 -12
  77. data/lib/net/ssh/transport/identity_cipher.rb +11 -13
  78. data/lib/net/ssh/transport/kex/abstract.rb +3 -3
  79. data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
  80. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
  81. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
  82. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  83. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
  84. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
  85. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
  86. data/lib/net/ssh/transport/kex.rb +8 -6
  87. data/lib/net/ssh/transport/key_expander.rb +7 -8
  88. data/lib/net/ssh/transport/openssl.rb +38 -22
  89. data/lib/net/ssh/transport/packet_stream.rb +2 -3
  90. data/lib/net/ssh/transport/server_version.rb +17 -16
  91. data/lib/net/ssh/transport/session.rb +9 -7
  92. data/lib/net/ssh/transport/state.rb +43 -43
  93. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  94. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  95. data/lib/net/ssh/verifiers/always.rb +6 -4
  96. data/lib/net/ssh/verifiers/never.rb +0 -2
  97. data/lib/net/ssh/version.rb +4 -4
  98. data/lib/net/ssh.rb +4 -5
  99. data/net-ssh-public_cert.pem +8 -8
  100. data/net-ssh.gemspec +2 -2
  101. data/support/ssh_tunnel_bug.rb +3 -3
  102. data.tar.gz.sig +0 -0
  103. metadata +24 -17
  104. metadata.gz.sig +0 -0
  105. data/.travis.yml +0 -52
data/CHANGES.txt CHANGED
@@ -1,3 +1,9 @@
1
+ === 6.3.0 beta1
2
+
3
+ * Support cert based host key auth, fix asterisk in known_hosts [#833]
4
+ * Support kex dh-group14-sha256 [#795]
5
+ * Fix StrictHostKeyChecking ssh config parameter translation [#765]
6
+
1
7
  === 6.2.0 rc1
2
8
 
3
9
  === 6.2.0 beta1
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/Gemfile CHANGED
@@ -9,3 +9,5 @@ if ENV["CI"]
9
9
  gem 'codecov', require: false, group: :test
10
10
  gem 'simplecov', require: false, group: :test
11
11
  end
12
+
13
+ gem 'webrick', group: %i[development test] if RUBY_VERSION.split(".")[0].to_i >= 3
data/Gemfile.noed25519 CHANGED
@@ -8,3 +8,5 @@ if ENV["CI"] && !Gem.win_platform?
8
8
  gem 'simplecov', require: false, group: :test
9
9
  gem 'codecov', require: false, group: :test
10
10
  end
11
+
12
+ gem 'webrick', group: %i[development test] if RUBY_VERSION.split(".")[0].to_i >= 3
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/net-ssh.svg)](https://badge.fury.io/rb/net-ssh)
2
2
  [![Join the chat at https://gitter.im/net-ssh/net-ssh](https://badges.gitter.im/net-ssh/net-ssh.svg)](https://gitter.im/net-ssh/net-ssh?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
3
- [![Build Status](https://travis-ci.org/net-ssh/net-ssh.svg?branch=master)](https://travis-ci.org/net-ssh/net-ssh)
3
+ [![Build status](https://github.com/net-ssh/net-ssh/actions/workflows/ci.yml/badge.svg)](https://github.com/net-ssh/net-ssh/actions/workflows/ci.yml)
4
4
  [![Coverage status](https://codecov.io/gh/net-ssh/net-ssh/branch/master/graph/badge.svg)](https://codecov.io/gh/net-ssh/net-ssh)
5
5
  [![Backers on Open Collective](https://opencollective.com/net-ssh/backers/badge.svg)](#backers])
6
6
  [![Sponsors on Open Collective](https://opencollective.com/net-ssh/sponsors/badge.svg)](#sponsors)
7
7
 
8
8
  # Net::SSH 6.x
9
9
 
10
- * Docs: http://net-ssh.github.com/net-ssh
10
+ * Docs: http://net-ssh.github.io/net-ssh
11
11
  * Issues: https://github.com/net-ssh/net-ssh/issues
12
12
  * Codes: https://github.com/net-ssh/net-ssh
13
13
  * Email: net-ssh@solutious.com
@@ -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
@@ -48,6 +48,7 @@ namespace :cert do
48
48
  raw = File.read "net-ssh-public_cert.pem"
49
49
  certificate = OpenSSL::X509::Certificate.new raw
50
50
  raise Exception, "Not yet expired: #{certificate.not_after}" unless certificate.not_after < Time.now
51
+
51
52
  sh "gem cert --build netssh@solutious.com --days 365*5 --private-key /mnt/gem/net-ssh-private_key.pem"
52
53
  sh "mv gem-public_cert.pem net-ssh-public_cert.pem"
53
54
  sh "gem cert --add net-ssh-public_cert.pem"
@@ -94,6 +95,10 @@ Rake::TestTask.new do |t|
94
95
  t.test_files = test_files
95
96
  end
96
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
+
97
102
  desc "Run tests of Net::SSH:Test"
98
103
  Rake::TestTask.new do |t|
99
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
@@ -13,6 +13,7 @@ module Net
13
13
  module Authentication
14
14
  # Class for representing agent-specific errors.
15
15
  class AgentError < Net::SSH::Exception; end
16
+
16
17
  # An exception for indicating that the SSH agent is not available.
17
18
  class AgentNotAvailable < AgentError; end
18
19
 
@@ -64,7 +65,7 @@ module Net
64
65
 
65
66
  # Instantiates a new agent object, connects to a running SSH agent,
66
67
  # negotiates the agent protocol version, and returns the agent object.
67
- 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)
68
69
  agent = new(logger)
69
70
  agent.connect!(agent_socket_factory, identity_agent)
70
71
  agent.negotiate!
@@ -73,7 +74,7 @@ module Net
73
74
 
74
75
  # Creates a new Agent object, using the optional logger instance to
75
76
  # report status.
76
- def initialize(logger=nil)
77
+ def initialize(logger = nil)
77
78
  self.logger = logger
78
79
  end
79
80
 
@@ -87,9 +88,9 @@ module Net
87
88
  if agent_socket_factory
88
89
  agent_socket_factory.call
89
90
  elsif identity_agent
90
- unix_socket_class.open(identity_agent)
91
+ unix_socket_class.open(File.expand_path(identity_agent))
91
92
  elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class
92
- unix_socket_class.open(ENV['SSH_AUTH_SOCK'])
93
+ unix_socket_class.open(File.expand_path(ENV['SSH_AUTH_SOCK']))
93
94
  elsif Gem.win_platform? && RUBY_ENGINE != "jruby"
94
95
  Pageant::Socket.open
95
96
  else
@@ -107,6 +108,7 @@ module Net
107
108
  type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
108
109
 
109
110
  raise AgentNotAvailable, "SSH2 agents are not yet supported" if type == SSH2_AGENT_VERSION_RESPONSE
111
+
110
112
  if type == SSH2_AGENT_FAILURE
111
113
  debug { "Unexpected response type==#{type}, this will be ignored" }
112
114
  elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
@@ -175,7 +177,7 @@ module Net
175
177
 
176
178
  req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED
177
179
  type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key),
178
- :string, comment, :raw, constraints)
180
+ :string, comment, :raw, constraints)
179
181
  raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS
180
182
  end
181
183
 
@@ -196,13 +198,13 @@ module Net
196
198
  type, = send_and_wait(SSH2_AGENT_LOCK, :string, password)
197
199
  raise AgentError, "could not lock agent" if type != SSH_AGENT_SUCCESS
198
200
  end
199
-
201
+
200
202
  # unlock the ssh agent with password
201
203
  def unlock(password)
202
204
  type, = send_and_wait(SSH2_AGENT_UNLOCK, :string, password)
203
205
  raise AgentError, "could not unlock agent" if type != SSH_AGENT_SUCCESS
204
206
  end
205
-
207
+
206
208
  private
207
209
 
208
210
  def unix_socket_class
@@ -249,31 +251,31 @@ module Net
249
251
  case priv_key.ssh_type
250
252
  when /^ssh-dss$/
251
253
  Net::SSH::Buffer.from(:bignum, priv_key.p, :bignum, priv_key.q, :bignum, priv_key.g,
252
- :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
253
255
  when /^ssh-dss-cert-v01@openssh\.com$/
254
256
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.priv_key).to_s
255
257
  when /^ecdsa\-sha2\-(\w*)$/
256
258
  curve_name = OpenSSL::PKey::EC::CurveNameAliasInv[priv_key.group.curve_name]
257
259
  Net::SSH::Buffer.from(:string, curve_name, :mstring, priv_key.public_key.to_bn.to_s(2),
258
- :bignum, priv_key.private_key).to_s
260
+ :bignum, priv_key.private_key).to_s
259
261
  when /^ecdsa\-sha2\-(\w*)-cert-v01@openssh\.com$/
260
262
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.private_key).to_s
261
263
  when /^ssh-ed25519$/
262
264
  Net::SSH::Buffer.from(:string, priv_key.public_key.verify_key.to_bytes,
263
- :string, priv_key.sign_key.keypair).to_s
265
+ :string, priv_key.sign_key.keypair).to_s
264
266
  when /^ssh-ed25519-cert-v01@openssh\.com$/
265
267
  # Unlike the other certificate types, the public key is included after the certifiate.
266
268
  Net::SSH::Buffer.from(:string, priv_key.to_blob,
267
- :string, priv_key.key.public_key.verify_key.to_bytes,
268
- :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
269
271
  when /^ssh-rsa$/
270
272
  # `n` and `e` are reversed compared to the ordering in `OpenSSL::PKey::RSA#to_blob`.
271
273
  Net::SSH::Buffer.from(:bignum, priv_key.n, :bignum, priv_key.e, :bignum, priv_key.d,
272
- :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
273
275
  when /^ssh-rsa-cert-v01@openssh\.com$/
274
276
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.d,
275
- :bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
276
- :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
277
279
  end
278
280
  end
279
281
  end
@@ -31,7 +31,7 @@ module Net
31
31
  cert.key_id = buffer.read_string
32
32
  cert.valid_principals = buffer.read_buffer.read_all(&:read_string)
33
33
  cert.valid_after = Time.at(buffer.read_int64)
34
-
34
+
35
35
  cert.valid_before = if RUBY_PLATFORM == "java"
36
36
  # 0x20c49ba5e353f7 = 0x7fffffffffffffff/1000, the largest value possible for JRuby
37
37
  # JRuby Time.at multiplies the arg by 1000, and then stores it in a signed long.
@@ -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
@@ -125,6 +125,7 @@ module Net
125
125
  def self.type_symbol(type)
126
126
  types = { 1 => :user, 2 => :host }
127
127
  raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
128
+
128
129
  types.fetch(type)
129
130
  end
130
131
  private_class_method :type_symbol
@@ -134,6 +135,7 @@ module Net
134
135
  def type_value(type)
135
136
  types = { user: 1, host: 2 }
136
137
  raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
138
+
137
139
  types.fetch(type)
138
140
  end
139
141
 
@@ -1,7 +1,6 @@
1
1
  module Net
2
2
  module SSH
3
3
  module Authentication
4
-
5
4
  # Describes the constants used by the Net::SSH::Authentication components
6
5
  # of the Net::SSH library. Individual authentication method implemenations
7
6
  # may define yet more constants that are specific to their implementation.
@@ -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
 
@@ -44,9 +44,11 @@ module Net
44
44
  datafull = datafull.strip
45
45
  raise ArgumentError.new("Expected #{MBEGIN} at start of private key") unless datafull.start_with?(MBEGIN)
46
46
  raise ArgumentError.new("Expected #{MEND} at end of private key") unless datafull.end_with?(MEND)
47
+
47
48
  datab64 = datafull[MBEGIN.size...-MEND.size]
48
49
  data = Base64.decode64(datab64)
49
50
  raise ArgumentError.new("Expected #{MAGIC} at start of decoded private key") unless data.start_with?(MAGIC)
51
+
50
52
  buffer = Net::SSH::Buffer.new(data[MAGIC.size + 1..-1])
51
53
 
52
54
  ciphername = buffer.read_string
@@ -59,6 +61,7 @@ module Net
59
61
  kdfopts = Net::SSH::Buffer.new(buffer.read_string)
60
62
  num_keys = buffer.read_long
61
63
  raise ArgumentError.new("Only 1 key is supported in ssh keys #{num_keys} was in private key") unless num_keys == 1
64
+
62
65
  _pubkey = buffer.read_string
63
66
 
64
67
  len = buffer.read_long
@@ -72,12 +75,13 @@ module Net
72
75
  rounds = kdfopts.read_long
73
76
 
74
77
  raise "BCryptPbkdf is not implemented for jruby" if RUBY_PLATFORM == "java"
78
+
75
79
  key = BCryptPbkdf::key(password, salt, keylen + ivlen, rounds)
76
80
  else
77
81
  key = '\x00' * (keylen + ivlen)
78
82
  end
79
83
 
80
- cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv:key[keylen...keylen + ivlen], decrypt: true)
84
+ cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv: key[keylen...keylen + ivlen], decrypt: true)
81
85
 
82
86
  decoded = cipher.update(buffer.remainder_as_buffer.to_s)
83
87
  decoded << cipher.final
@@ -112,7 +116,7 @@ module Net
112
116
  end
113
117
 
114
118
  def to_blob
115
- Net::SSH::Buffer.from(:mstring,"ssh-ed25519",:string,@verify_key.to_bytes).to_s
119
+ Net::SSH::Buffer.from(:mstring, "ssh-ed25519".dup, :string, @verify_key.to_bytes).to_s
116
120
  end
117
121
 
118
122
  def ssh_type
@@ -124,7 +128,7 @@ module Net
124
128
  end
125
129
 
126
130
  def ssh_do_verify(sig, data, options = {})
127
- @verify_key.verify(sig,data)
131
+ @verify_key.verify(sig, data)
128
132
  end
129
133
 
130
134
  def to_pem
@@ -148,7 +152,7 @@ module Net
148
152
  _comment = buffer.read_string
149
153
 
150
154
  @pk = pk
151
- @sign_key = SigningKeyFromFile.new(pk,sk)
155
+ @sign_key = SigningKeyFromFile.new(pk, sk)
152
156
  end
153
157
 
154
158
  def to_blob
@@ -167,7 +171,7 @@ module Net
167
171
  PubKey.new(@pk)
168
172
  end
169
173
 
170
- def ssh_do_sign(data)
174
+ def ssh_do_sign(data, sig_alg = nil)
171
175
  @sign_key.sign(data)
172
176
  end
173
177
 
@@ -1,11 +1,9 @@
1
- module Net
2
- module SSH
1
+ module Net
2
+ module SSH
3
3
  module Authentication
4
-
5
4
  # Loads ED25519 support which requires optinal dependecies like
6
5
  # ed25519, bcrypt_pbkdf
7
6
  module ED25519Loader
8
-
9
7
  begin
10
8
  require 'net/ssh/authentication/ed25519'
11
9
  LOADED = true
@@ -14,20 +12,19 @@ module Net
14
12
  ERROR = e
15
13
  LOADED = false
16
14
  end
17
-
15
+
18
16
  def self.raiseUnlessLoaded(message)
19
17
  description = ERROR.is_a?(LoadError) ? dependenciesRequiredForED25519 : ''
20
18
  description << "#{ERROR.class} : \"#{ERROR.message}\"\n" if ERROR
21
19
  raise NotImplementedError, "#{message}\n#{description}" unless LOADED
22
20
  end
23
-
21
+
24
22
  def self.dependenciesRequiredForED25519
25
23
  result = "net-ssh requires the following gems for ed25519 support:\n"
26
24
  result << " * ed25519 (>= 1.2, < 2.0)\n"
27
25
  result << " * bcrypt_pbkdf (>= 1.0, < 2.0)\n" unless RUBY_PLATFORM == "java"
28
26
  result << "See https://github.com/net-ssh/net-ssh/issues/565 for more information\n"
29
27
  end
30
-
31
28
  end
32
29
  end
33
30
  end
@@ -6,7 +6,6 @@ require 'net/ssh/authentication/agent'
6
6
  module Net
7
7
  module SSH
8
8
  module Authentication
9
-
10
9
  # A trivial exception class used to report errors in the key manager.
11
10
  class KeyManagerError < Net::SSH::Exception; end
12
11
 
@@ -42,7 +41,7 @@ module Net
42
41
  # Create a new KeyManager. By default, the manager will
43
42
  # use the ssh-agent if it is running and the `:use_agent` option
44
43
  # is not false.
45
- def initialize(logger, options={})
44
+ def initialize(logger, options = {})
46
45
  self.logger = logger
47
46
  @key_files = []
48
47
  @key_data = []
@@ -159,7 +158,7 @@ module Net
159
158
  # Regardless of the identity's origin or who does the signing, this
160
159
  # will always return the signature in an SSH2-specified "signature
161
160
  # blob" format.
162
- def sign(identity, data)
161
+ def sign(identity, data, sig_alg = nil)
163
162
  info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
164
163
 
165
164
  if info[:key].nil? && info[:from] == :file
@@ -171,13 +170,27 @@ module Net
171
170
  end
172
171
 
173
172
  if info[:key]
174
- return Net::SSH::Buffer.from(:string, identity.ssh_signature_type,
175
- :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
176
181
  end
177
182
 
178
183
  if info[:from] == :agent
179
184
  raise KeyManagerError, "the agent is no longer available" unless agent
180
- return agent.sign(info[:identity], data.to_s)
185
+
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})"
@@ -201,6 +214,7 @@ module Net
201
214
  # or if the agent is otherwise not available.
202
215
  def agent
203
216
  return unless use_agent?
217
+
204
218
  @agent ||= Agent.connect(logger, options[:agent_socket_factory], options[:identity_agent])
205
219
  rescue AgentNotAvailable
206
220
  @use_agent = false
@@ -248,37 +262,35 @@ module Net
248
262
  # Load prepared identities. Private key decryption errors ignored if ignore_decryption_errors
249
263
  def load_identities(identities, ask_passphrase, ignore_decryption_errors)
250
264
  identities.map do |identity|
251
- begin
252
- case identity[:load_from]
253
- when :pubkey_file
254
- key = KeyFactory.load_public_key(identity[:pubkey_file])
255
- { public_key: key, from: :file, file: identity[:privkey_file] }
256
- when :privkey_file
257
- private_key = KeyFactory.load_private_key(
258
- identity[:privkey_file], options[:passphrase], ask_passphrase, options[:password_prompt]
259
- )
260
- key = private_key.send(:public_key)
261
- { public_key: key, from: :file, file: identity[:privkey_file], key: private_key }
262
- when :data
263
- private_key = KeyFactory.load_data_private_key(
264
- identity[:data], options[:passphrase], ask_passphrase, "<key in memory>", options[:password_prompt]
265
- )
266
- key = private_key.send(:public_key)
267
- { public_key: key, from: :key_data, data: identity[:data], key: private_key }
268
- else
269
- identity
270
- end
271
- rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError, OpenSSL::PKey::PKeyError, ArgumentError => e
272
- if ignore_decryption_errors
273
- identity
274
- else
275
- process_identity_loading_error(identity, e)
276
- nil
277
- end
278
- rescue Exception => e
265
+ case identity[:load_from]
266
+ when :pubkey_file
267
+ key = KeyFactory.load_public_key(identity[:pubkey_file])
268
+ { public_key: key, from: :file, file: identity[:privkey_file] }
269
+ when :privkey_file
270
+ private_key = KeyFactory.load_private_key(
271
+ identity[:privkey_file], options[:passphrase], ask_passphrase, options[:password_prompt]
272
+ )
273
+ key = private_key.send(:public_key)
274
+ { public_key: key, from: :file, file: identity[:privkey_file], key: private_key }
275
+ when :data
276
+ private_key = KeyFactory.load_data_private_key(
277
+ identity[:data], options[:passphrase], ask_passphrase, "<key in memory>", options[:password_prompt]
278
+ )
279
+ key = private_key.send(:public_key)
280
+ { public_key: key, from: :key_data, data: identity[:data], key: private_key }
281
+ else
282
+ identity
283
+ end
284
+ rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError, OpenSSL::PKey::PKeyError, ArgumentError => e
285
+ if ignore_decryption_errors
286
+ identity
287
+ else
279
288
  process_identity_loading_error(identity, e)
280
289
  nil
281
290
  end
291
+ rescue Exception => e
292
+ process_identity_loading_error(identity, e)
293
+ nil
282
294
  end.compact
283
295
  end
284
296
 
@@ -7,7 +7,6 @@ module Net
7
7
  module SSH
8
8
  module Authentication
9
9
  module Methods
10
-
11
10
  # The base class of all user authentication methods. It provides a few
12
11
  # bits of common functionality.
13
12
  class Abstract
@@ -21,12 +20,22 @@ module Net
21
20
  # this.
22
21
  attr_reader :key_manager
23
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
+
24
28
  # Instantiates a new authentication method.
25
- def initialize(session, options={})
29
+ def initialize(session, options = {})
26
30
  @session = session
27
31
  @key_manager = options[:key_manager]
28
32
  @options = options
29
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]
30
39
  self.logger = session.logger
31
40
  end
32
41
 
@@ -47,7 +56,7 @@ module Net
47
56
  # of the packet. The new packet is returned, ready for sending.
48
57
  def userauth_request(username, next_service, auth_method, *others)
49
58
  buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
50
- :string, username, :string, next_service, :string, auth_method)
59
+ :string, username, :string, next_service, :string, auth_method)
51
60
 
52
61
  others.each do |value|
53
62
  case value
@@ -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
@@ -64,10 +63,9 @@ module Net
64
63
  # Build the "core" hostbased request string.
65
64
  def build_request(identity, next_service, username, hostname, client_username)
66
65
  userauth_request(username, next_service, "hostbased", identity.ssh_type,
67
- Buffer.from(:key, identity).to_s, hostname, client_username).to_s
66
+ Buffer.from(:key, identity).to_s, hostname, client_username).to_s
68
67
  end
69
68
  end
70
-
71
69
  end
72
70
  end
73
71
  end