net-ssh 6.0.2 → 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 +51 -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 +19 -8
  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 +37 -21
  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 +3 -3
  100. data/lib/net/ssh.rb +11 -7
  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,3 +1,51 @@
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
+
38
+ === 6.1.0
39
+
40
+ * Adapt to ssh's default behaviors when no username is provided.
41
+ When Net::SSH.start user is nil and config has no entry
42
+ we default to Etc.getpwuid.name() instead of Etc.getlogin(). [#749]
43
+
44
+ === 6.1.0.rc1
45
+
46
+ * Make sha2-{256,512}-etm@openssh.com MAC default again [#761]
47
+ * Support algorithm subtraction syntax from ssh_config [#751]
48
+
1
49
  === 6.0.2
2
50
 
3
51
  * Fix corrupted hmac issue in etm hmac [#759]
@@ -12,7 +60,7 @@
12
60
  * Add sha2-{256,512}-etm@openssh.com MAC algorithms [graaff, #714]
13
61
 
14
62
  === 6.0.0 beta2
15
-
63
+
16
64
  * Support :certkeys and CertificateFile configuration option [Anders Carling, #722]
17
65
 
18
66
  === 6.0.0 beta1
@@ -25,7 +73,7 @@
25
73
  === 5.2.0.rc3
26
74
 
27
75
  * Fix check_host_ip read from config
28
- * Support ssh-ed25519 in kown hosts
76
+ * Support ssh-ed25519 in known hosts
29
77
 
30
78
  === 5.2.0.rc2
31
79
 
@@ -48,7 +96,7 @@
48
96
 
49
97
  === 5.0.2
50
98
 
51
- * fix ctr for jruby [#612]
99
+ * Fix ctr for jruby [#612]
52
100
 
53
101
  === 5.0.1
54
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
@@ -33,7 +33,7 @@ We strongly recommend that you install a servers's version that supports the lat
33
33
 
34
34
  It is possible to return to the previous behavior by adding the option : `append_all_supported_algorithms: true`
35
35
 
36
- Unsecure algoritms will be definively remove in Net::SSH 7.*.
36
+ Unsecure algoritms will definitely be removed in Net::SSH 7.*.
37
37
 
38
38
  ### Host Keys
39
39
 
@@ -63,7 +63,7 @@ Unsecure algoritms will be definively remove in Net::SSH 7.*.
63
63
 
64
64
  | Name | Support | Details |
65
65
  |--------------------------------------|-----------------------|----------|
66
- | aes256-ctr / aes192-ctr / aes128-ctr | OK | [using weak elliptic curves](https://safecurves.cr.yp.to/) |
66
+ | aes256-ctr / aes192-ctr / aes128-ctr | OK | |
67
67
  | aes256-cbc / aes192-cbc / aes128-cbc | Deprecated in 6.0 | unsecure, will be removed in 7.0 |
68
68
  | rijndael-cbc@lysator.liu.se | Deprecated in 6.0 | unsecure, will be removed in 7.0 |
69
69
  | blowfish-ctr blowfish-cbc | Deprecated in 6.0 | unsecure, will be removed in 7.0 |
@@ -97,6 +97,7 @@ In a nutshell:
97
97
  require 'net/ssh'
98
98
 
99
99
  Net::SSH.start('host', 'user', password: "password") do |ssh|
100
+
100
101
  # capture all stderr and stdout output from a remote process
101
102
  output = ssh.exec!("hostname")
102
103
  puts output
@@ -104,7 +105,7 @@ puts output
104
105
  # capture only stdout matching a particular pattern
105
106
  stdout = ""
106
107
  ssh.exec!("ls -l /home/jamis") do |channel, stream, data|
107
- stdout << data if stream == :stdout
108
+ stdout << data if stream == :stdout && /foo/.match(data)
108
109
  end
109
110
  puts stdout
110
111
 
@@ -164,7 +165,7 @@ gem install net-ssh # might need sudo privileges
164
165
  ```
165
166
 
166
167
  NOTE: If you are running on jruby on windows you need to install `jruby-pageant` manually
167
- (gemspec doesn't allow for platform specific dependencies).
168
+ (gemspec doesn't allow for platform specific dependencies at gem installation time).
168
169
 
169
170
  However, in order to be sure the code you're installing hasn't been tampered with,
170
171
  it's recommended that you verify the [signature](http://docs.rubygems.org/read/chapter/21).
@@ -210,13 +211,19 @@ Run the test suite from the net-ssh directory with the following command:
210
211
  bundle exec rake test
211
212
  ```
212
213
 
214
+ NOTE : you can run test on all ruby versions with docker :
215
+
216
+ ```
217
+ docker-compose up --build
218
+ ```
219
+
213
220
  Run a single test file like this:
214
221
 
215
222
  ```sh
216
223
  ruby -Ilib -Itest test/transport/test_server_version.rb
217
224
  ```
218
225
 
219
- To run integration tests see test/integration/README.txt
226
+ To run integration tests see [here](test/integration/README.md)
220
227
 
221
228
  ### BUILDING GEM
222
229
 
@@ -240,6 +247,10 @@ mv gem-public_cert.pem net-ssh-public_cert.pem
240
247
  gem cert --add net-ssh-public_cert.pem
241
248
  ```
242
249
 
250
+ ## Security contact information
251
+
252
+ See [SECURITY.md](SECURITY.md)
253
+
243
254
  ## CREDITS
244
255
 
245
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