net-ssh 6.3.0.beta1 → 7.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +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
|
|