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.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +93 -0
  3. data/.gitignore +13 -0
  4. data/.rubocop.yml +21 -0
  5. data/.rubocop_todo.yml +1074 -0
  6. data/.travis.yml +51 -0
  7. data/CHANGES.txt +698 -0
  8. data/Gemfile +13 -0
  9. data/Gemfile.noed25519 +12 -0
  10. data/ISSUE_TEMPLATE.md +30 -0
  11. data/LICENSE.txt +19 -0
  12. data/Manifest +132 -0
  13. data/README.md +287 -0
  14. data/Rakefile +105 -0
  15. data/THANKS.txt +110 -0
  16. data/appveyor.yml +58 -0
  17. data/lib/net/ssh/authentication/agent.rb +284 -0
  18. data/lib/net/ssh/authentication/certificate.rb +183 -0
  19. data/lib/net/ssh/authentication/constants.rb +20 -0
  20. data/lib/net/ssh/authentication/ed25519.rb +185 -0
  21. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  22. data/lib/net/ssh/authentication/key_manager.rb +297 -0
  23. data/lib/net/ssh/authentication/methods/abstract.rb +69 -0
  24. data/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
  25. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
  26. data/lib/net/ssh/authentication/methods/none.rb +34 -0
  27. data/lib/net/ssh/authentication/methods/password.rb +80 -0
  28. data/lib/net/ssh/authentication/methods/publickey.rb +95 -0
  29. data/lib/net/ssh/authentication/pageant.rb +497 -0
  30. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  31. data/lib/net/ssh/authentication/session.rb +163 -0
  32. data/lib/net/ssh/buffer.rb +434 -0
  33. data/lib/net/ssh/buffered_io.rb +202 -0
  34. data/lib/net/ssh/config.rb +406 -0
  35. data/lib/net/ssh/connection/channel.rb +695 -0
  36. data/lib/net/ssh/connection/constants.rb +33 -0
  37. data/lib/net/ssh/connection/event_loop.rb +123 -0
  38. data/lib/net/ssh/connection/keepalive.rb +59 -0
  39. data/lib/net/ssh/connection/session.rb +712 -0
  40. data/lib/net/ssh/connection/term.rb +180 -0
  41. data/lib/net/ssh/errors.rb +106 -0
  42. data/lib/net/ssh/key_factory.rb +218 -0
  43. data/lib/net/ssh/known_hosts.rb +264 -0
  44. data/lib/net/ssh/loggable.rb +62 -0
  45. data/lib/net/ssh/packet.rb +106 -0
  46. data/lib/net/ssh/prompt.rb +62 -0
  47. data/lib/net/ssh/proxy/command.rb +123 -0
  48. data/lib/net/ssh/proxy/errors.rb +16 -0
  49. data/lib/net/ssh/proxy/http.rb +98 -0
  50. data/lib/net/ssh/proxy/https.rb +50 -0
  51. data/lib/net/ssh/proxy/jump.rb +54 -0
  52. data/lib/net/ssh/proxy/socks4.rb +67 -0
  53. data/lib/net/ssh/proxy/socks5.rb +140 -0
  54. data/lib/net/ssh/service/forward.rb +426 -0
  55. data/lib/net/ssh/test/channel.rb +147 -0
  56. data/lib/net/ssh/test/extensions.rb +173 -0
  57. data/lib/net/ssh/test/kex.rb +46 -0
  58. data/lib/net/ssh/test/local_packet.rb +53 -0
  59. data/lib/net/ssh/test/packet.rb +101 -0
  60. data/lib/net/ssh/test/remote_packet.rb +40 -0
  61. data/lib/net/ssh/test/script.rb +180 -0
  62. data/lib/net/ssh/test/socket.rb +65 -0
  63. data/lib/net/ssh/test.rb +94 -0
  64. data/lib/net/ssh/transport/algorithms.rb +502 -0
  65. data/lib/net/ssh/transport/cipher_factory.rb +103 -0
  66. data/lib/net/ssh/transport/constants.rb +40 -0
  67. data/lib/net/ssh/transport/ctr.rb +115 -0
  68. data/lib/net/ssh/transport/hmac/abstract.rb +97 -0
  69. data/lib/net/ssh/transport/hmac/md5.rb +10 -0
  70. data/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
  71. data/lib/net/ssh/transport/hmac/none.rb +13 -0
  72. data/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
  73. data/lib/net/ssh/transport/hmac/sha1.rb +11 -0
  74. data/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
  75. data/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
  76. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
  77. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  78. data/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
  79. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
  80. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  81. data/lib/net/ssh/transport/hmac.rb +47 -0
  82. data/lib/net/ssh/transport/identity_cipher.rb +57 -0
  83. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  84. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  85. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  86. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  87. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
  88. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  89. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
  90. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
  92. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
  93. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
  94. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
  95. data/lib/net/ssh/transport/kex.rb +31 -0
  96. data/lib/net/ssh/transport/key_expander.rb +30 -0
  97. data/lib/net/ssh/transport/openssl.rb +253 -0
  98. data/lib/net/ssh/transport/packet_stream.rb +280 -0
  99. data/lib/net/ssh/transport/server_version.rb +77 -0
  100. data/lib/net/ssh/transport/session.rb +354 -0
  101. data/lib/net/ssh/transport/state.rb +208 -0
  102. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  103. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  104. data/lib/net/ssh/verifiers/always.rb +58 -0
  105. data/lib/net/ssh/verifiers/never.rb +19 -0
  106. data/lib/net/ssh/version.rb +68 -0
  107. data/lib/net/ssh.rb +330 -0
  108. data/net-ssh-public_cert.pem +20 -0
  109. data/net-ssh.gemspec +44 -0
  110. data/support/ssh_tunnel_bug.rb +65 -0
  111. 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,10 @@
1
+ require 'net/ssh/transport/hmac/abstract'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+ # The MD5 HMAC algorithm.
5
+ class MD5 < Abstract
6
+ mac_length 16
7
+ key_length 16
8
+ digest_class OpenSSL::Digest::MD5
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require 'net/ssh/transport/hmac/md5'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+ # The MD5-96 HMAC algorithm. This returns only the first 12 bytes of
5
+ # the digest.
6
+ class MD5_96 < MD5
7
+ mac_length 12
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ require 'net/ssh/transport/hmac/abstract'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+ # The "none" algorithm. This has a key and mac length of 0.
5
+ class None < Abstract
6
+ key_length 0
7
+ mac_length 0
8
+
9
+ def digest(data)
10
+ ""
11
+ end
12
+ end
13
+ 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,9 @@
1
+ require 'net/ssh/transport/hmac/sha1'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+ # The SHA1-96 HMAC algorithm. This returns only the first 12 bytes of
5
+ # the digest.
6
+ class SHA1_96 < SHA1
7
+ mac_length 12
8
+ end
9
+ 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,9 @@
1
+ require 'net/ssh/transport/hmac/abstract'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+ # The SHA256-96 HMAC algorithm. This returns only the first 12 bytes of
5
+ # the digest.
6
+ class SHA2_256_96 < SHA2_256
7
+ mac_length 12
8
+ end
9
+ 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,9 @@
1
+ require 'net/ssh/transport/hmac/abstract'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+ # The SHA2-512-96 HMAC algorithm. This returns only the first 12 bytes of
5
+ # the digest.
6
+ class SHA2_512_96 < SHA2_512
7
+ mac_length 12
8
+ end
9
+ 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