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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +22 -11
- data/.github/workflows/rubocop.yml +13 -0
- data/.rubocop.yml +12 -1
- data/.rubocop_todo.yml +470 -262
- data/CHANGES.txt +6 -0
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/README.md +9 -3
- data/Rakefile +5 -0
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +17 -15
- data/lib/net/ssh/authentication/certificate.rb +7 -5
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +10 -6
- data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
- data/lib/net/ssh/authentication/key_manager.rb +46 -34
- data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
- data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
- data/lib/net/ssh/authentication/methods/none.rb +6 -9
- data/lib/net/ssh/authentication/methods/password.rb +2 -3
- data/lib/net/ssh/authentication/methods/publickey.rb +56 -16
- data/lib/net/ssh/authentication/pageant.rb +97 -97
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -2
- data/lib/net/ssh/authentication/session.rb +18 -17
- data/lib/net/ssh/buffer.rb +50 -30
- data/lib/net/ssh/buffered_io.rb +24 -25
- data/lib/net/ssh/config.rb +33 -20
- data/lib/net/ssh/connection/channel.rb +84 -83
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +30 -24
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +108 -107
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +12 -12
- data/lib/net/ssh/key_factory.rb +7 -8
- data/lib/net/ssh/known_hosts.rb +84 -15
- data/lib/net/ssh/loggable.rb +8 -9
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +9 -11
- data/lib/net/ssh/proxy/command.rb +1 -1
- data/lib/net/ssh/proxy/errors.rb +2 -4
- data/lib/net/ssh/proxy/http.rb +18 -20
- data/lib/net/ssh/proxy/https.rb +8 -10
- data/lib/net/ssh/proxy/jump.rb +8 -10
- data/lib/net/ssh/proxy/socks4.rb +2 -4
- data/lib/net/ssh/proxy/socks5.rb +3 -5
- data/lib/net/ssh/service/forward.rb +7 -7
- data/lib/net/ssh/test/channel.rb +23 -25
- data/lib/net/ssh/test/extensions.rb +35 -35
- data/lib/net/ssh/test/kex.rb +6 -8
- data/lib/net/ssh/test/local_packet.rb +0 -2
- data/lib/net/ssh/test/packet.rb +3 -3
- data/lib/net/ssh/test/remote_packet.rb +5 -7
- data/lib/net/ssh/test/script.rb +24 -26
- data/lib/net/ssh/test/socket.rb +12 -15
- data/lib/net/ssh/test.rb +4 -5
- data/lib/net/ssh/transport/algorithms.rb +14 -13
- data/lib/net/ssh/transport/cipher_factory.rb +28 -28
- data/lib/net/ssh/transport/constants.rb +3 -3
- data/lib/net/ssh/transport/ctr.rb +7 -7
- data/lib/net/ssh/transport/hmac/abstract.rb +4 -5
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac.rb +12 -12
- data/lib/net/ssh/transport/identity_cipher.rb +11 -13
- data/lib/net/ssh/transport/kex/abstract.rb +3 -3
- data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
- data/lib/net/ssh/transport/kex.rb +8 -6
- data/lib/net/ssh/transport/key_expander.rb +7 -8
- data/lib/net/ssh/transport/openssl.rb +38 -22
- data/lib/net/ssh/transport/packet_stream.rb +2 -3
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +9 -7
- data/lib/net/ssh/transport/state.rb +43 -43
- data/lib/net/ssh/verifiers/accept_new.rb +0 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +6 -4
- data/lib/net/ssh/verifiers/never.rb +0 -2
- data/lib/net/ssh/version.rb +4 -4
- data/lib/net/ssh.rb +4 -5
- data/net-ssh-public_cert.pem +8 -8
- data/net-ssh.gemspec +2 -2
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +24 -17
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -52
|
@@ -41,6 +41,7 @@ module Net
|
|
|
41
41
|
ecdh-sha2-nistp384
|
|
42
42
|
ecdh-sha2-nistp256
|
|
43
43
|
diffie-hellman-group-exchange-sha256
|
|
44
|
+
diffie-hellman-group14-sha256
|
|
44
45
|
diffie-hellman-group14-sha1],
|
|
45
46
|
|
|
46
47
|
encryption: %w[aes256-ctr aes192-ctr aes128-ctr],
|
|
@@ -145,7 +146,7 @@ module Net
|
|
|
145
146
|
|
|
146
147
|
# Instantiates a new Algorithms object, and prepares the hash of preferred
|
|
147
148
|
# algorithms based on the options parameter and the ALGORITHMS constant.
|
|
148
|
-
def initialize(session, options={})
|
|
149
|
+
def initialize(session, options = {})
|
|
149
150
|
@session = session
|
|
150
151
|
@logger = session.logger
|
|
151
152
|
@options = options
|
|
@@ -277,7 +278,7 @@ module Net
|
|
|
277
278
|
# existing known key for the host has preference.
|
|
278
279
|
|
|
279
280
|
existing_keys = session.host_keys
|
|
280
|
-
host_keys = existing_keys.
|
|
281
|
+
host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
|
|
281
282
|
algorithms[:host_key].each do |name|
|
|
282
283
|
host_keys << name unless host_keys.include?(name)
|
|
283
284
|
end
|
|
@@ -368,10 +369,10 @@ module Net
|
|
|
368
369
|
language = algorithms[:language].join(",")
|
|
369
370
|
|
|
370
371
|
Net::SSH::Buffer.from(:byte, KEXINIT,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
372
|
+
:long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
|
|
373
|
+
:mstring, [kex, host_key, encryption, encryption, hmac, hmac],
|
|
374
|
+
:mstring, [compression, compression, language, language],
|
|
375
|
+
:bool, false, :long, 0)
|
|
375
376
|
end
|
|
376
377
|
|
|
377
378
|
# Given the parsed server KEX packet, and the client's preferred algorithm
|
|
@@ -437,13 +438,13 @@ module Net
|
|
|
437
438
|
debug { "exchanging keys" }
|
|
438
439
|
|
|
439
440
|
algorithm = Kex::MAP[kex].new(self, session,
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
441
|
+
client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
|
|
442
|
+
server_version_string: session.server_version.version,
|
|
443
|
+
server_algorithm_packet: @server_packet,
|
|
444
|
+
client_algorithm_packet: @client_packet,
|
|
445
|
+
need_bytes: kex_byte_requirement,
|
|
446
|
+
minimum_dh_bits: options[:minimum_dh_bits],
|
|
447
|
+
logger: logger)
|
|
447
448
|
result = algorithm.exchange_keys
|
|
448
449
|
|
|
449
450
|
secret = result[:shared_secret].to_ssh
|
|
@@ -3,31 +3,30 @@ require 'net/ssh/transport/ctr.rb'
|
|
|
3
3
|
require 'net/ssh/transport/key_expander'
|
|
4
4
|
require 'net/ssh/transport/identity_cipher'
|
|
5
5
|
|
|
6
|
-
module Net
|
|
7
|
-
module SSH
|
|
6
|
+
module Net
|
|
7
|
+
module SSH
|
|
8
8
|
module Transport
|
|
9
|
-
|
|
10
9
|
# Implements a factory of OpenSSL cipher algorithms.
|
|
11
10
|
class CipherFactory
|
|
12
11
|
# Maps the SSH name of a cipher to it's corresponding OpenSSL name
|
|
13
12
|
SSH_TO_OSSL = {
|
|
14
|
-
"3des-cbc"
|
|
15
|
-
"blowfish-cbc"
|
|
16
|
-
"aes256-cbc"
|
|
17
|
-
"aes192-cbc"
|
|
18
|
-
"aes128-cbc"
|
|
19
|
-
"idea-cbc"
|
|
20
|
-
"cast128-cbc"
|
|
13
|
+
"3des-cbc" => "des-ede3-cbc",
|
|
14
|
+
"blowfish-cbc" => "bf-cbc",
|
|
15
|
+
"aes256-cbc" => "aes-256-cbc",
|
|
16
|
+
"aes192-cbc" => "aes-192-cbc",
|
|
17
|
+
"aes128-cbc" => "aes-128-cbc",
|
|
18
|
+
"idea-cbc" => "idea-cbc",
|
|
19
|
+
"cast128-cbc" => "cast-cbc",
|
|
21
20
|
"rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
|
|
22
|
-
"3des-ctr"
|
|
23
|
-
"blowfish-ctr"
|
|
21
|
+
"3des-ctr" => "des-ede3",
|
|
22
|
+
"blowfish-ctr" => "bf-ecb",
|
|
24
23
|
|
|
25
|
-
"aes256-ctr"
|
|
26
|
-
"aes192-ctr"
|
|
27
|
-
"aes128-ctr"
|
|
28
|
-
'cast128-ctr'
|
|
24
|
+
"aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
|
|
25
|
+
"aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
|
|
26
|
+
"aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
|
|
27
|
+
'cast128-ctr' => 'cast5-ecb',
|
|
29
28
|
|
|
30
|
-
'none'
|
|
29
|
+
'none' => 'none'
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
# Returns true if the underlying OpenSSL library supports the given cipher,
|
|
@@ -35,23 +34,25 @@ module Net
|
|
|
35
34
|
def self.supported?(name)
|
|
36
35
|
ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
|
|
37
36
|
return true if ossl_name == "none"
|
|
37
|
+
|
|
38
38
|
return OpenSSL::Cipher.ciphers.include?(ossl_name)
|
|
39
39
|
end
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
# Retrieves a new instance of the named algorithm. The new instance
|
|
42
42
|
# will be initialized using an iv and key generated from the given
|
|
43
43
|
# iv, key, shared, hash and digester values. Additionally, the
|
|
44
44
|
# cipher will be put into encryption or decryption mode, based on the
|
|
45
45
|
# value of the +encrypt+ parameter.
|
|
46
|
-
def self.get(name, options={})
|
|
46
|
+
def self.get(name, options = {})
|
|
47
47
|
ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
|
|
48
48
|
return IdentityCipher if ossl_name == "none"
|
|
49
|
+
|
|
49
50
|
cipher = OpenSSL::Cipher.new(ossl_name)
|
|
50
|
-
|
|
51
|
+
|
|
51
52
|
cipher.send(options[:encrypt] ? :encrypt : :decrypt)
|
|
52
|
-
|
|
53
|
+
|
|
53
54
|
cipher.padding = 0
|
|
54
|
-
|
|
55
|
+
|
|
55
56
|
if name =~ /-ctr(@openssh.org)?$/
|
|
56
57
|
if ossl_name !~ /-ctr/
|
|
57
58
|
cipher.extend(Net::SSH::Transport::CTR)
|
|
@@ -60,14 +61,14 @@ module Net
|
|
|
60
61
|
end
|
|
61
62
|
end
|
|
62
63
|
cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)
|
|
63
|
-
|
|
64
|
+
|
|
64
65
|
key_len = cipher.key_len
|
|
65
66
|
cipher.key_len = key_len
|
|
66
67
|
cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
|
|
67
|
-
|
|
68
|
+
|
|
68
69
|
return cipher
|
|
69
70
|
end
|
|
70
|
-
|
|
71
|
+
|
|
71
72
|
# Returns a two-element array containing the [ key-length,
|
|
72
73
|
# block-size ] for the named cipher algorithm. If the cipher
|
|
73
74
|
# algorithm is unknown, or is "none", 0 is returned for both elements
|
|
@@ -82,7 +83,7 @@ module Net
|
|
|
82
83
|
cipher = OpenSSL::Cipher.new(ossl_name)
|
|
83
84
|
key_len = cipher.key_len
|
|
84
85
|
cipher.key_len = key_len
|
|
85
|
-
|
|
86
|
+
|
|
86
87
|
block_size =
|
|
87
88
|
case ossl_name
|
|
88
89
|
when /\-ctr/
|
|
@@ -90,14 +91,13 @@ module Net
|
|
|
90
91
|
else
|
|
91
92
|
cipher.block_size
|
|
92
93
|
end
|
|
93
|
-
|
|
94
|
+
|
|
94
95
|
result = [key_len, block_size]
|
|
95
96
|
result << cipher.iv_len if options[:iv_len]
|
|
96
97
|
end
|
|
97
98
|
result
|
|
98
99
|
end
|
|
99
100
|
end
|
|
100
|
-
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
103
|
end
|
|
@@ -2,7 +2,7 @@ require 'openssl'
|
|
|
2
2
|
require 'delegate'
|
|
3
3
|
|
|
4
4
|
module Net::SSH::Transport
|
|
5
|
-
|
|
5
|
+
# :nodoc:
|
|
6
6
|
class OpenSSLAESCTR < SimpleDelegator
|
|
7
7
|
def initialize(original)
|
|
8
8
|
super
|
|
@@ -26,13 +26,13 @@ module Net::SSH::Transport
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
# :nodoc:
|
|
30
30
|
# Pure-Ruby implementation of Stateful Decryption Counter(SDCTR) Mode
|
|
31
31
|
# for Block Ciphers. See RFC4344 for detail.
|
|
32
32
|
module CTR
|
|
33
33
|
def self.extended(orig)
|
|
34
34
|
orig.instance_eval {
|
|
35
|
-
@remaining =
|
|
35
|
+
@remaining = String.new
|
|
36
36
|
@counter = nil
|
|
37
37
|
@counter_len = orig.block_size
|
|
38
38
|
orig.encrypt
|
|
@@ -67,13 +67,13 @@ module Net::SSH::Transport
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def reset
|
|
70
|
-
@remaining =
|
|
70
|
+
@remaining = String.new
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def update(data)
|
|
74
74
|
@remaining += data
|
|
75
75
|
|
|
76
|
-
encrypted =
|
|
76
|
+
encrypted = String.new
|
|
77
77
|
|
|
78
78
|
offset = 0
|
|
79
79
|
while (@remaining.bytesize - offset) >= block_size
|
|
@@ -89,13 +89,13 @@ module Net::SSH::Transport
|
|
|
89
89
|
|
|
90
90
|
def final
|
|
91
91
|
s = @remaining.empty? ? '' : xor!(@remaining, _update(@counter))
|
|
92
|
-
@remaining =
|
|
92
|
+
@remaining = String.new
|
|
93
93
|
s
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def xor!(s1, s2)
|
|
97
97
|
s = []
|
|
98
|
-
s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a ^ b) }
|
|
98
|
+
s1.unpack('Q*').zip(s2.unpack('Q*')) {|a, b| s.push(a ^ b) }
|
|
99
99
|
s.pack('Q*')
|
|
100
100
|
end
|
|
101
101
|
singleton_class.send(:private, :xor!)
|
|
@@ -5,10 +5,9 @@ module Net
|
|
|
5
5
|
module SSH
|
|
6
6
|
module Transport
|
|
7
7
|
module HMAC
|
|
8
|
-
|
|
9
8
|
# The base class of all OpenSSL-based HMAC algorithm wrappers.
|
|
10
9
|
class Abstract
|
|
11
|
-
class <<self
|
|
10
|
+
class << self
|
|
12
11
|
def etm(*v)
|
|
13
12
|
@etm = false if !defined?(@etm)
|
|
14
13
|
if v.empty?
|
|
@@ -77,19 +76,19 @@ module Net
|
|
|
77
76
|
# The key in use for this instance.
|
|
78
77
|
attr_reader :key
|
|
79
78
|
|
|
80
|
-
def initialize(key=nil)
|
|
79
|
+
def initialize(key = nil)
|
|
81
80
|
self.key = key
|
|
82
81
|
end
|
|
83
82
|
|
|
84
83
|
# Sets the key to the given value, truncating it so that it is the correct
|
|
85
84
|
# length.
|
|
86
85
|
def key=(value)
|
|
87
|
-
@key = value ? value.to_s[0,key_length] : nil
|
|
86
|
+
@key = value ? value.to_s[0, key_length] : nil
|
|
88
87
|
end
|
|
89
88
|
|
|
90
89
|
# Compute the HMAC digest for the given data string.
|
|
91
90
|
def digest(data)
|
|
92
|
-
OpenSSL::HMAC.digest(digest_class.new, key, data)[0,mac_length]
|
|
91
|
+
OpenSSL::HMAC.digest(digest_class.new, key, data)[0, mac_length]
|
|
93
92
|
end
|
|
94
93
|
end
|
|
95
94
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'net/ssh/transport/hmac/abstract'
|
|
2
2
|
|
|
3
3
|
module Net::SSH::Transport::HMAC
|
|
4
|
-
|
|
5
4
|
# The "none" algorithm. This has a key and mac length of 0.
|
|
6
5
|
class None < Abstract
|
|
7
6
|
key_length 0
|
|
@@ -11,5 +10,4 @@ module Net::SSH::Transport::HMAC
|
|
|
11
10
|
""
|
|
12
11
|
end
|
|
13
12
|
end
|
|
14
|
-
|
|
15
13
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'net/ssh/transport/hmac/abstract'
|
|
2
2
|
|
|
3
3
|
module Net::SSH::Transport::HMAC
|
|
4
|
-
|
|
5
4
|
# The RIPEMD-160 HMAC algorithm. This has a mac and key length of 20, and
|
|
6
5
|
# uses the RIPEMD-160 digest algorithm.
|
|
7
6
|
class RIPEMD160 < Abstract
|
|
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
|
|
|
9
8
|
key_length 20
|
|
10
9
|
digest_class OpenSSL::Digest::RIPEMD160
|
|
11
10
|
end
|
|
12
|
-
|
|
13
11
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'net/ssh/transport/hmac/abstract'
|
|
2
2
|
|
|
3
3
|
module Net::SSH::Transport::HMAC
|
|
4
|
-
|
|
5
4
|
# The SHA1 HMAC algorithm. This has a mac and key length of 20, and
|
|
6
5
|
# uses the SHA1 digest algorithm.
|
|
7
6
|
class SHA1 < Abstract
|
|
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
|
|
|
9
8
|
key_length 20
|
|
10
9
|
digest_class OpenSSL::Digest::SHA1
|
|
11
10
|
end
|
|
12
|
-
|
|
13
11
|
end
|
|
@@ -17,24 +17,24 @@ require 'net/ssh/transport/hmac/none'
|
|
|
17
17
|
module Net::SSH::Transport::HMAC
|
|
18
18
|
# The mapping of SSH hmac algorithms to their implementations
|
|
19
19
|
MAP = {
|
|
20
|
-
'hmac-md5'
|
|
21
|
-
'hmac-md5-96'
|
|
22
|
-
'hmac-sha1'
|
|
23
|
-
'hmac-sha1-96'
|
|
24
|
-
'hmac-sha2-256'
|
|
25
|
-
'hmac-sha2-256-96'
|
|
26
|
-
'hmac-sha2-512'
|
|
27
|
-
'hmac-sha2-512-96'
|
|
20
|
+
'hmac-md5' => MD5,
|
|
21
|
+
'hmac-md5-96' => MD5_96,
|
|
22
|
+
'hmac-sha1' => SHA1,
|
|
23
|
+
'hmac-sha1-96' => SHA1_96,
|
|
24
|
+
'hmac-sha2-256' => SHA2_256,
|
|
25
|
+
'hmac-sha2-256-96' => SHA2_256_96,
|
|
26
|
+
'hmac-sha2-512' => SHA2_512,
|
|
27
|
+
'hmac-sha2-512-96' => SHA2_512_96,
|
|
28
28
|
'hmac-sha2-256-etm@openssh.com' => SHA2_256_Etm,
|
|
29
29
|
'hmac-sha2-512-etm@openssh.com' => SHA2_512_Etm,
|
|
30
|
-
'hmac-ripemd160'
|
|
31
|
-
'hmac-ripemd160@openssh.com'
|
|
32
|
-
'none'
|
|
30
|
+
'hmac-ripemd160' => RIPEMD160,
|
|
31
|
+
'hmac-ripemd160@openssh.com' => RIPEMD160,
|
|
32
|
+
'none' => None
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
# Retrieves a new hmac instance of the given SSH type (+name+). If +key+ is
|
|
36
36
|
# given, the new instance will be initialized with that key.
|
|
37
|
-
def self.get(name, key="", parameters = {})
|
|
37
|
+
def self.get(name, key = "", parameters = {})
|
|
38
38
|
impl = MAP[name] or raise ArgumentError, "hmac not found: #{name.inspect}"
|
|
39
39
|
impl.new(Net::SSH::Transport::KeyExpander.expand_key(impl.key_length, key, parameters))
|
|
40
40
|
end
|
|
@@ -1,59 +1,57 @@
|
|
|
1
|
-
module Net
|
|
2
|
-
module SSH
|
|
1
|
+
module Net
|
|
2
|
+
module SSH
|
|
3
3
|
module Transport
|
|
4
|
-
|
|
5
4
|
# A cipher that does nothing but pass the data through, unchanged. This
|
|
6
5
|
# keeps things in the code nice and clean when a cipher has not yet been
|
|
7
6
|
# determined (i.e., during key exchange).
|
|
8
7
|
class IdentityCipher
|
|
9
|
-
class <<self
|
|
8
|
+
class << self
|
|
10
9
|
# A default block size of 8 is required by the SSH2 protocol.
|
|
11
10
|
def block_size
|
|
12
11
|
8
|
|
13
12
|
end
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
# Returns an arbitrary integer.
|
|
16
15
|
def iv_len
|
|
17
16
|
4
|
|
18
17
|
end
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
# Does nothing. Returns self.
|
|
21
20
|
def encrypt
|
|
22
21
|
self
|
|
23
22
|
end
|
|
24
|
-
|
|
23
|
+
|
|
25
24
|
# Does nothing. Returns self.
|
|
26
25
|
def decrypt
|
|
27
26
|
self
|
|
28
27
|
end
|
|
29
|
-
|
|
28
|
+
|
|
30
29
|
# Passes its single argument through unchanged.
|
|
31
30
|
def update(text)
|
|
32
31
|
text
|
|
33
32
|
end
|
|
34
|
-
|
|
33
|
+
|
|
35
34
|
# Returns the empty string.
|
|
36
35
|
def final
|
|
37
36
|
""
|
|
38
37
|
end
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
# The name of this cipher, which is "identity".
|
|
41
40
|
def name
|
|
42
41
|
"identity"
|
|
43
42
|
end
|
|
44
|
-
|
|
43
|
+
|
|
45
44
|
# Does nothing. Returns nil.
|
|
46
45
|
def iv=(v)
|
|
47
46
|
nil
|
|
48
47
|
end
|
|
49
|
-
|
|
48
|
+
|
|
50
49
|
# Does nothing. Returns self.
|
|
51
50
|
def reset
|
|
52
51
|
self
|
|
53
52
|
end
|
|
54
53
|
end
|
|
55
54
|
end
|
|
56
|
-
|
|
57
55
|
end
|
|
58
56
|
end
|
|
59
57
|
end
|
|
@@ -72,7 +72,7 @@ module Net
|
|
|
72
72
|
# Verify that the given key is of the expected type, and that it
|
|
73
73
|
# really is the key for the session's host. Raise Net::SSH::Exception
|
|
74
74
|
# if it is not.
|
|
75
|
-
def verify_server_key(key)
|
|
75
|
+
def verify_server_key(key) # :nodoc:
|
|
76
76
|
unless matching?(key.ssh_type, algorithms.host_key)
|
|
77
77
|
raise Net::SSH::Exception, "host key algorithm mismatch '#{key.ssh_type}' != '#{algorithms.host_key}'"
|
|
78
78
|
end
|
|
@@ -97,7 +97,7 @@ module Net
|
|
|
97
97
|
# Verify the signature that was received. Raise Net::SSH::Exception
|
|
98
98
|
# if the signature could not be verified. Otherwise, return the new
|
|
99
99
|
# session-id.
|
|
100
|
-
def verify_signature(result)
|
|
100
|
+
def verify_signature(result) # :nodoc:
|
|
101
101
|
response = build_signature_buffer(result)
|
|
102
102
|
|
|
103
103
|
hash = digester.digest(response.to_s)
|
|
@@ -113,7 +113,7 @@ module Net
|
|
|
113
113
|
|
|
114
114
|
# Send the NEWKEYS message, and expect the NEWKEYS message in
|
|
115
115
|
# reply.
|
|
116
|
-
def confirm_newkeys
|
|
116
|
+
def confirm_newkeys # :nodoc:
|
|
117
117
|
# send own NEWKEYS message first (the wodSSHServer won't send first)
|
|
118
118
|
response = Net::SSH::Buffer.new
|
|
119
119
|
response.write_byte(NEWKEYS)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
gem 'x25519' # raise if the gem x25519 is not installed
|
|
2
2
|
|
|
3
3
|
require 'x25519'
|
|
4
|
+
|
|
4
5
|
require 'net/ssh/transport/constants'
|
|
5
6
|
require 'net/ssh/transport/kex/abstract5656'
|
|
6
7
|
|
|
@@ -17,7 +18,7 @@ module Net
|
|
|
17
18
|
|
|
18
19
|
private
|
|
19
20
|
|
|
20
|
-
def generate_key
|
|
21
|
+
def generate_key # :nodoc:
|
|
21
22
|
::X25519::Scalar.generate
|
|
22
23
|
end
|
|
23
24
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
|
|
2
2
|
|
|
3
|
-
module Net
|
|
4
|
-
module SSH
|
|
5
|
-
module Transport
|
|
3
|
+
module Net
|
|
4
|
+
module SSH
|
|
5
|
+
module Transport
|
|
6
6
|
module Kex
|
|
7
7
|
# A key-exchange service implementing the "diffie-hellman-group14-sha1"
|
|
8
8
|
# key-exchange algorithm. (defined in RFC 4253)
|
|
@@ -24,7 +24,7 @@ module Net
|
|
|
24
24
|
"B5C55DF0" "6F4C52C9" "DE2BCBF6" "95581718" +
|
|
25
25
|
"3995497C" "EA956AE5" "15D22618" "98FA0510" +
|
|
26
26
|
"15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
# The radix in which P_s represents the value of P
|
|
29
29
|
P_r = 16
|
|
30
30
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
|
|
2
|
+
|
|
3
|
+
module Net::SSH::Transport::Kex
|
|
4
|
+
# A key-exchange service implementing the "diffie-hellman-group14-sha256"
|
|
5
|
+
# key-exchange algorithm.
|
|
6
|
+
class DiffieHellmanGroup14SHA256 < DiffieHellmanGroup14SHA1
|
|
7
|
+
def digester
|
|
8
|
+
OpenSSL::Digest::SHA256
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -59,26 +59,26 @@ module Net
|
|
|
59
59
|
|
|
60
60
|
# Generate a DH key with a private key consisting of the given
|
|
61
61
|
# number of bytes.
|
|
62
|
-
def generate_key
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
def generate_key # :nodoc:
|
|
63
|
+
p, g = get_parameters
|
|
64
|
+
|
|
65
|
+
asn1 = OpenSSL::ASN1::Sequence(
|
|
66
|
+
[
|
|
67
|
+
OpenSSL::ASN1::Integer(p),
|
|
68
|
+
OpenSSL::ASN1::Integer(g)
|
|
69
|
+
]
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
dh_params = OpenSSL::PKey::DH.new(asn1.to_der)
|
|
73
|
+
# XXX No private key size check! In theory the latter call should work but fails on OpenSSL 3.0 as
|
|
74
|
+
# dh_paramgen_subprime_len is now reserved for DHX algorithm
|
|
75
|
+
# key = OpenSSL::PKey.generate_key(dh_params, "dh_paramgen_subprime_len" => data[:need_bytes]/8)
|
|
76
|
+
if OpenSSL::PKey.respond_to?(:generate_key)
|
|
77
|
+
OpenSSL::PKey.generate_key(dh_params)
|
|
68
78
|
else
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
dh.generate_key!
|
|
73
|
-
until dh.valid? && dh.priv_key.num_bytes == data[:need_bytes]
|
|
74
|
-
if dh.respond_to?(:set_key)
|
|
75
|
-
dh.set_key(nil, OpenSSL::BN.rand(data[:need_bytes] * 8))
|
|
76
|
-
else
|
|
77
|
-
dh.priv_key = OpenSSL::BN.rand(data[:need_bytes] * 8)
|
|
78
|
-
end
|
|
79
|
-
dh.generate_key!
|
|
79
|
+
dh_params.generate_key!
|
|
80
|
+
dh_params
|
|
80
81
|
end
|
|
81
|
-
dh
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
# Send the KEXDH_INIT message, and expect the KEXDH_REPLY. Return the
|
|
@@ -86,7 +86,7 @@ module Net
|
|
|
86
86
|
#
|
|
87
87
|
# Parse the buffer from a KEXDH_REPLY message, returning a hash of
|
|
88
88
|
# the extracted values.
|
|
89
|
-
def send_kexinit
|
|
89
|
+
def send_kexinit # :nodoc:
|
|
90
90
|
init, reply = get_message_types
|
|
91
91
|
|
|
92
92
|
# send the KEXDH_INIT message
|
|
@@ -108,8 +108,8 @@ module Net
|
|
|
108
108
|
sig_type = sig_buffer.read_string
|
|
109
109
|
if sig_type != algorithms.host_key_format
|
|
110
110
|
raise Net::SSH::Exception,
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
"host key algorithm mismatch for signature " +
|
|
112
|
+
"'#{sig_type}' != '#{algorithms.host_key_format}'"
|
|
113
113
|
end
|
|
114
114
|
result[:server_sig] = sig_buffer.read_string
|
|
115
115
|
|
|
@@ -34,7 +34,7 @@ module Net::SSH::Transport::Kex
|
|
|
34
34
|
|
|
35
35
|
# request the DH key parameters for the given number of bits.
|
|
36
36
|
buffer = Net::SSH::Buffer.from(:byte, KEXDH_GEX_REQUEST, :long, data[:minimum_dh_bits],
|
|
37
|
-
|
|
37
|
+
:long, data[:need_bits], :long, MAXIMUM_BITS)
|
|
38
38
|
connection.send_message(buffer)
|
|
39
39
|
|
|
40
40
|
buffer = connection.next_message
|
|
@@ -69,5 +69,4 @@ module Net::SSH::Transport::Kex
|
|
|
69
69
|
response
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
|
-
|
|
73
72
|
end
|
|
@@ -17,8 +17,8 @@ module Net
|
|
|
17
17
|
|
|
18
18
|
private
|
|
19
19
|
|
|
20
|
-
def generate_key
|
|
21
|
-
OpenSSL::PKey::EC.
|
|
20
|
+
def generate_key # :nodoc:
|
|
21
|
+
OpenSSL::PKey::EC.generate(curve_name)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# compute shared secret from server's public key and client's private key
|