net-ssh 6.1.0 → 7.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -1
  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 +16 -0
  8. data/.gitignore +2 -0
  9. data/.rubocop.yml +12 -1
  10. data/.rubocop_todo.yml +474 -375
  11. data/CHANGES.txt +40 -3
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +2 -0
  15. data/Gemfile.noed25519 +2 -0
  16. data/README.md +14 -4
  17. data/Rakefile +59 -0
  18. data/SECURITY.md +4 -0
  19. data/docker-compose.yml +23 -0
  20. data/lib/net/ssh/authentication/agent.rb +29 -13
  21. data/lib/net/ssh/authentication/certificate.rb +14 -11
  22. data/lib/net/ssh/authentication/constants.rb +0 -1
  23. data/lib/net/ssh/authentication/ed25519.rb +12 -7
  24. data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
  25. data/lib/net/ssh/authentication/key_manager.rb +46 -34
  26. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  27. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  28. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
  29. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  30. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  31. data/lib/net/ssh/authentication/methods/publickey.rb +56 -16
  32. data/lib/net/ssh/authentication/pageant.rb +97 -97
  33. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -2
  34. data/lib/net/ssh/authentication/session.rb +18 -17
  35. data/lib/net/ssh/buffer.rb +71 -51
  36. data/lib/net/ssh/buffered_io.rb +24 -25
  37. data/lib/net/ssh/config.rb +33 -20
  38. data/lib/net/ssh/connection/channel.rb +84 -82
  39. data/lib/net/ssh/connection/constants.rb +0 -4
  40. data/lib/net/ssh/connection/event_loop.rb +30 -24
  41. data/lib/net/ssh/connection/keepalive.rb +12 -12
  42. data/lib/net/ssh/connection/session.rb +109 -108
  43. data/lib/net/ssh/connection/term.rb +56 -58
  44. data/lib/net/ssh/errors.rb +12 -12
  45. data/lib/net/ssh/key_factory.rb +7 -8
  46. data/lib/net/ssh/known_hosts.rb +84 -15
  47. data/lib/net/ssh/loggable.rb +8 -9
  48. data/lib/net/ssh/packet.rb +1 -1
  49. data/lib/net/ssh/prompt.rb +9 -11
  50. data/lib/net/ssh/proxy/command.rb +1 -1
  51. data/lib/net/ssh/proxy/errors.rb +2 -4
  52. data/lib/net/ssh/proxy/http.rb +18 -20
  53. data/lib/net/ssh/proxy/https.rb +8 -10
  54. data/lib/net/ssh/proxy/jump.rb +8 -10
  55. data/lib/net/ssh/proxy/socks4.rb +2 -4
  56. data/lib/net/ssh/proxy/socks5.rb +3 -5
  57. data/lib/net/ssh/service/forward.rb +7 -7
  58. data/lib/net/ssh/test/channel.rb +24 -26
  59. data/lib/net/ssh/test/extensions.rb +35 -35
  60. data/lib/net/ssh/test/kex.rb +6 -8
  61. data/lib/net/ssh/test/local_packet.rb +0 -2
  62. data/lib/net/ssh/test/packet.rb +3 -3
  63. data/lib/net/ssh/test/remote_packet.rb +6 -8
  64. data/lib/net/ssh/test/script.rb +25 -27
  65. data/lib/net/ssh/test/socket.rb +12 -15
  66. data/lib/net/ssh/test.rb +4 -5
  67. data/lib/net/ssh/transport/algorithms.rb +17 -14
  68. data/lib/net/ssh/transport/cipher_factory.rb +28 -28
  69. data/lib/net/ssh/transport/constants.rb +3 -3
  70. data/lib/net/ssh/transport/ctr.rb +7 -7
  71. data/lib/net/ssh/transport/hmac/abstract.rb +4 -5
  72. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  73. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  78. data/lib/net/ssh/transport/hmac.rb +12 -12
  79. data/lib/net/ssh/transport/identity_cipher.rb +11 -13
  80. data/lib/net/ssh/transport/kex/abstract.rb +12 -5
  81. data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
  82. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
  83. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
  84. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  85. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
  86. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
  87. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
  88. data/lib/net/ssh/transport/kex.rb +8 -6
  89. data/lib/net/ssh/transport/key_expander.rb +7 -8
  90. data/lib/net/ssh/transport/openssl.rb +51 -26
  91. data/lib/net/ssh/transport/packet_stream.rb +2 -3
  92. data/lib/net/ssh/transport/server_version.rb +17 -16
  93. data/lib/net/ssh/transport/session.rb +9 -7
  94. data/lib/net/ssh/transport/state.rb +43 -43
  95. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  96. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  97. data/lib/net/ssh/verifiers/always.rb +6 -4
  98. data/lib/net/ssh/verifiers/never.rb +0 -2
  99. data/lib/net/ssh/version.rb +1 -1
  100. data/lib/net/ssh.rb +10 -6
  101. data/net-ssh-public_cert.pem +8 -8
  102. data/net-ssh.gemspec +2 -2
  103. data/support/ssh_tunnel_bug.rb +3 -3
  104. data.tar.gz.sig +0 -0
  105. metadata +24 -15
  106. metadata.gz.sig +0 -0
  107. data/.travis.yml +0 -52
