net-ssh 6.3.0.beta1 → 7.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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 +4 -10
- data/.github/workflows/rubocop.yml +13 -0
- data/.rubocop.yml +2 -1
- data/.rubocop_todo.yml +244 -237
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/README.md +7 -1
- data/Rakefile +4 -0
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +13 -13
- data/lib/net/ssh/authentication/certificate.rb +4 -4
- data/lib/net/ssh/authentication/ed25519.rb +5 -5
- data/lib/net/ssh/authentication/key_manager.rb +18 -5
- data/lib/net/ssh/authentication/methods/abstract.rb +12 -2
- data/lib/net/ssh/authentication/methods/hostbased.rb +3 -3
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
- data/lib/net/ssh/authentication/methods/none.rb +1 -1
- data/lib/net/ssh/authentication/methods/password.rb +1 -1
- data/lib/net/ssh/authentication/methods/publickey.rb +56 -14
- data/lib/net/ssh/authentication/pageant.rb +8 -8
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -2
- data/lib/net/ssh/authentication/session.rb +5 -3
- data/lib/net/ssh/buffer.rb +41 -26
- data/lib/net/ssh/buffered_io.rb +6 -6
- data/lib/net/ssh/config.rb +4 -4
- data/lib/net/ssh/connection/channel.rb +13 -13
- data/lib/net/ssh/connection/event_loop.rb +8 -8
- data/lib/net/ssh/connection/session.rb +13 -13
- data/lib/net/ssh/errors.rb +2 -2
- data/lib/net/ssh/key_factory.rb +7 -7
- data/lib/net/ssh/known_hosts.rb +5 -4
- data/lib/net/ssh/prompt.rb +1 -1
- data/lib/net/ssh/proxy/http.rb +1 -1
- data/lib/net/ssh/proxy/https.rb +2 -2
- data/lib/net/ssh/proxy/socks4.rb +1 -1
- data/lib/net/ssh/proxy/socks5.rb +1 -1
- data/lib/net/ssh/service/forward.rb +4 -4
- data/lib/net/ssh/test/channel.rb +3 -3
- data/lib/net/ssh/test/extensions.rb +6 -6
- data/lib/net/ssh/test/packet.rb +1 -1
- data/lib/net/ssh/test/script.rb +3 -3
- data/lib/net/ssh/test/socket.rb +1 -1
- data/lib/net/ssh/test.rb +3 -3
- data/lib/net/ssh/transport/algorithms.rb +12 -12
- data/lib/net/ssh/transport/cipher_factory.rb +15 -15
- data/lib/net/ssh/transport/ctr.rb +3 -3
- data/lib/net/ssh/transport/hmac/abstract.rb +4 -4
- data/lib/net/ssh/transport/hmac.rb +12 -12
- data/lib/net/ssh/transport/identity_cipher.rb +1 -1
- 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 +1 -1
- 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 -1
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
- data/lib/net/ssh/transport/kex.rb +7 -7
- data/lib/net/ssh/transport/key_expander.rb +1 -1
- data/lib/net/ssh/transport/openssl.rb +32 -11
- data/lib/net/ssh/transport/packet_stream.rb +1 -1
- data/lib/net/ssh/transport/session.rb +6 -6
- data/lib/net/ssh/transport/state.rb +1 -1
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +3 -3
- data/net-ssh.gemspec +2 -2
- data.tar.gz.sig +0 -0
- metadata +13 -7
- metadata.gz.sig +1 -2
- data/.travis.yml +0 -51
@@ -38,7 +38,7 @@ module Net
|
|
38
38
|
module PacketStream
|
39
39
|
include BufferedIo # make sure we get the extensions here, too
|
40
40
|
|
41
|
-
def self.included(base)
|
41
|
+
def self.included(base) # :nodoc:
|
42
42
|
base.send :alias_method, :real_available_for_read?, :available_for_read?
|
43
43
|
base.send :alias_method, :available_for_read?, :test_available_for_read?
|
44
44
|
|
@@ -93,7 +93,7 @@ module Net
|
|
93
93
|
|
94
94
|
# An extension to Net::SSH::Connection::Channel. Facilitates unit testing.
|
95
95
|
module Channel
|
96
|
-
def self.included(base)
|
96
|
+
def self.included(base) # :nodoc:
|
97
97
|
base.send :alias_method, :send_data_for_real, :send_data
|
98
98
|
base.send :alias_method, :send_data, :send_data_for_test
|
99
99
|
end
|
@@ -111,7 +111,7 @@ module Net
|
|
111
111
|
# An extension to the built-in ::IO class. Simply redefines IO.select
|
112
112
|
# so that it can be scripted in Net::SSH unit tests.
|
113
113
|
module IO
|
114
|
-
def self.included(base)
|
114
|
+
def self.included(base) # :nodoc:
|
115
115
|
base.extend(ClassMethods)
|
116
116
|
end
|
117
117
|
|
@@ -132,8 +132,8 @@ module Net
|
|
132
132
|
end
|
133
133
|
|
134
134
|
module ClassMethods
|
135
|
-
def self.extended(obj)
|
136
|
-
class <<obj
|
135
|
+
def self.extended(obj) # :nodoc:
|
136
|
+
class << obj
|
137
137
|
alias_method :select_for_real, :select
|
138
138
|
alias_method :select, :select_for_test
|
139
139
|
end
|
@@ -142,7 +142,7 @@ module Net
|
|
142
142
|
# The testing version of ::IO.select. Assumes that all readers,
|
143
143
|
# writers, and errors arrays are either nil, or contain only objects
|
144
144
|
# that mix in Net::SSH::Test::Extensions::BufferedIo.
|
145
|
-
def select_for_test(readers=nil, writers=nil, errors=nil, wait=nil)
|
145
|
+
def select_for_test(readers = nil, writers = nil, errors = nil, wait = nil)
|
146
146
|
return select_for_real(readers, writers, errors, wait) unless Net::SSH::Test::Extensions::IO.extension_enabled?
|
147
147
|
|
148
148
|
ready_readers = Array(readers).select { |r| r.select_for_read? }
|
data/lib/net/ssh/test/packet.rb
CHANGED
@@ -82,7 +82,7 @@ module Net
|
|
82
82
|
when CHANNEL_REQUEST
|
83
83
|
parts = %i[long string bool]
|
84
84
|
case @data[1]
|
85
|
-
when "exec", "subsystem","shell" then parts << :string
|
85
|
+
when "exec", "subsystem", "shell" then parts << :string
|
86
86
|
when "exit-status" then parts << :long
|
87
87
|
when "pty-req" then parts.concat(%i[string long long long long string])
|
88
88
|
when "env" then parts.contact(%i[string string])
|
data/lib/net/ssh/test/script.rb
CHANGED
@@ -33,7 +33,7 @@ module Net
|
|
33
33
|
#
|
34
34
|
# A new Net::SSH::Test::Channel instance is returned, which can be used
|
35
35
|
# to script additional channel operations.
|
36
|
-
def opens_channel(confirm=true)
|
36
|
+
def opens_channel(confirm = true)
|
37
37
|
channel = Channel.new(self)
|
38
38
|
channel.remote_id = 5555
|
39
39
|
|
@@ -70,7 +70,7 @@ module Net
|
|
70
70
|
#
|
71
71
|
# This will typically be called via Net::SSH::Test::Channel#sends_exec or
|
72
72
|
# Net::SSH::Test::Channel#sends_subsystem.
|
73
|
-
def sends_channel_request(channel, request, reply, data, success=true)
|
73
|
+
def sends_channel_request(channel, request, reply, data, success = true)
|
74
74
|
if data.is_a? Array
|
75
75
|
events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, *data)
|
76
76
|
else
|
@@ -163,7 +163,7 @@ module Net
|
|
163
163
|
#
|
164
164
|
# # peek at the next event
|
165
165
|
# event = script.next(:first)
|
166
|
-
def next(mode
|
166
|
+
def next(mode = :shift)
|
167
167
|
events.send(mode)
|
168
168
|
end
|
169
169
|
|
data/lib/net/ssh/test/socket.rb
CHANGED
data/lib/net/ssh/test.rb
CHANGED
@@ -56,21 +56,21 @@ module Net
|
|
56
56
|
|
57
57
|
# Returns the test socket instance to use for these tests (see
|
58
58
|
# Net::SSH::Test::Socket).
|
59
|
-
def socket(options={})
|
59
|
+
def socket(options = {})
|
60
60
|
@socket ||= Net::SSH::Test::Socket.new
|
61
61
|
end
|
62
62
|
|
63
63
|
# Returns the connection session (Net::SSH::Connection::Session) for use
|
64
64
|
# in these tests. It is a fully functional SSH session, operating over
|
65
65
|
# a mock socket (#socket).
|
66
|
-
def connection(options={})
|
66
|
+
def connection(options = {})
|
67
67
|
@connection ||= Net::SSH::Connection::Session.new(transport(options), options)
|
68
68
|
end
|
69
69
|
|
70
70
|
# Returns the transport session (Net::SSH::Transport::Session) for use
|
71
71
|
# in these tests. It is a fully functional SSH transport session, operating
|
72
72
|
# over a mock socket (#socket).
|
73
|
-
def transport(options={})
|
73
|
+
def transport(options = {})
|
74
74
|
@transport ||= Net::SSH::Transport::Session.new(
|
75
75
|
options[:host] || "localhost",
|
76
76
|
options.merge(kex: "test", host_key: "ssh-rsa", append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
|
@@ -146,7 +146,7 @@ module Net
|
|
146
146
|
|
147
147
|
# Instantiates a new Algorithms object, and prepares the hash of preferred
|
148
148
|
# algorithms based on the options parameter and the ALGORITHMS constant.
|
149
|
-
def initialize(session, options={})
|
149
|
+
def initialize(session, options = {})
|
150
150
|
@session = session
|
151
151
|
@logger = session.logger
|
152
152
|
@options = options
|
@@ -369,10 +369,10 @@ module Net
|
|
369
369
|
language = algorithms[:language].join(",")
|
370
370
|
|
371
371
|
Net::SSH::Buffer.from(:byte, KEXINIT,
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
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)
|
376
376
|
end
|
377
377
|
|
378
378
|
# Given the parsed server KEX packet, and the client's preferred algorithm
|
@@ -438,13 +438,13 @@ module Net
|
|
438
438
|
debug { "exchanging keys" }
|
439
439
|
|
440
440
|
algorithm = Kex::MAP[kex].new(self, session,
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
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)
|
448
448
|
result = algorithm.exchange_keys
|
449
449
|
|
450
450
|
secret = result[:shared_secret].to_ssh
|
@@ -10,23 +10,23 @@ module Net
|
|
10
10
|
class CipherFactory
|
11
11
|
# Maps the SSH name of a cipher to it's corresponding OpenSSL name
|
12
12
|
SSH_TO_OSSL = {
|
13
|
-
"3des-cbc"
|
14
|
-
"blowfish-cbc"
|
15
|
-
"aes256-cbc"
|
16
|
-
"aes192-cbc"
|
17
|
-
"aes128-cbc"
|
18
|
-
"idea-cbc"
|
19
|
-
"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",
|
20
20
|
"rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
|
21
|
-
"3des-ctr"
|
22
|
-
"blowfish-ctr"
|
21
|
+
"3des-ctr" => "des-ede3",
|
22
|
+
"blowfish-ctr" => "bf-ecb",
|
23
23
|
|
24
|
-
"aes256-ctr"
|
25
|
-
"aes192-ctr"
|
26
|
-
"aes128-ctr"
|
27
|
-
'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',
|
28
28
|
|
29
|
-
'none'
|
29
|
+
'none' => 'none'
|
30
30
|
}
|
31
31
|
|
32
32
|
# Returns true if the underlying OpenSSL library supports the given cipher,
|
@@ -43,7 +43,7 @@ module Net
|
|
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
|
|
@@ -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,7 +26,7 @@ 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
|
@@ -95,7 +95,7 @@ module Net::SSH::Transport
|
|
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!)
|
@@ -7,7 +7,7 @@ module Net
|
|
7
7
|
module HMAC
|
8
8
|
# The base class of all OpenSSL-based HMAC algorithm wrappers.
|
9
9
|
class Abstract
|
10
|
-
class <<self
|
10
|
+
class << self
|
11
11
|
def etm(*v)
|
12
12
|
@etm = false if !defined?(@etm)
|
13
13
|
if v.empty?
|
@@ -76,19 +76,19 @@ module Net
|
|
76
76
|
# The key in use for this instance.
|
77
77
|
attr_reader :key
|
78
78
|
|
79
|
-
def initialize(key=nil)
|
79
|
+
def initialize(key = nil)
|
80
80
|
self.key = key
|
81
81
|
end
|
82
82
|
|
83
83
|
# Sets the key to the given value, truncating it so that it is the correct
|
84
84
|
# length.
|
85
85
|
def key=(value)
|
86
|
-
@key = value ? value.to_s[0,key_length] : nil
|
86
|
+
@key = value ? value.to_s[0, key_length] : nil
|
87
87
|
end
|
88
88
|
|
89
89
|
# Compute the HMAC digest for the given data string.
|
90
90
|
def digest(data)
|
91
|
-
OpenSSL::HMAC.digest(digest_class.new, key, data)[0,mac_length]
|
91
|
+
OpenSSL::HMAC.digest(digest_class.new, key, data)[0, mac_length]
|
92
92
|
end
|
93
93
|
end
|
94
94
|
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
|
@@ -5,7 +5,7 @@ module Net
|
|
5
5
|
# keeps things in the code nice and clean when a cipher has not yet been
|
6
6
|
# determined (i.e., during key exchange).
|
7
7
|
class IdentityCipher
|
8
|
-
class <<self
|
8
|
+
class << self
|
9
9
|
# A default block size of 8 is required by the SSH2 protocol.
|
10
10
|
def block_size
|
11
11
|
8
|
@@ -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)
|
@@ -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
|
@@ -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
|
@@ -13,14 +13,14 @@ module Net::SSH::Transport
|
|
13
13
|
# Maps the supported key-exchange algorithms as named by the SSH protocol
|
14
14
|
# to their corresponding implementors.
|
15
15
|
MAP = {
|
16
|
-
'diffie-hellman-group1-sha1'
|
17
|
-
'diffie-hellman-group14-sha1'
|
18
|
-
'diffie-hellman-group14-sha256'
|
19
|
-
'diffie-hellman-group-exchange-sha1'
|
16
|
+
'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1,
|
17
|
+
'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
|
18
|
+
'diffie-hellman-group14-sha256' => DiffieHellmanGroup14SHA256,
|
19
|
+
'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1,
|
20
20
|
'diffie-hellman-group-exchange-sha256' => DiffieHellmanGroupExchangeSHA256,
|
21
|
-
'ecdh-sha2-nistp256'
|
22
|
-
'ecdh-sha2-nistp384'
|
23
|
-
'ecdh-sha2-nistp521'
|
21
|
+
'ecdh-sha2-nistp256' => EcdhSHA2NistP256,
|
22
|
+
'ecdh-sha2-nistp384' => EcdhSHA2NistP384,
|
23
|
+
'ecdh-sha2-nistp521' => EcdhSHA2NistP521
|
24
24
|
}
|
25
25
|
|
26
26
|
if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
|
@@ -4,7 +4,7 @@ module Net
|
|
4
4
|
module KeyExpander
|
5
5
|
# Generate a key value in accordance with the SSH2 specification.
|
6
6
|
# (RFC4253 7.2. "Output from Key Exchange")
|
7
|
-
def self.expand_key(bytes, start, options={})
|
7
|
+
def self.expand_key(bytes, start, options = {})
|
8
8
|
if bytes == 0
|
9
9
|
return ""
|
10
10
|
end
|
@@ -74,8 +74,16 @@ module OpenSSL
|
|
74
74
|
end
|
75
75
|
|
76
76
|
# Returns the signature for the given data.
|
77
|
-
def ssh_do_sign(data)
|
78
|
-
|
77
|
+
def ssh_do_sign(data, sig_alg = nil)
|
78
|
+
digester =
|
79
|
+
if sig_alg == "rsa-sha2-512"
|
80
|
+
OpenSSL::Digest::SHA512.new
|
81
|
+
elsif sig_alg == "rsa-sha2-256"
|
82
|
+
OpenSSL::Digest::SHA256.new
|
83
|
+
else
|
84
|
+
OpenSSL::Digest::SHA1.new
|
85
|
+
end
|
86
|
+
sign(digester, data)
|
79
87
|
end
|
80
88
|
end
|
81
89
|
|
@@ -94,13 +102,13 @@ module OpenSSL
|
|
94
102
|
# Converts the key to a blob, according to the SSH2 protocol.
|
95
103
|
def to_blob
|
96
104
|
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
97
|
-
|
105
|
+
:bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
|
98
106
|
end
|
99
107
|
|
100
108
|
# Verifies the given signature matches the given data.
|
101
109
|
def ssh_do_verify(sig, data, options = {})
|
102
|
-
sig_r = sig[0,20].unpack("H*")[0].to_i(16)
|
103
|
-
sig_s = sig[20,20].unpack("H*")[0].to_i(16)
|
110
|
+
sig_r = sig[0, 20].unpack("H*")[0].to_i(16)
|
111
|
+
sig_s = sig[20, 20].unpack("H*")[0].to_i(16)
|
104
112
|
a1sig = OpenSSL::ASN1::Sequence([
|
105
113
|
OpenSSL::ASN1::Integer(sig_r),
|
106
114
|
OpenSSL::ASN1::Integer(sig_s)
|
@@ -109,14 +117,15 @@ module OpenSSL
|
|
109
117
|
end
|
110
118
|
|
111
119
|
# Signs the given data.
|
112
|
-
def ssh_do_sign(data)
|
120
|
+
def ssh_do_sign(data, sig_alg = nil)
|
113
121
|
sig = sign(OpenSSL::Digest::SHA1.new, data)
|
114
122
|
a1sig = OpenSSL::ASN1.decode(sig)
|
115
123
|
|
116
124
|
sig_r = a1sig.value[0].value.to_s(2)
|
117
125
|
sig_s = a1sig.value[1].value.to_s(2)
|
118
126
|
|
119
|
-
|
127
|
+
sig_size = params["q"].num_bits / 8
|
128
|
+
raise OpenSSL::PKey::DSAError, "bad sig size" if sig_r.length > sig_size || sig_s.length > sig_size
|
120
129
|
|
121
130
|
sig_r = "\0" * (20 - sig_r.length) + sig_r if sig_r.length < 20
|
122
131
|
sig_s = "\0" * (20 - sig_s.length) + sig_s if sig_s.length < 20
|
@@ -150,10 +159,22 @@ module OpenSSL
|
|
150
159
|
|
151
160
|
public_key_oct = buffer.read_string
|
152
161
|
begin
|
153
|
-
|
154
|
-
group =
|
162
|
+
curvename = OpenSSL::PKey::EC::CurveNameAlias[curve_name_in_key]
|
163
|
+
group = OpenSSL::PKey::EC::Group.new(curvename)
|
155
164
|
point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_oct, 2))
|
156
|
-
|
165
|
+
asn1 = OpenSSL::ASN1::Sequence(
|
166
|
+
[
|
167
|
+
OpenSSL::ASN1::Sequence(
|
168
|
+
[
|
169
|
+
OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
|
170
|
+
OpenSSL::ASN1::ObjectId(curvename)
|
171
|
+
]
|
172
|
+
),
|
173
|
+
OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
|
174
|
+
]
|
175
|
+
)
|
176
|
+
|
177
|
+
key = OpenSSL::PKey::EC.new(asn1.to_der)
|
157
178
|
|
158
179
|
return key
|
159
180
|
rescue OpenSSL::PKey::ECError
|
@@ -220,7 +241,7 @@ module OpenSSL
|
|
220
241
|
end
|
221
242
|
|
222
243
|
# Returns the signature for the given data.
|
223
|
-
def ssh_do_sign(data)
|
244
|
+
def ssh_do_sign(data, sig_alg = nil)
|
224
245
|
digest = digester.digest(data)
|
225
246
|
sig = dsa_sign_asn1(digest)
|
226
247
|
a1sig = OpenSSL::ASN1.decode(sig)
|
@@ -80,7 +80,7 @@ module Net
|
|
80
80
|
# available or not, and will return nil if there is no packet ready to be
|
81
81
|
# returned. If the mode parameter is :block, then this method will block
|
82
82
|
# until a packet is available or timeout seconds have passed.
|
83
|
-
def next_packet(mode
|
83
|
+
def next_packet(mode = :nonblock, timeout = nil)
|
84
84
|
case mode
|
85
85
|
when :nonblock then
|
86
86
|
packet = poll_next_packet
|
@@ -55,7 +55,7 @@ module Net
|
|
55
55
|
# Instantiates a new transport layer abstraction. This will block until
|
56
56
|
# the initial key exchange completes, leaving you with a ready-to-use
|
57
57
|
# transport session.
|
58
|
-
def initialize(host, options={})
|
58
|
+
def initialize(host, options = {})
|
59
59
|
self.logger = options[:logger]
|
60
60
|
|
61
61
|
@host = host
|
@@ -186,7 +186,7 @@ module Net
|
|
186
186
|
# received, it will be enqueued and otherwise ignored. When a key-exchange
|
187
187
|
# is not in process, and consume_queue is true, packets will be first
|
188
188
|
# read from the queue before the socket is queried.
|
189
|
-
def poll_message(mode
|
189
|
+
def poll_message(mode = :nonblock, consume_queue = true)
|
190
190
|
loop do
|
191
191
|
return @queue.shift if consume_queue && @queue.any? && algorithms.allow?(@queue.first)
|
192
192
|
|
@@ -252,27 +252,27 @@ module Net
|
|
252
252
|
# Configure's the packet stream's client state with the given set of
|
253
253
|
# options. This is typically used to define the cipher, compression, and
|
254
254
|
# hmac algorithms to use when sending packets to the server.
|
255
|
-
def configure_client(options={})
|
255
|
+
def configure_client(options = {})
|
256
256
|
socket.client.set(options)
|
257
257
|
end
|
258
258
|
|
259
259
|
# Configure's the packet stream's server state with the given set of
|
260
260
|
# options. This is typically used to define the cipher, compression, and
|
261
261
|
# hmac algorithms to use when reading packets from the server.
|
262
|
-
def configure_server(options={})
|
262
|
+
def configure_server(options = {})
|
263
263
|
socket.server.set(options)
|
264
264
|
end
|
265
265
|
|
266
266
|
# Sets a new hint for the packet stream, which the packet stream may use
|
267
267
|
# to change its behavior. (See PacketStream#hints).
|
268
|
-
def hint(which, value=true)
|
268
|
+
def hint(which, value = true)
|
269
269
|
socket.hints[which] = value
|
270
270
|
end
|
271
271
|
|
272
272
|
public
|
273
273
|
|
274
274
|
# this method is primarily for use in tests
|
275
|
-
attr_reader :queue
|
275
|
+
attr_reader :queue # :nodoc:
|
276
276
|
|
277
277
|
private
|
278
278
|
|