minmb-net-ssh 2.5.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.
- data/CHANGELOG.rdoc +291 -0
- data/Manifest +132 -0
- data/README.rdoc +184 -0
- data/Rakefile +86 -0
- data/Rudyfile +96 -0
- data/THANKS.rdoc +19 -0
- data/lib/net/ssh.rb +223 -0
- data/lib/net/ssh/authentication/agent.rb +23 -0
- data/lib/net/ssh/authentication/agent/java_pageant.rb +85 -0
- data/lib/net/ssh/authentication/agent/socket.rb +170 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +253 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +75 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +70 -0
- data/lib/net/ssh/authentication/methods/password.rb +43 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -0
- data/lib/net/ssh/authentication/pageant.rb +301 -0
- data/lib/net/ssh/authentication/session.rb +154 -0
- data/lib/net/ssh/buffer.rb +350 -0
- data/lib/net/ssh/buffered_io.rb +207 -0
- data/lib/net/ssh/config.rb +207 -0
- data/lib/net/ssh/connection/channel.rb +630 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/session.rb +603 -0
- data/lib/net/ssh/connection/term.rb +178 -0
- data/lib/net/ssh/errors.rb +88 -0
- data/lib/net/ssh/key_factory.rb +107 -0
- data/lib/net/ssh/known_hosts.rb +141 -0
- data/lib/net/ssh/loggable.rb +61 -0
- data/lib/net/ssh/packet.rb +102 -0
- data/lib/net/ssh/prompt.rb +93 -0
- data/lib/net/ssh/proxy/command.rb +75 -0
- data/lib/net/ssh/proxy/errors.rb +14 -0
- data/lib/net/ssh/proxy/http.rb +94 -0
- data/lib/net/ssh/proxy/socks4.rb +70 -0
- data/lib/net/ssh/proxy/socks5.rb +142 -0
- data/lib/net/ssh/ruby_compat.rb +77 -0
- data/lib/net/ssh/service/forward.rb +327 -0
- data/lib/net/ssh/test.rb +89 -0
- data/lib/net/ssh/test/channel.rb +129 -0
- data/lib/net/ssh/test/extensions.rb +152 -0
- data/lib/net/ssh/test/kex.rb +44 -0
- data/lib/net/ssh/test/local_packet.rb +51 -0
- data/lib/net/ssh/test/packet.rb +81 -0
- data/lib/net/ssh/test/remote_packet.rb +38 -0
- data/lib/net/ssh/test/script.rb +157 -0
- data/lib/net/ssh/test/socket.rb +64 -0
- data/lib/net/ssh/transport/algorithms.rb +407 -0
- data/lib/net/ssh/transport/cipher_factory.rb +106 -0
- data/lib/net/ssh/transport/constants.rb +32 -0
- data/lib/net/ssh/transport/ctr.rb +95 -0
- data/lib/net/ssh/transport/hmac.rb +45 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +79 -0
- data/lib/net/ssh/transport/hmac/md5.rb +12 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
- data/lib/net/ssh/transport/hmac/none.rb +15 -0
- data/lib/net/ssh/transport/hmac/ripemd160.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
- data/lib/net/ssh/transport/hmac/sha2_256.rb +15 -0
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +14 -0
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +13 -0
- data/lib/net/ssh/transport/identity_cipher.rb +55 -0
- data/lib/net/ssh/transport/kex.rb +28 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +44 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +216 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +80 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +15 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +93 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +13 -0
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +13 -0
- data/lib/net/ssh/transport/key_expander.rb +26 -0
- data/lib/net/ssh/transport/openssl.rb +237 -0
- data/lib/net/ssh/transport/packet_stream.rb +235 -0
- data/lib/net/ssh/transport/server_version.rb +71 -0
- data/lib/net/ssh/transport/session.rb +278 -0
- data/lib/net/ssh/transport/state.rb +206 -0
- data/lib/net/ssh/verifiers/lenient.rb +30 -0
- data/lib/net/ssh/verifiers/null.rb +12 -0
- data/lib/net/ssh/verifiers/strict.rb +53 -0
- data/lib/net/ssh/version.rb +62 -0
- data/net-ssh.gemspec +164 -0
- data/setup.rb +1585 -0
- data/support/arcfour_check.rb +20 -0
- data/support/ssh_tunnel_bug.rb +65 -0
- data/test/authentication/methods/common.rb +28 -0
- data/test/authentication/methods/test_abstract.rb +51 -0
- data/test/authentication/methods/test_hostbased.rb +114 -0
- data/test/authentication/methods/test_keyboard_interactive.rb +100 -0
- data/test/authentication/methods/test_password.rb +52 -0
- data/test/authentication/methods/test_publickey.rb +148 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +218 -0
- data/test/authentication/test_session.rb +106 -0
- data/test/common.rb +107 -0
- data/test/configs/eqsign +3 -0
- data/test/configs/exact_match +8 -0
- data/test/configs/host_plus +10 -0
- data/test/configs/multihost +4 -0
- data/test/configs/wild_cards +14 -0
- data/test/connection/test_channel.rb +467 -0
- data/test/connection/test_session.rb +488 -0
- data/test/known_hosts/github +1 -0
- data/test/test_all.rb +9 -0
- data/test/test_buffer.rb +426 -0
- data/test/test_buffered_io.rb +63 -0
- data/test/test_config.rb +120 -0
- data/test/test_key_factory.rb +121 -0
- data/test/test_known_hosts.rb +13 -0
- data/test/transport/hmac/test_md5.rb +39 -0
- data/test/transport/hmac/test_md5_96.rb +25 -0
- data/test/transport/hmac/test_none.rb +34 -0
- data/test/transport/hmac/test_ripemd160.rb +34 -0
- data/test/transport/hmac/test_sha1.rb +34 -0
- data/test/transport/hmac/test_sha1_96.rb +25 -0
- data/test/transport/hmac/test_sha2_256.rb +35 -0
- data/test/transport/hmac/test_sha2_256_96.rb +25 -0
- data/test/transport/hmac/test_sha2_512.rb +35 -0
- data/test/transport/hmac/test_sha2_512_96.rb +25 -0
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +13 -0
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +33 -0
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +161 -0
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +37 -0
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +37 -0
- data/test/transport/test_algorithms.rb +330 -0
- data/test/transport/test_cipher_factory.rb +441 -0
- data/test/transport/test_hmac.rb +34 -0
- data/test/transport/test_identity_cipher.rb +40 -0
- data/test/transport/test_packet_stream.rb +1745 -0
- data/test/transport/test_server_version.rb +78 -0
- data/test/transport/test_session.rb +315 -0
- data/test/transport/test_state.rb +179 -0
- metadata +208 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
|
2
|
+
|
|
3
|
+
if defined?(OpenSSL::Digest::SHA256) # need openssl support
|
|
4
|
+
module Net::SSH::Transport::HMAC
|
|
5
|
+
|
|
6
|
+
# The SHA-256 HMAC algorithm. This has a mac and key length of 32, and
|
|
7
|
+
# uses the SHA-256 digest algorithm.
|
|
8
|
+
class SHA2_256 < Abstract
|
|
9
|
+
mac_length 32
|
|
10
|
+
key_length 32
|
|
11
|
+
digest_class OpenSSL::Digest::SHA256
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
|
2
|
+
|
|
3
|
+
module Net::SSH::Transport::HMAC
|
|
4
|
+
|
|
5
|
+
if defined?(SHA2_256) # need openssl support
|
|
6
|
+
# The SHA256-96 HMAC algorithm. This returns only the first 12 bytes of
|
|
7
|
+
# the digest.
|
|
8
|
+
class SHA2_256_96 < SHA2_256
|
|
9
|
+
mac_length 12
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
|
2
|
+
|
|
3
|
+
module Net::SSH::Transport::HMAC
|
|
4
|
+
|
|
5
|
+
if defined?(OpenSSL::Digest::SHA512) # need openssl support
|
|
6
|
+
# The SHA-512 HMAC algorithm. This has a mac and key length of 64, and
|
|
7
|
+
# uses the SHA-512 digest algorithm.
|
|
8
|
+
class SHA2_512 < Abstract
|
|
9
|
+
mac_length 64
|
|
10
|
+
key_length 64
|
|
11
|
+
digest_class OpenSSL::Digest::SHA512
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
|
2
|
+
|
|
3
|
+
module Net::SSH::Transport::HMAC
|
|
4
|
+
|
|
5
|
+
if defined?(SHA2_512) # need openssl support
|
|
6
|
+
# The SHA2-512-96 HMAC algorithm. This returns only the first 12 bytes of
|
|
7
|
+
# the digest.
|
|
8
|
+
class SHA2_512_96 < SHA2_512
|
|
9
|
+
mac_length 12
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Net; module SSH; module Transport
|
|
2
|
+
|
|
3
|
+
# A cipher that does nothing but pass the data through, unchanged. This
|
|
4
|
+
# keeps things in the code nice and clean when a cipher has not yet been
|
|
5
|
+
# determined (i.e., during key exchange).
|
|
6
|
+
class IdentityCipher
|
|
7
|
+
class <<self
|
|
8
|
+
# A default block size of 8 is required by the SSH2 protocol.
|
|
9
|
+
def block_size
|
|
10
|
+
8
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Returns an arbitrary integer.
|
|
14
|
+
def iv_len
|
|
15
|
+
4
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Does nothing. Returns self.
|
|
19
|
+
def encrypt
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Does nothing. Returns self.
|
|
24
|
+
def decrypt
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Passes its single argument through unchanged.
|
|
29
|
+
def update(text)
|
|
30
|
+
text
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the empty string.
|
|
34
|
+
def final
|
|
35
|
+
""
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The name of this cipher, which is "identity".
|
|
39
|
+
def name
|
|
40
|
+
"identity"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Does nothing. Returns nil.
|
|
44
|
+
def iv=(v)
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Does nothing. Returns self.
|
|
49
|
+
def reset
|
|
50
|
+
self
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end; end; end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
|
|
2
|
+
require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
|
|
3
|
+
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
|
|
4
|
+
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha256'
|
|
5
|
+
|
|
6
|
+
module Net::SSH::Transport
|
|
7
|
+
module Kex
|
|
8
|
+
# Maps the supported key-exchange algorithms as named by the SSH protocol
|
|
9
|
+
# to their corresponding implementors.
|
|
10
|
+
MAP = {
|
|
11
|
+
'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1,
|
|
12
|
+
'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1,
|
|
13
|
+
'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
|
|
14
|
+
}
|
|
15
|
+
if defined?(DiffieHellmanGroupExchangeSHA256)
|
|
16
|
+
MAP['diffie-hellman-group-exchange-sha256'] = DiffieHellmanGroupExchangeSHA256
|
|
17
|
+
end
|
|
18
|
+
if defined?(OpenSSL::PKey::EC)
|
|
19
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
|
|
20
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp384'
|
|
21
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp521'
|
|
22
|
+
|
|
23
|
+
MAP['ecdh-sha2-nistp256'] = EcdhSHA2NistP256
|
|
24
|
+
MAP['ecdh-sha2-nistp384'] = EcdhSHA2NistP384
|
|
25
|
+
MAP['ecdh-sha2-nistp521'] = EcdhSHA2NistP521
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
|
|
2
|
+
|
|
3
|
+
module Net; module SSH; module Transport; module Kex
|
|
4
|
+
|
|
5
|
+
# A key-exchange service implementing the "diffie-hellman-group14-sha1"
|
|
6
|
+
# key-exchange algorithm. (defined in RFC 4253)
|
|
7
|
+
class DiffieHellmanGroup14SHA1 < DiffieHellmanGroup1SHA1
|
|
8
|
+
include Constants, Loggable
|
|
9
|
+
|
|
10
|
+
# The value of 'P', as a string, in hexadecimal
|
|
11
|
+
P_s = "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" +
|
|
12
|
+
"C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" +
|
|
13
|
+
"020BBEA6" "3B139B22" "514A0879" "8E3404DD" +
|
|
14
|
+
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" +
|
|
15
|
+
"4FE1356D" "6D51C245" "E485B576" "625E7EC6" +
|
|
16
|
+
"F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" +
|
|
17
|
+
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" +
|
|
18
|
+
"49286651" "ECE45B3D" "C2007CB8" "A163BF05" +
|
|
19
|
+
"98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" +
|
|
20
|
+
"83655D23" "DCA3AD96" "1C62F356" "208552BB" +
|
|
21
|
+
"9ED52907" "7096966D" "670C354E" "4ABC9804" +
|
|
22
|
+
"F1746C08" "CA18217C" "32905E46" "2E36CE3B" +
|
|
23
|
+
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" +
|
|
24
|
+
"B5C55DF0" "6F4C52C9" "DE2BCBF6" "95581718" +
|
|
25
|
+
"3995497C" "EA956AE5" "15D22618" "98FA0510" +
|
|
26
|
+
"15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"
|
|
27
|
+
|
|
28
|
+
# The radix in which P_s represents the value of P
|
|
29
|
+
P_r = 16
|
|
30
|
+
|
|
31
|
+
# The group constant
|
|
32
|
+
G = 2
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def get_p
|
|
37
|
+
OpenSSL::BN.new(P_s, P_r)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def get_g
|
|
41
|
+
G
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end; end; end; end
|
|
@@ -0,0 +1,216 @@
|
|
|
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; module SSH; module Transport; module Kex
|
|
8
|
+
|
|
9
|
+
# A key-exchange service implementing the "diffie-hellman-group1-sha1"
|
|
10
|
+
# key-exchange algorithm.
|
|
11
|
+
class DiffieHellmanGroup1SHA1
|
|
12
|
+
include Constants, Loggable
|
|
13
|
+
|
|
14
|
+
# The value of 'P', as a string, in hexadecimal
|
|
15
|
+
P_s = "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" +
|
|
16
|
+
"C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" +
|
|
17
|
+
"020BBEA6" "3B139B22" "514A0879" "8E3404DD" +
|
|
18
|
+
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" +
|
|
19
|
+
"4FE1356D" "6D51C245" "E485B576" "625E7EC6" +
|
|
20
|
+
"F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" +
|
|
21
|
+
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" +
|
|
22
|
+
"49286651" "ECE65381" "FFFFFFFF" "FFFFFFFF"
|
|
23
|
+
|
|
24
|
+
# The radix in which P_s represents the value of P
|
|
25
|
+
P_r = 16
|
|
26
|
+
|
|
27
|
+
# The group constant
|
|
28
|
+
G = 2
|
|
29
|
+
|
|
30
|
+
attr_reader :p
|
|
31
|
+
attr_reader :g
|
|
32
|
+
attr_reader :digester
|
|
33
|
+
attr_reader :algorithms
|
|
34
|
+
attr_reader :connection
|
|
35
|
+
attr_reader :data
|
|
36
|
+
attr_reader :dh
|
|
37
|
+
|
|
38
|
+
# Create a new instance of the DiffieHellmanGroup1SHA1 algorithm.
|
|
39
|
+
# The data is a Hash of symbols representing information
|
|
40
|
+
# required by this algorithm, which was acquired during earlier
|
|
41
|
+
# processing.
|
|
42
|
+
def initialize(algorithms, connection, data)
|
|
43
|
+
@p = get_p
|
|
44
|
+
@g = get_g
|
|
45
|
+
|
|
46
|
+
@digester = OpenSSL::Digest::SHA1
|
|
47
|
+
@algorithms = algorithms
|
|
48
|
+
@connection = connection
|
|
49
|
+
|
|
50
|
+
@data = data.dup
|
|
51
|
+
@dh = generate_key
|
|
52
|
+
@logger = @data.delete(:logger)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Perform the key-exchange for the given session, with the given
|
|
56
|
+
# data. This method will return a hash consisting of the
|
|
57
|
+
# following keys:
|
|
58
|
+
#
|
|
59
|
+
# * :session_id
|
|
60
|
+
# * :server_key
|
|
61
|
+
# * :shared_secret
|
|
62
|
+
# * :hashing_algorithm
|
|
63
|
+
#
|
|
64
|
+
# The caller is expected to be able to understand how to use these
|
|
65
|
+
# deliverables.
|
|
66
|
+
def exchange_keys
|
|
67
|
+
result = send_kexinit
|
|
68
|
+
verify_server_key(result[:server_key])
|
|
69
|
+
session_id = verify_signature(result)
|
|
70
|
+
confirm_newkeys
|
|
71
|
+
|
|
72
|
+
return { :session_id => session_id,
|
|
73
|
+
:server_key => result[:server_key],
|
|
74
|
+
:shared_secret => result[:shared_secret],
|
|
75
|
+
:hashing_algorithm => digester }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def get_p
|
|
81
|
+
OpenSSL::BN.new(P_s, P_r)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def get_g
|
|
85
|
+
G
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Returns the DH key parameters for the current connection.
|
|
89
|
+
def get_parameters
|
|
90
|
+
[p, g]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Returns the INIT/REPLY constants used by this algorithm.
|
|
94
|
+
def get_message_types
|
|
95
|
+
[KEXDH_INIT, KEXDH_REPLY]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Build the signature buffer to use when verifying a signature from
|
|
99
|
+
# the server.
|
|
100
|
+
def build_signature_buffer(result)
|
|
101
|
+
response = Net::SSH::Buffer.new
|
|
102
|
+
response.write_string data[:client_version_string],
|
|
103
|
+
data[:server_version_string],
|
|
104
|
+
data[:client_algorithm_packet],
|
|
105
|
+
data[:server_algorithm_packet],
|
|
106
|
+
result[:key_blob]
|
|
107
|
+
response.write_bignum dh.pub_key,
|
|
108
|
+
result[:server_dh_pubkey],
|
|
109
|
+
result[:shared_secret]
|
|
110
|
+
response
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Generate a DH key with a private key consisting of the given
|
|
114
|
+
# number of bytes.
|
|
115
|
+
def generate_key #:nodoc:
|
|
116
|
+
dh = OpenSSL::PKey::DH.new
|
|
117
|
+
|
|
118
|
+
dh.p, dh.g = get_parameters
|
|
119
|
+
dh.priv_key = OpenSSL::BN.rand(data[:need_bytes] * 8)
|
|
120
|
+
|
|
121
|
+
dh.generate_key! until dh.valid?
|
|
122
|
+
|
|
123
|
+
dh
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Send the KEXDH_INIT message, and expect the KEXDH_REPLY. Return the
|
|
127
|
+
# resulting buffer.
|
|
128
|
+
#
|
|
129
|
+
# Parse the buffer from a KEXDH_REPLY message, returning a hash of
|
|
130
|
+
# the extracted values.
|
|
131
|
+
def send_kexinit #:nodoc:
|
|
132
|
+
init, reply = get_message_types
|
|
133
|
+
|
|
134
|
+
# send the KEXDH_INIT message
|
|
135
|
+
buffer = Net::SSH::Buffer.from(:byte, init, :bignum, dh.pub_key)
|
|
136
|
+
connection.send_message(buffer)
|
|
137
|
+
|
|
138
|
+
# expect the KEXDH_REPLY message
|
|
139
|
+
buffer = connection.next_message
|
|
140
|
+
raise Net::SSH::Exception, "expected REPLY" unless buffer.type == reply
|
|
141
|
+
|
|
142
|
+
result = Hash.new
|
|
143
|
+
|
|
144
|
+
result[:key_blob] = buffer.read_string
|
|
145
|
+
result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
|
|
146
|
+
result[:server_dh_pubkey] = buffer.read_bignum
|
|
147
|
+
result[:shared_secret] = OpenSSL::BN.new(dh.compute_key(result[:server_dh_pubkey]), 2)
|
|
148
|
+
|
|
149
|
+
sig_buffer = Net::SSH::Buffer.new(buffer.read_string)
|
|
150
|
+
sig_type = sig_buffer.read_string
|
|
151
|
+
if sig_type != algorithms.host_key
|
|
152
|
+
raise Net::SSH::Exception,
|
|
153
|
+
"host key algorithm mismatch for signature " +
|
|
154
|
+
"'#{sig_type}' != '#{algorithms.host_key}'"
|
|
155
|
+
end
|
|
156
|
+
result[:server_sig] = sig_buffer.read_string
|
|
157
|
+
|
|
158
|
+
return result
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Verify that the given key is of the expected type, and that it
|
|
162
|
+
# really is the key for the session's host. Raise Net::SSH::Exception
|
|
163
|
+
# if it is not.
|
|
164
|
+
def verify_server_key(key) #:nodoc:
|
|
165
|
+
if key.ssh_type != algorithms.host_key
|
|
166
|
+
raise Net::SSH::Exception,
|
|
167
|
+
"host key algorithm mismatch " +
|
|
168
|
+
"'#{key.ssh_type}' != '#{algorithms.host_key}'"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
blob, fingerprint = generate_key_fingerprint(key)
|
|
172
|
+
|
|
173
|
+
unless connection.host_key_verifier.verify(:key => key, :key_blob => blob, :fingerprint => fingerprint, :session => connection)
|
|
174
|
+
raise Net::SSH::Exception, "host key verification failed"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def generate_key_fingerprint(key)
|
|
179
|
+
blob = Net::SSH::Buffer.from(:key, key).to_s
|
|
180
|
+
fingerprint = OpenSSL::Digest::MD5.hexdigest(blob).scan(/../).join(":")
|
|
181
|
+
|
|
182
|
+
[blob, fingerprint]
|
|
183
|
+
rescue ::Exception => e
|
|
184
|
+
[nil, "(could not generate fingerprint: #{e.message})"]
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Verify the signature that was received. Raise Net::SSH::Exception
|
|
188
|
+
# if the signature could not be verified. Otherwise, return the new
|
|
189
|
+
# session-id.
|
|
190
|
+
def verify_signature(result) #:nodoc:
|
|
191
|
+
response = build_signature_buffer(result)
|
|
192
|
+
|
|
193
|
+
hash = @digester.digest(response.to_s)
|
|
194
|
+
|
|
195
|
+
unless result[:server_key].ssh_do_verify(result[:server_sig], hash)
|
|
196
|
+
raise Net::SSH::Exception, "could not verify server signature"
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
return hash
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Send the NEWKEYS message, and expect the NEWKEYS message in
|
|
203
|
+
# reply.
|
|
204
|
+
def confirm_newkeys #:nodoc:
|
|
205
|
+
# send own NEWKEYS message first (the wodSSHServer won't send first)
|
|
206
|
+
response = Net::SSH::Buffer.new
|
|
207
|
+
response.write_byte(NEWKEYS)
|
|
208
|
+
connection.send_message(response)
|
|
209
|
+
|
|
210
|
+
# wait for the server's NEWKEYS message
|
|
211
|
+
buffer = connection.next_message
|
|
212
|
+
raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
end; end; end; end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'net/ssh/errors'
|
|
2
|
+
require 'net/ssh/transport/constants'
|
|
3
|
+
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
|
|
4
|
+
|
|
5
|
+
module Net::SSH::Transport::Kex
|
|
6
|
+
|
|
7
|
+
# A key-exchange service implementing the
|
|
8
|
+
# "diffie-hellman-group-exchange-sha1" key-exchange algorithm.
|
|
9
|
+
class DiffieHellmanGroupExchangeSHA1 < DiffieHellmanGroup1SHA1
|
|
10
|
+
MINIMUM_BITS = 1024
|
|
11
|
+
MAXIMUM_BITS = 8192
|
|
12
|
+
|
|
13
|
+
KEXDH_GEX_GROUP = 31
|
|
14
|
+
KEXDH_GEX_INIT = 32
|
|
15
|
+
KEXDH_GEX_REPLY = 33
|
|
16
|
+
KEXDH_GEX_REQUEST = 34
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
# Compute the number of bits needed for the given number of bytes.
|
|
21
|
+
def compute_need_bits
|
|
22
|
+
|
|
23
|
+
# for Compatibility: OpenSSH requires (need_bits * 2 + 1) length of parameter
|
|
24
|
+
need_bits = data[:need_bytes] * 8 * 2 + 1
|
|
25
|
+
|
|
26
|
+
if need_bits < MINIMUM_BITS
|
|
27
|
+
need_bits = MINIMUM_BITS
|
|
28
|
+
elsif need_bits > MAXIMUM_BITS
|
|
29
|
+
need_bits = MAXIMUM_BITS
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
data[:need_bits ] = need_bits
|
|
33
|
+
data[:need_bytes] = need_bits / 8
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns the DH key parameters for the given session.
|
|
37
|
+
def get_parameters
|
|
38
|
+
compute_need_bits
|
|
39
|
+
|
|
40
|
+
# request the DH key parameters for the given number of bits.
|
|
41
|
+
buffer = Net::SSH::Buffer.from(:byte, KEXDH_GEX_REQUEST, :long, MINIMUM_BITS,
|
|
42
|
+
:long, data[:need_bits], :long, MAXIMUM_BITS)
|
|
43
|
+
connection.send_message(buffer)
|
|
44
|
+
|
|
45
|
+
buffer = connection.next_message
|
|
46
|
+
unless buffer.type == KEXDH_GEX_GROUP
|
|
47
|
+
raise Net::SSH::Exception, "expected KEXDH_GEX_GROUP, got #{buffer.type}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
p = buffer.read_bignum
|
|
51
|
+
g = buffer.read_bignum
|
|
52
|
+
|
|
53
|
+
[p, g]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Returns the INIT/REPLY constants used by this algorithm.
|
|
57
|
+
def get_message_types
|
|
58
|
+
[KEXDH_GEX_INIT, KEXDH_GEX_REPLY]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Build the signature buffer to use when verifying a signature from
|
|
62
|
+
# the server.
|
|
63
|
+
def build_signature_buffer(result)
|
|
64
|
+
response = Net::SSH::Buffer.new
|
|
65
|
+
response.write_string data[:client_version_string],
|
|
66
|
+
data[:server_version_string],
|
|
67
|
+
data[:client_algorithm_packet],
|
|
68
|
+
data[:server_algorithm_packet],
|
|
69
|
+
result[:key_blob]
|
|
70
|
+
response.write_long MINIMUM_BITS,
|
|
71
|
+
data[:need_bits],
|
|
72
|
+
MAXIMUM_BITS
|
|
73
|
+
response.write_bignum dh.p, dh.g, dh.pub_key,
|
|
74
|
+
result[:server_dh_pubkey],
|
|
75
|
+
result[:shared_secret]
|
|
76
|
+
response
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|