data/CHANGES.txt CHANGED
@@ -1,6 +1,43 @@
1
+
2
+ === 7.1.0
3
+
4
+ * Accept pubkey_algorithms option when starting a new connection [#891]
5
+
6
+ === 7.1.0 beta1
7
+
8
+ * Don't use the deprecated set_XXX methods on RSA keys. [#875]
9
+ * Raise error when BCryptPbkdf fails [#876]
10
+
11
+ === 7.0.1
12
+
13
+ * Drop leftover debug statement [#866]
14
+
15
+ === 7.0.0
16
+
17
+ * BREAKING: Drop support for Ruby 2.5
18
+ * Fix decoding of ecdsa-sha2-nistp256 private keys [#657, #854]
19
+ * Fix missing require [#855]
20
+ * Support `~` in the path to the SSH agent's unix socket [#850]
21
+ * Add support for RSA client authentication with SHA-2 [a45f54]
22
+ * openssl: DSA: don't hardcode expected signature size, see ruby/openssl#483 [23a15c]
23
+ * Internal housekeeping (rubocop, codecov, remove travis, adding/improving tests)
24
+
25
+ === 6.3.0 beta1
26
+
27
+ * Support cert based host key auth, fix asterisk in known_hosts [#833]
28
+ * Support kex dh-group14-sha256 [#795]
29
+ * Fix StrictHostKeyChecking ssh config parameter translation [#765]
30
+
31
+ === 6.2.0 rc1
32
+
33
+ === 6.2.0 beta1
34
+
35
+ * rsa-sha2-512, rsa-sha2-256 host_key algs [#771]
36
+ * JRuby aes*-ctr suppport [#767]
37
+
1
38
  === 6.1.0
2
39
 
3
- * adapt to ssh's default bahaviors when no username is provided.
40
+ * Adapt to ssh's default behaviors when no username is provided.
4
41
  When Net::SSH.start user is nil and config has no entry
5
42
  we default to Etc.getpwuid.name() instead of Etc.getlogin(). [#749]
6
43
 
@@ -36,7 +73,7 @@
36
73
  === 5.2.0.rc3
37
74
 
38
75
  * Fix check_host_ip read from config
39
- * Support ssh-ed25519 in kown hosts
76
+ * Support ssh-ed25519 in known hosts
40
77
 
41
78
  === 5.2.0.rc2
42
79
 
@@ -59,7 +96,7 @@
59
96
 
60
97
  === 5.0.2
61
98
 
62
- * fix ctr for jruby [#612]
99
+ * Fix ctr for jruby [#612]
63
100
 
64
101
  === 5.0.1
65
102
 
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
- # Net::SSH 6.x
8
+ # Net::SSH 7.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
 
@@ -241,6 +247,10 @@ mv gem-public_cert.pem net-ssh-public_cert.pem
241
247
  gem cert --add net-ssh-public_cert.pem
242
248
  ```
243
249
 
250
+ ## Security contact information
251
+
252
+ See [SECURITY.md](SECURITY.md)
253
+
244
254
  ## CREDITS
245
255
 
246
256
  ### Contributors
data/Rakefile CHANGED
@@ -48,12 +48,67 @@ 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"
54
55
  end
55
56
  end
56
57
 
58
+ def change_version(&block)
59
+ version_file = 'lib/net/ssh/version.rb'
60
+ require_relative version_file
61
+ pre = Net::SSH::Version::PRE
62
+ result = block[pre: pre]
63
+ raise "Version change logic should always return a pre", ArgumentError unless result.key?(:pre)
64
+
65
+ new_pre = result[:pre]
66
+ found = false
67
+ File.open("#{version_file}.new", "w") do |f|
68
+ File.readlines(version_file).each do |line|
69
+ match = /^(\s+PRE\s+=\s+")#{pre}("\s*)$/.match(line)
70
+ if match
71
+ prefix = match[1]
72
+ postfix = match[2]
73
+ if new_pre.nil?
74
+ prefix.delete_suffix!('"')
75
+ postfix.delete_prefix!('"')
76
+ end
77
+ new_line = "#{prefix}#{new_pre.inspect}#{postfix}"
78
+ puts "Changing:\n - #{line} + #{new_line}"
79
+ line = new_line
80
+ found = true
81
+ end
82
+ f.write(line)
83
+ end
84
+ raise ArugmentError, "Cound not find line: PRE = \"#{pre}\" in #{version_file}" unless found
85
+ end
86
+
87
+ FileUtils.mv version_file, "#{version_file}.old"
88
+ FileUtils.mv "#{version_file}.new", version_file
89
+ end
90
+
91
+ namespace :vbump do
92
+ desc "Final release"
93
+ task :final do
94
+ change_version do |pre:|
95
+ raise ArgumentError, "Unexpected pre: #{pre}" if pre.nil?
96
+
97
+ { pre: nil }
98
+ end
99
+ end
100
+
101
+ desc "Increment prerelease"
102
+ task :pre do
103
+ change_version do |pre:|
104
+ match = /^([a-z]+)(\d+)/.match(pre)
105
+ raise ArgumentError, "Unexpected pre: #{pre}" if match.nil?
106
+
107
+ { pre: "#{match[1]}#{match[2].to_i + 1}" }
108
+ end
109
+ end
110
+ end
111
+
57
112
  namespace :rdoc do
58
113
  desc "Update gh-pages branch"
59
114
  task :publish do
@@ -94,6 +149,10 @@ Rake::TestTask.new do |t|
94
149
  t.test_files = test_files
95
150
  end
96
151
 
152
+ # We need to enable the OpenSSL 3.0 legacy providers for our test suite
153
+ require 'openssl'
154
+ ENV['OPENSSL_CONF'] = 'test/openssl3.conf' if OpenSSL::OPENSSL_LIBRARY_VERSION.start_with? "OpenSSL 3"
155
+
97
156
  desc "Run tests of Net::SSH:Test"
98
157
  Rake::TestTask.new do |t|
99
158
  t.name = "test_test"
data/SECURITY.md ADDED
@@ -0,0 +1,4 @@
1
+ ## Security contact information
2
+
3
+ To report a security vulnerability, please use the
4
+ [GitHub private vulnerability reporting feature](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability).
@@ -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
 
@@ -39,6 +40,8 @@ module Net
39
40
  SSH2_AGENT_ADD_IDENTITY = 17
40
41
  SSH2_AGENT_REMOVE_IDENTITY = 18
41
42
  SSH2_AGENT_REMOVE_ALL_IDENTITIES = 19
43
+ SSH2_AGENT_LOCK = 22
44
+ SSH2_AGENT_UNLOCK = 23
42
45
  SSH2_AGENT_ADD_ID_CONSTRAINED = 25
43
46
  SSH2_AGENT_FAILURE = 30
44
47
  SSH2_AGENT_VERSION_RESPONSE = 103
@@ -62,7 +65,7 @@ module Net
62
65
 
63
66
  # Instantiates a new agent object, connects to a running SSH agent,
64
67
  # negotiates the agent protocol version, and returns the agent object.
65
- 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)
66
69
  agent = new(logger)
67
70
  agent.connect!(agent_socket_factory, identity_agent)
68
71
  agent.negotiate!
@@ -71,7 +74,7 @@ module Net
71
74
 
72
75
  # Creates a new Agent object, using the optional logger instance to
73
76
  # report status.
74
- def initialize(logger=nil)
77
+ def initialize(logger = nil)
75
78
  self.logger = logger
76
79
  end
77
80
 
@@ -85,9 +88,9 @@ module Net
85
88
  if agent_socket_factory
86
89
  agent_socket_factory.call
87
90
  elsif identity_agent
88
- unix_socket_class.open(identity_agent)
91
+ unix_socket_class.open(File.expand_path(identity_agent))
89
92
  elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class
90
- unix_socket_class.open(ENV['SSH_AUTH_SOCK'])
93
+ unix_socket_class.open(File.expand_path(ENV['SSH_AUTH_SOCK']))
91
94
  elsif Gem.win_platform? && RUBY_ENGINE != "jruby"
92
95
  Pageant::Socket.open
93
96
  else
@@ -105,6 +108,7 @@ module Net
105
108
  type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
106
109
 
107
110
  raise AgentNotAvailable, "SSH2 agents are not yet supported" if type == SSH2_AGENT_VERSION_RESPONSE
111
+
108
112
  if type == SSH2_AGENT_FAILURE
109
113
  debug { "Unexpected response type==#{type}, this will be ignored" }
110
114
  elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
@@ -173,7 +177,7 @@ module Net
173
177
 
174
178
  req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED
175
179
  type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key),
176
- :string, comment, :raw, constraints)
180
+ :string, comment, :raw, constraints)
177
181
  raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS
178
182
  end
179
183
 
@@ -189,6 +193,18 @@ module Net
189
193
  raise AgentError, "could not remove all identity from agent" if type != SSH_AGENT_SUCCESS
190
194
  end
191
195
 
196
+ # lock the ssh agent with password
197
+ def lock(password)
198
+ type, = send_and_wait(SSH2_AGENT_LOCK, :string, password)
199
+ raise AgentError, "could not lock agent" if type != SSH_AGENT_SUCCESS
200
+ end
201
+
202
+ # unlock the ssh agent with password
203
+ def unlock(password)
204
+ type, = send_and_wait(SSH2_AGENT_UNLOCK, :string, password)
205
+ raise AgentError, "could not unlock agent" if type != SSH_AGENT_SUCCESS
206
+ end
207
+
192
208
  private
193
209
 
194
210
  def unix_socket_class
@@ -235,31 +251,31 @@ module Net
235
251
  case priv_key.ssh_type
236
252
  when /^ssh-dss$/
237
253
  Net::SSH::Buffer.from(:bignum, priv_key.p, :bignum, priv_key.q, :bignum, priv_key.g,
238
- :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
239
255
  when /^ssh-dss-cert-v01@openssh\.com$/
240
256
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.priv_key).to_s
241
257
  when /^ecdsa\-sha2\-(\w*)$/
242
258
  curve_name = OpenSSL::PKey::EC::CurveNameAliasInv[priv_key.group.curve_name]
243
259
  Net::SSH::Buffer.from(:string, curve_name, :mstring, priv_key.public_key.to_bn.to_s(2),
244
- :bignum, priv_key.private_key).to_s
260
+ :bignum, priv_key.private_key).to_s
245
261
  when /^ecdsa\-sha2\-(\w*)-cert-v01@openssh\.com$/
246
262
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.private_key).to_s
247
263
  when /^ssh-ed25519$/
248
264
  Net::SSH::Buffer.from(:string, priv_key.public_key.verify_key.to_bytes,
249
- :string, priv_key.sign_key.keypair).to_s
265
+ :string, priv_key.sign_key.keypair).to_s
250
266
  when /^ssh-ed25519-cert-v01@openssh\.com$/
251
267
  # Unlike the other certificate types, the public key is included after the certifiate.
252
268
  Net::SSH::Buffer.from(:string, priv_key.to_blob,
253
- :string, priv_key.key.public_key.verify_key.to_bytes,
254
- :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
255
271
  when /^ssh-rsa$/
256
272
  # `n` and `e` are reversed compared to the ordering in `OpenSSL::PKey::RSA#to_blob`.
257
273
  Net::SSH::Buffer.from(:bignum, priv_key.n, :bignum, priv_key.e, :bignum, priv_key.d,
258
- :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
259
275
  when /^ssh-rsa-cert-v01@openssh\.com$/
260
276
  Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.d,
261
- :bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
262
- :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
263
279
  end
264
280
  end
265
281
  end
@@ -31,12 +31,13 @@ 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.
38
- # 0x20c49ba5e353f7 = 292278994-08-17 01:12:55 -0600
39
- Time.at([0x20c49ba5e353f7, buffer.read_int64].min)
38
+ # 0x20c49ba2d52500 = 292278993-01-01 00:00:00 +0000
39
+ # JRuby 9.1 does not accept the year 292278994 because of edge cases (https://github.com/JodaOrg/joda-time/issues/190)
40
+ Time.at([0x20c49ba2d52500, buffer.read_int64].min)
40
41
  else
41
42
  Time.at(buffer.read_int64)
42
43
  end
@@ -65,12 +66,12 @@ module Net
65
66
  ).to_s
66
67
  end
67
68
 
68
- def ssh_do_sign(data)
69
- key.ssh_do_sign(data)
69
+ def ssh_do_sign(data, sig_alg = nil)
70
+ key.ssh_do_sign(data, sig_alg)
70
71
  end
71
72
 
72
- def ssh_do_verify(sig, data)
73
- key.ssh_do_verify(sig, data)
73
+ def ssh_do_verify(sig, data, options = {})
74
+ key.ssh_do_verify(sig, data, options)
74
75
  end
75
76
 
76
77
  def to_pem
@@ -82,7 +83,7 @@ module Net
82
83
  end
83
84
 
84
85
  # Signs the certificate with key.
85
- def sign!(key, sign_nonce=nil)
86
+ def sign!(key, sign_nonce = nil)
86
87
  # ssh-keygen uses 32 bytes of nonce.
87
88
  self.nonce = sign_nonce || SecureRandom.random_bytes(32)
88
89
  self.signature_key = key
@@ -93,7 +94,7 @@ module Net
93
94
  self
94
95
  end
95
96
 
96
- def sign(key, sign_nonce=nil)
97
+ def sign(key, sign_nonce = nil)
97
98
  cert = clone
98
99
  cert.sign!(key, sign_nonce)
99
100
  end
@@ -101,8 +102,8 @@ module Net
101
102
  # Checks whether the certificate's signature was signed by signature key.
102
103
  def signature_valid?
103
104
  buffer = Buffer.new(signature)
104
- buffer.read_string # skip signature format
105
- signature_key.ssh_do_verify(buffer.read_string, to_blob_without_signature)
105
+ sig_format = buffer.read_string
106
+ signature_key.ssh_do_verify(buffer.read_string, to_blob_without_signature, host_key: sig_format)
106
107
  end
107
108
 
108
109
  def self.read_options(buffer)
@@ -124,6 +125,7 @@ module Net
124
125
  def self.type_symbol(type)
125
126
  types = { 1 => :user, 2 => :host }
126
127
  raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
128
+
127
129
  types.fetch(type)
128
130
  end
129
131
  private_class_method :type_symbol
@@ -133,6 +135,7 @@ module Net
133
135
  def type_value(type)
134
136
  types = { user: 1, host: 2 }
135
137
  raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
138
+
136
139
  types.fetch(type)
137
140
  end
138
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,14 @@ 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)
80
+ raise DecryptError.new("BCyryptPbkdf failed", encrypted_key: true) unless key
76
81
  else
77
82
  key = '\x00' * (keylen + ivlen)
78
83
  end
79
84
 
80
- cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv:key[keylen...keylen + ivlen], decrypt: true)
85
+ cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv: key[keylen...keylen + ivlen], decrypt: true)
81
86
 
82
87
  decoded = cipher.update(buffer.remainder_as_buffer.to_s)
83
88
  decoded << cipher.final
@@ -112,7 +117,7 @@ module Net
112
117
  end
113
118
 
114
119
  def to_blob
115
- Net::SSH::Buffer.from(:mstring,"ssh-ed25519",:string,@verify_key.to_bytes).to_s
120
+ Net::SSH::Buffer.from(:mstring, "ssh-ed25519".dup, :string, @verify_key.to_bytes).to_s
116
121
  end
117
122
 
118
123
  def ssh_type
@@ -123,8 +128,8 @@ module Net
123
128
  ssh_type
124
129
  end
125
130
 
126
- def ssh_do_verify(sig,data)
127
- @verify_key.verify(sig,data)
131
+ def ssh_do_verify(sig, data, options = {})
132
+ @verify_key.verify(sig, data)
128
133
  end
129
134
 
130
135
  def to_pem
@@ -148,7 +153,7 @@ module Net
148
153
  _comment = buffer.read_string
149
154
 
150
155
  @pk = pk
151
- @sign_key = SigningKeyFromFile.new(pk,sk)
156
+ @sign_key = SigningKeyFromFile.new(pk, sk)
152
157
  end
153
158
 
154
159
  def to_blob
@@ -167,7 +172,7 @@ module Net
167
172
  PubKey.new(@pk)
168
173
  end
169
174
 
170
- def ssh_do_sign(data)
175
+ def ssh_do_sign(data, sig_alg = nil)
171
176
  @sign_key.sign(data)
172
177
  end
173
178
 
@@ -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