net-ssh-backports 6.3.0.backports
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 +7 -0
- data/.github/workflows/ci.yml +93 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +1074 -0
- data/.travis.yml +51 -0
- data/CHANGES.txt +698 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/LICENSE.txt +19 -0
- data/Manifest +132 -0
- data/README.md +287 -0
- data/Rakefile +105 -0
- data/THANKS.txt +110 -0
- data/appveyor.yml +58 -0
- data/lib/net/ssh/authentication/agent.rb +284 -0
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +20 -0
- data/lib/net/ssh/authentication/ed25519.rb +185 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +297 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +69 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
- data/lib/net/ssh/authentication/methods/none.rb +34 -0
- data/lib/net/ssh/authentication/methods/password.rb +80 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +95 -0
- data/lib/net/ssh/authentication/pageant.rb +497 -0
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +163 -0
- data/lib/net/ssh/buffer.rb +434 -0
- data/lib/net/ssh/buffered_io.rb +202 -0
- data/lib/net/ssh/config.rb +406 -0
- data/lib/net/ssh/connection/channel.rb +695 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +59 -0
- data/lib/net/ssh/connection/session.rb +712 -0
- data/lib/net/ssh/connection/term.rb +180 -0
- data/lib/net/ssh/errors.rb +106 -0
- data/lib/net/ssh/key_factory.rb +218 -0
- data/lib/net/ssh/known_hosts.rb +264 -0
- data/lib/net/ssh/loggable.rb +62 -0
- data/lib/net/ssh/packet.rb +106 -0
- data/lib/net/ssh/prompt.rb +62 -0
- data/lib/net/ssh/proxy/command.rb +123 -0
- data/lib/net/ssh/proxy/errors.rb +16 -0
- data/lib/net/ssh/proxy/http.rb +98 -0
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +67 -0
- data/lib/net/ssh/proxy/socks5.rb +140 -0
- data/lib/net/ssh/service/forward.rb +426 -0
- data/lib/net/ssh/test/channel.rb +147 -0
- data/lib/net/ssh/test/extensions.rb +173 -0
- data/lib/net/ssh/test/kex.rb +46 -0
- data/lib/net/ssh/test/local_packet.rb +53 -0
- data/lib/net/ssh/test/packet.rb +101 -0
- data/lib/net/ssh/test/remote_packet.rb +40 -0
- data/lib/net/ssh/test/script.rb +180 -0
- data/lib/net/ssh/test/socket.rb +65 -0
- data/lib/net/ssh/test.rb +94 -0
- data/lib/net/ssh/transport/algorithms.rb +502 -0
- data/lib/net/ssh/transport/cipher_factory.rb +103 -0
- data/lib/net/ssh/transport/constants.rb +40 -0
- data/lib/net/ssh/transport/ctr.rb +115 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +97 -0
- data/lib/net/ssh/transport/hmac/md5.rb +10 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/none.rb +13 -0
- data/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +47 -0
- data/lib/net/ssh/transport/identity_cipher.rb +57 -0
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
- data/lib/net/ssh/transport/kex.rb +31 -0
- data/lib/net/ssh/transport/key_expander.rb +30 -0
- data/lib/net/ssh/transport/openssl.rb +253 -0
- data/lib/net/ssh/transport/packet_stream.rb +280 -0
- data/lib/net/ssh/transport/server_version.rb +77 -0
- data/lib/net/ssh/transport/session.rb +354 -0
- data/lib/net/ssh/transport/state.rb +208 -0
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +68 -0
- data/lib/net/ssh.rb +330 -0
- data/net-ssh-public_cert.pem +20 -0
- data/net-ssh.gemspec +44 -0
- data/support/ssh_tunnel_bug.rb +65 -0
- metadata +271 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
module Net
|
2
|
+
module SSH
|
3
|
+
module Transport
|
4
|
+
module Constants
|
5
|
+
#--
|
6
|
+
# Transport layer generic messages
|
7
|
+
#++
|
8
|
+
|
9
|
+
DISCONNECT = 1
|
10
|
+
IGNORE = 2
|
11
|
+
UNIMPLEMENTED = 3
|
12
|
+
DEBUG = 4
|
13
|
+
SERVICE_REQUEST = 5
|
14
|
+
SERVICE_ACCEPT = 6
|
15
|
+
|
16
|
+
#--
|
17
|
+
# Algorithm negotiation messages
|
18
|
+
#++
|
19
|
+
|
20
|
+
KEXINIT = 20
|
21
|
+
NEWKEYS = 21
|
22
|
+
|
23
|
+
#--
|
24
|
+
# Key exchange method specific messages
|
25
|
+
#++
|
26
|
+
|
27
|
+
KEXDH_INIT = 30
|
28
|
+
KEXDH_REPLY = 31
|
29
|
+
|
30
|
+
KEXECDH_INIT = 30
|
31
|
+
KEXECDH_REPLY = 31
|
32
|
+
|
33
|
+
KEXDH_GEX_GROUP = 31
|
34
|
+
KEXDH_GEX_INIT = 32
|
35
|
+
KEXDH_GEX_REPLY = 33
|
36
|
+
KEXDH_GEX_REQUEST = 34
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
module Net::SSH::Transport
|
5
|
+
#:nodoc:
|
6
|
+
class OpenSSLAESCTR < SimpleDelegator
|
7
|
+
def initialize(original)
|
8
|
+
super
|
9
|
+
@was_reset = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def block_size
|
13
|
+
16
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.block_size
|
17
|
+
16
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset
|
21
|
+
@was_reset = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def iv=(iv_s)
|
25
|
+
super unless @was_reset
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#:nodoc:
|
30
|
+
# Pure-Ruby implementation of Stateful Decryption Counter(SDCTR) Mode
|
31
|
+
# for Block Ciphers. See RFC4344 for detail.
|
32
|
+
module CTR
|
33
|
+
def self.extended(orig)
|
34
|
+
orig.instance_eval {
|
35
|
+
@remaining = String.new
|
36
|
+
@counter = nil
|
37
|
+
@counter_len = orig.block_size
|
38
|
+
orig.encrypt
|
39
|
+
orig.padding = 0
|
40
|
+
|
41
|
+
singleton_class.send(:alias_method, :_update, :update)
|
42
|
+
singleton_class.send(:private, :_update)
|
43
|
+
singleton_class.send(:undef_method, :update)
|
44
|
+
|
45
|
+
def iv
|
46
|
+
@counter
|
47
|
+
end
|
48
|
+
|
49
|
+
def iv_len
|
50
|
+
block_size
|
51
|
+
end
|
52
|
+
|
53
|
+
def iv=(iv_s)
|
54
|
+
@counter = iv_s if @counter.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
def encrypt
|
58
|
+
# DO NOTHING (always set to "encrypt")
|
59
|
+
end
|
60
|
+
|
61
|
+
def decrypt
|
62
|
+
# DO NOTHING (always set to "encrypt")
|
63
|
+
end
|
64
|
+
|
65
|
+
def padding=(pad)
|
66
|
+
# DO NOTHING (always 0)
|
67
|
+
end
|
68
|
+
|
69
|
+
def reset
|
70
|
+
@remaining = String.new
|
71
|
+
end
|
72
|
+
|
73
|
+
def update(data)
|
74
|
+
@remaining += data
|
75
|
+
|
76
|
+
encrypted = String.new
|
77
|
+
|
78
|
+
offset = 0
|
79
|
+
while (@remaining.bytesize - offset) >= block_size
|
80
|
+
encrypted += xor!(@remaining.slice(offset, block_size),
|
81
|
+
_update(@counter))
|
82
|
+
increment_counter!
|
83
|
+
offset += block_size
|
84
|
+
end
|
85
|
+
@remaining = @remaining.slice(offset..-1)
|
86
|
+
|
87
|
+
encrypted
|
88
|
+
end
|
89
|
+
|
90
|
+
def final
|
91
|
+
s = @remaining.empty? ? '' : xor!(@remaining, _update(@counter))
|
92
|
+
@remaining = String.new
|
93
|
+
s
|
94
|
+
end
|
95
|
+
|
96
|
+
def xor!(s1, s2)
|
97
|
+
s = []
|
98
|
+
s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a ^ b) }
|
99
|
+
s.pack('Q*')
|
100
|
+
end
|
101
|
+
singleton_class.send(:private, :xor!)
|
102
|
+
|
103
|
+
def increment_counter!
|
104
|
+
c = @counter_len
|
105
|
+
while ((c -= 1) > 0)
|
106
|
+
if @counter.setbyte(c, (@counter.getbyte(c) + 1) & 0xff) != 0
|
107
|
+
break
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
singleton_class.send(:private, :increment_counter!)
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'openssl/digest'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
|
+
module Transport
|
7
|
+
module HMAC
|
8
|
+
# The base class of all OpenSSL-based HMAC algorithm wrappers.
|
9
|
+
class Abstract
|
10
|
+
class <<self
|
11
|
+
def etm(*v)
|
12
|
+
@etm = false if !defined?(@etm)
|
13
|
+
if v.empty?
|
14
|
+
@etm = superclass.etm if @etm.nil? && superclass.respond_to?(:etm)
|
15
|
+
return @etm
|
16
|
+
elsif v.length == 1
|
17
|
+
@etm = v.first
|
18
|
+
else
|
19
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def key_length(*v)
|
24
|
+
@key_length = nil if !defined?(@key_length)
|
25
|
+
if v.empty?
|
26
|
+
@key_length = superclass.key_length if @key_length.nil? && superclass.respond_to?(:key_length)
|
27
|
+
return @key_length
|
28
|
+
elsif v.length == 1
|
29
|
+
@key_length = v.first
|
30
|
+
else
|
31
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def mac_length(*v)
|
36
|
+
@mac_length = nil if !defined?(@mac_length)
|
37
|
+
if v.empty?
|
38
|
+
@mac_length = superclass.mac_length if @mac_length.nil? && superclass.respond_to?(:mac_length)
|
39
|
+
return @mac_length
|
40
|
+
elsif v.length == 1
|
41
|
+
@mac_length = v.first
|
42
|
+
else
|
43
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def digest_class(*v)
|
48
|
+
@digest_class = nil if !defined?(@digest_class)
|
49
|
+
if v.empty?
|
50
|
+
@digest_class = superclass.digest_class if @digest_class.nil? && superclass.respond_to?(:digest_class)
|
51
|
+
return @digest_class
|
52
|
+
elsif v.length == 1
|
53
|
+
@digest_class = v.first
|
54
|
+
else
|
55
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def etm
|
61
|
+
self.class.etm
|
62
|
+
end
|
63
|
+
|
64
|
+
def key_length
|
65
|
+
self.class.key_length
|
66
|
+
end
|
67
|
+
|
68
|
+
def mac_length
|
69
|
+
self.class.mac_length
|
70
|
+
end
|
71
|
+
|
72
|
+
def digest_class
|
73
|
+
self.class.digest_class
|
74
|
+
end
|
75
|
+
|
76
|
+
# The key in use for this instance.
|
77
|
+
attr_reader :key
|
78
|
+
|
79
|
+
def initialize(key=nil)
|
80
|
+
self.key = key
|
81
|
+
end
|
82
|
+
|
83
|
+
# Sets the key to the given value, truncating it so that it is the correct
|
84
|
+
# length.
|
85
|
+
def key=(value)
|
86
|
+
@key = value ? value.to_s[0,key_length] : nil
|
87
|
+
end
|
88
|
+
|
89
|
+
# Compute the HMAC digest for the given data string.
|
90
|
+
def digest(data)
|
91
|
+
OpenSSL::HMAC.digest(digest_class.new, key, data)[0,mac_length]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
2
|
+
|
3
|
+
module Net::SSH::Transport::HMAC
|
4
|
+
# The RIPEMD-160 HMAC algorithm. This has a mac and key length of 20, and
|
5
|
+
# uses the RIPEMD-160 digest algorithm.
|
6
|
+
class RIPEMD160 < Abstract
|
7
|
+
mac_length 20
|
8
|
+
key_length 20
|
9
|
+
digest_class OpenSSL::Digest::RIPEMD160
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
2
|
+
|
3
|
+
module Net::SSH::Transport::HMAC
|
4
|
+
# The SHA1 HMAC algorithm. This has a mac and key length of 20, and
|
5
|
+
# uses the SHA1 digest algorithm.
|
6
|
+
class SHA1 < Abstract
|
7
|
+
mac_length 20
|
8
|
+
key_length 20
|
9
|
+
digest_class OpenSSL::Digest::SHA1
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
2
|
+
|
3
|
+
module Net::SSH::Transport::HMAC
|
4
|
+
# The SHA-256 HMAC algorithm. This has a mac and key length of 32, and
|
5
|
+
# uses the SHA-256 digest algorithm.
|
6
|
+
class SHA2_256 < Abstract
|
7
|
+
mac_length 32
|
8
|
+
key_length 32
|
9
|
+
digest_class OpenSSL::Digest::SHA256
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
2
|
+
|
3
|
+
module Net::SSH::Transport::HMAC
|
4
|
+
# The SHA-256 Encrypt-Then-Mac HMAC algorithm. This has a mac and
|
5
|
+
# key length of 32, and uses the SHA-256 digest algorithm.
|
6
|
+
class SHA2_256_Etm < Abstract
|
7
|
+
etm true
|
8
|
+
mac_length 32
|
9
|
+
key_length 32
|
10
|
+
digest_class OpenSSL::Digest::SHA256
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
2
|
+
|
3
|
+
module Net::SSH::Transport::HMAC
|
4
|
+
# The SHA-512 HMAC algorithm. This has a mac and key length of 64, and
|
5
|
+
# uses the SHA-512 digest algorithm.
|
6
|
+
class SHA2_512 < Abstract
|
7
|
+
mac_length 64
|
8
|
+
key_length 64
|
9
|
+
digest_class OpenSSL::Digest::SHA512
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
2
|
+
|
3
|
+
module Net::SSH::Transport::HMAC
|
4
|
+
# The SHA-512 Encrypt-Then-Mac HMAC algorithm. This has a mac and
|
5
|
+
# key length of 64, and uses the SHA-512 digest algorithm.
|
6
|
+
class SHA2_512_Etm < Abstract
|
7
|
+
etm true
|
8
|
+
mac_length 64
|
9
|
+
key_length 64
|
10
|
+
digest_class OpenSSL::Digest::SHA512
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'net/ssh/transport/key_expander'
|
2
|
+
require 'net/ssh/transport/hmac/md5'
|
3
|
+
require 'net/ssh/transport/hmac/md5_96'
|
4
|
+
require 'net/ssh/transport/hmac/sha1'
|
5
|
+
require 'net/ssh/transport/hmac/sha1_96'
|
6
|
+
require 'net/ssh/transport/hmac/sha2_256'
|
7
|
+
require 'net/ssh/transport/hmac/sha2_256_96'
|
8
|
+
require 'net/ssh/transport/hmac/sha2_512'
|
9
|
+
require 'net/ssh/transport/hmac/sha2_512_96'
|
10
|
+
require 'net/ssh/transport/hmac/sha2_256_etm'
|
11
|
+
require 'net/ssh/transport/hmac/sha2_512_etm'
|
12
|
+
require 'net/ssh/transport/hmac/ripemd160'
|
13
|
+
require 'net/ssh/transport/hmac/none'
|
14
|
+
|
15
|
+
# Implements a simple factory interface for fetching hmac implementations, or
|
16
|
+
# for finding the key lengths for hmac implementations.s
|
17
|
+
module Net::SSH::Transport::HMAC
|
18
|
+
# The mapping of SSH hmac algorithms to their implementations
|
19
|
+
MAP = {
|
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
|
+
'hmac-sha2-256-etm@openssh.com' => SHA2_256_Etm,
|
29
|
+
'hmac-sha2-512-etm@openssh.com' => SHA2_512_Etm,
|
30
|
+
'hmac-ripemd160' => RIPEMD160,
|
31
|
+
'hmac-ripemd160@openssh.com' => RIPEMD160,
|
32
|
+
'none' => None
|
33
|
+
}
|
34
|
+
|
35
|
+
# Retrieves a new hmac instance of the given SSH type (+name+). If +key+ is
|
36
|
+
# given, the new instance will be initialized with that key.
|
37
|
+
def self.get(name, key="", parameters = {})
|
38
|
+
impl = MAP[name] or raise ArgumentError, "hmac not found: #{name.inspect}"
|
39
|
+
impl.new(Net::SSH::Transport::KeyExpander.expand_key(impl.key_length, key, parameters))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Retrieves the key length for the hmac of the given SSH type (+name+).
|
43
|
+
def self.key_length(name)
|
44
|
+
impl = MAP[name] or raise ArgumentError, "hmac not found: #{name.inspect}"
|
45
|
+
impl.key_length
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Net
|
2
|
+
module SSH
|
3
|
+
module Transport
|
4
|
+
# A cipher that does nothing but pass the data through, unchanged. This
|
5
|
+
# keeps things in the code nice and clean when a cipher has not yet been
|
6
|
+
# determined (i.e., during key exchange).
|
7
|
+
class IdentityCipher
|
8
|
+
class <<self
|
9
|
+
# A default block size of 8 is required by the SSH2 protocol.
|
10
|
+
def block_size
|
11
|
+
8
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns an arbitrary integer.
|
15
|
+
def iv_len
|
16
|
+
4
|
17
|
+
end
|
18
|
+
|
19
|
+
# Does nothing. Returns self.
|
20
|
+
def encrypt
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# Does nothing. Returns self.
|
25
|
+
def decrypt
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Passes its single argument through unchanged.
|
30
|
+
def update(text)
|
31
|
+
text
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the empty string.
|
35
|
+
def final
|
36
|
+
""
|
37
|
+
end
|
38
|
+
|
39
|
+
# The name of this cipher, which is "identity".
|
40
|
+
def name
|
41
|
+
"identity"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Does nothing. Returns nil.
|
45
|
+
def iv=(v)
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# Does nothing. Returns self.
|
50
|
+
def reset
|
51
|
+
self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'net/ssh/buffer'
|
2
|
+
require 'net/ssh/errors'
|
3
|
+
require 'net/ssh/loggable'
|
4
|
+
require 'net/ssh/transport/openssl'
|
5
|
+
require 'net/ssh/transport/constants'
|
6
|
+
|
7
|
+
module Net
|
8
|
+
module SSH
|
9
|
+
module Transport
|
10
|
+
module Kex
|
11
|
+
# Abstract class that implement Diffie-Hellman Key Exchange
|
12
|
+
# See https://tools.ietf.org/html/rfc4253#page-21
|
13
|
+
class Abstract
|
14
|
+
include Loggable
|
15
|
+
include Constants
|
16
|
+
|
17
|
+
attr_reader :algorithms
|
18
|
+
attr_reader :connection
|
19
|
+
attr_reader :data
|
20
|
+
attr_reader :dh
|
21
|
+
|
22
|
+
# Create a new instance of the Diffie-Hellman Key Exchange algorithm.
|
23
|
+
# The Diffie-Hellman (DH) key exchange provides a shared secret that
|
24
|
+
# cannot be determined by either party alone. The key exchange is
|
25
|
+
# combined with a signature with the host key to provide host
|
26
|
+
# authentication.
|
27
|
+
def initialize(algorithms, connection, data)
|
28
|
+
@algorithms = algorithms
|
29
|
+
@connection = connection
|
30
|
+
|
31
|
+
@data = data.dup
|
32
|
+
@dh = generate_key
|
33
|
+
@logger = @data.delete(:logger)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Perform the key-exchange for the given session, with the given
|
37
|
+
# data. This method will return a hash consisting of the
|
38
|
+
# following keys:
|
39
|
+
#
|
40
|
+
# * :session_id
|
41
|
+
# * :server_key
|
42
|
+
# * :shared_secret
|
43
|
+
# * :hashing_algorithm
|
44
|
+
#
|
45
|
+
# The caller is expected to be able to understand how to use these
|
46
|
+
# deliverables.
|
47
|
+
def exchange_keys
|
48
|
+
result = send_kexinit
|
49
|
+
verify_server_key(result[:server_key])
|
50
|
+
session_id = verify_signature(result)
|
51
|
+
confirm_newkeys
|
52
|
+
|
53
|
+
{
|
54
|
+
session_id: session_id,
|
55
|
+
server_key: result[:server_key],
|
56
|
+
shared_secret: result[:shared_secret],
|
57
|
+
hashing_algorithm: digester
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def digester
|
62
|
+
raise NotImplementedError, 'abstract class: digester not implemented'
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def matching?(key_ssh_type, host_key_alg)
|
68
|
+
return true if key_ssh_type == host_key_alg
|
69
|
+
return true if key_ssh_type == 'ssh-rsa' && ['rsa-sha2-512', 'rsa-sha2-256'].include?(host_key_alg)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Verify that the given key is of the expected type, and that it
|
73
|
+
# really is the key for the session's host. Raise Net::SSH::Exception
|
74
|
+
# if it is not.
|
75
|
+
def verify_server_key(key) #:nodoc:
|
76
|
+
unless matching?(key.ssh_type, algorithms.host_key)
|
77
|
+
raise Net::SSH::Exception, "host key algorithm mismatch '#{key.ssh_type}' != '#{algorithms.host_key}'"
|
78
|
+
end
|
79
|
+
|
80
|
+
blob, fingerprint = generate_key_fingerprint(key)
|
81
|
+
|
82
|
+
unless connection.host_key_verifier.verify(key: key, key_blob: blob, fingerprint: fingerprint, session: connection)
|
83
|
+
raise Net::SSH::Exception, 'host key verification failed'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def generate_key_fingerprint(key)
|
88
|
+
blob = Net::SSH::Buffer.from(:key, key).to_s
|
89
|
+
|
90
|
+
fingerprint = Net::SSH::Authentication::PubKeyFingerprint.fingerprint(blob, @connection.options[:fingerprint_hash] || 'SHA256')
|
91
|
+
|
92
|
+
[blob, fingerprint]
|
93
|
+
rescue StandardError => e
|
94
|
+
[nil, "(could not generate fingerprint: #{e.message})"]
|
95
|
+
end
|
96
|
+
|
97
|
+
# Verify the signature that was received. Raise Net::SSH::Exception
|
98
|
+
# if the signature could not be verified. Otherwise, return the new
|
99
|
+
# session-id.
|
100
|
+
def verify_signature(result) #:nodoc:
|
101
|
+
response = build_signature_buffer(result)
|
102
|
+
|
103
|
+
hash = digester.digest(response.to_s)
|
104
|
+
|
105
|
+
server_key = result[:server_key]
|
106
|
+
server_sig = result[:server_sig]
|
107
|
+
unless connection.host_key_verifier.verify_signature { server_key.ssh_do_verify(server_sig, hash, host_key: algorithms.host_key) }
|
108
|
+
raise Net::SSH::Exception, 'could not verify server signature'
|
109
|
+
end
|
110
|
+
|
111
|
+
hash
|
112
|
+
end
|
113
|
+
|
114
|
+
# Send the NEWKEYS message, and expect the NEWKEYS message in
|
115
|
+
# reply.
|
116
|
+
def confirm_newkeys #:nodoc:
|
117
|
+
# send own NEWKEYS message first (the wodSSHServer won't send first)
|
118
|
+
response = Net::SSH::Buffer.new
|
119
|
+
response.write_byte(NEWKEYS)
|
120
|
+
connection.send_message(response)
|
121
|
+
|
122
|
+
# wait for the server's NEWKEYS message
|
123
|
+
buffer = connection.next_message
|
124
|
+
raise Net::SSH::Exception, 'expected NEWKEYS' unless buffer.type == NEWKEYS
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|