net-ssh 5.0.2 → 7.0.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.
- 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 +87 -0
- data/.github/workflows/rubocop.yml +13 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +19 -2
- data/.rubocop_todo.yml +623 -511
- data/CHANGES.txt +76 -0
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/Manifest +0 -1
- data/README.md +293 -0
- data/Rakefile +6 -2
- data/appveyor.yml +4 -2
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +36 -14
- data/lib/net/ssh/authentication/certificate.rb +19 -7
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +83 -50
- data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
- data/lib/net/ssh/authentication/key_manager.rb +74 -33
- data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
- data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +5 -3
- data/lib/net/ssh/authentication/methods/none.rb +6 -9
- data/lib/net/ssh/authentication/methods/password.rb +2 -3
- data/lib/net/ssh/authentication/methods/publickey.rb +58 -16
- data/lib/net/ssh/authentication/pageant.rb +97 -97
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -3
- data/lib/net/ssh/authentication/session.rb +27 -23
- data/lib/net/ssh/buffer.rb +91 -40
- data/lib/net/ssh/buffered_io.rb +24 -26
- data/lib/net/ssh/config.rb +99 -53
- data/lib/net/ssh/connection/channel.rb +101 -87
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +30 -25
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +115 -111
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +12 -12
- data/lib/net/ssh/key_factory.rb +108 -22
- data/lib/net/ssh/known_hosts.rb +120 -36
- data/lib/net/ssh/loggable.rb +10 -11
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +9 -11
- data/lib/net/ssh/proxy/command.rb +1 -2
- data/lib/net/ssh/proxy/errors.rb +2 -4
- data/lib/net/ssh/proxy/http.rb +18 -20
- data/lib/net/ssh/proxy/https.rb +8 -10
- data/lib/net/ssh/proxy/jump.rb +8 -10
- data/lib/net/ssh/proxy/socks4.rb +2 -4
- data/lib/net/ssh/proxy/socks5.rb +3 -6
- data/lib/net/ssh/service/forward.rb +9 -8
- data/lib/net/ssh/test/channel.rb +24 -26
- data/lib/net/ssh/test/extensions.rb +37 -35
- data/lib/net/ssh/test/kex.rb +6 -8
- data/lib/net/ssh/test/local_packet.rb +0 -2
- data/lib/net/ssh/test/packet.rb +3 -3
- data/lib/net/ssh/test/remote_packet.rb +6 -8
- data/lib/net/ssh/test/script.rb +25 -27
- data/lib/net/ssh/test/socket.rb +12 -15
- data/lib/net/ssh/test.rb +12 -12
- data/lib/net/ssh/transport/algorithms.rb +177 -118
- data/lib/net/ssh/transport/cipher_factory.rb +34 -50
- data/lib/net/ssh/transport/constants.rb +13 -9
- data/lib/net/ssh/transport/ctr.rb +8 -14
- data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +13 -11
- data/lib/net/ssh/transport/identity_cipher.rb +11 -13
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +5 -19
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +30 -139
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -8
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +20 -81
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
- data/lib/net/ssh/transport/kex.rb +15 -10
- data/lib/net/ssh/transport/key_expander.rb +7 -8
- data/lib/net/ssh/transport/openssl.rb +149 -111
- data/lib/net/ssh/transport/packet_stream.rb +53 -22
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +35 -11
- data/lib/net/ssh/transport/state.rb +44 -44
- data/lib/net/ssh/verifiers/accept_new.rb +7 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +10 -4
- data/lib/net/ssh/verifiers/never.rb +4 -2
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +17 -9
- data/net-ssh-public_cert.pem +18 -19
- data/net-ssh.gemspec +9 -7
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +65 -41
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -52
- data/Gemfile.noed25519.lock +0 -41
- data/README.rdoc +0 -169
- data/lib/net/ssh/ruby_compat.rb +0 -13
- data/support/arcfour_check.rb +0 -20
|
@@ -1,97 +1,36 @@
|
|
|
1
|
-
require 'net/ssh/transport/
|
|
2
|
-
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
|
|
1
|
+
require 'net/ssh/transport/kex/abstract5656'
|
|
3
2
|
|
|
4
|
-
module Net
|
|
5
|
-
module SSH
|
|
6
|
-
module Transport
|
|
3
|
+
module Net
|
|
4
|
+
module SSH
|
|
5
|
+
module Transport
|
|
7
6
|
module Kex
|
|
8
|
-
|
|
9
7
|
# A key-exchange service implementing the "ecdh-sha2-nistp256"
|
|
10
8
|
# key-exchange algorithm. (defined in RFC 5656)
|
|
11
|
-
class EcdhSHA2NistP256 <
|
|
12
|
-
include Loggable
|
|
13
|
-
include Constants
|
|
14
|
-
|
|
15
|
-
attr_reader :ecdh
|
|
16
|
-
|
|
9
|
+
class EcdhSHA2NistP256 < Abstract5656
|
|
17
10
|
def digester
|
|
18
11
|
OpenSSL::Digest::SHA256
|
|
19
12
|
end
|
|
20
|
-
|
|
13
|
+
|
|
21
14
|
def curve_name
|
|
22
15
|
OpenSSL::PKey::EC::CurveNameAlias['nistp256']
|
|
23
16
|
end
|
|
24
|
-
|
|
25
|
-
def initialize(algorithms, connection, data)
|
|
26
|
-
@algorithms = algorithms
|
|
27
|
-
@connection = connection
|
|
28
|
-
|
|
29
|
-
@digester = digester
|
|
30
|
-
@data = data.dup
|
|
31
|
-
@ecdh = generate_key
|
|
32
|
-
@logger = @data.delete(:logger)
|
|
33
|
-
end
|
|
34
|
-
|
|
17
|
+
|
|
35
18
|
private
|
|
36
|
-
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def build_signature_buffer(result)
|
|
42
|
-
response = Net::SSH::Buffer.new
|
|
43
|
-
response.write_string data[:client_version_string],
|
|
44
|
-
data[:server_version_string],
|
|
45
|
-
data[:client_algorithm_packet],
|
|
46
|
-
data[:server_algorithm_packet],
|
|
47
|
-
result[:key_blob],
|
|
48
|
-
ecdh.public_key.to_bn.to_s(2),
|
|
49
|
-
result[:server_ecdh_pubkey]
|
|
50
|
-
response.write_bignum result[:shared_secret]
|
|
51
|
-
response
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def generate_key #:nodoc:
|
|
55
|
-
OpenSSL::PKey::EC.new(curve_name).generate_key
|
|
19
|
+
|
|
20
|
+
def generate_key # :nodoc:
|
|
21
|
+
OpenSSL::PKey::EC.generate(curve_name)
|
|
56
22
|
end
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# send the KEXECDH_INIT message
|
|
62
|
-
## byte SSH_MSG_KEX_ECDH_INIT
|
|
63
|
-
## string Q_C, client's ephemeral public key octet string
|
|
64
|
-
buffer = Net::SSH::Buffer.from(:byte, init, :mstring, ecdh.public_key.to_bn.to_s(2))
|
|
65
|
-
connection.send_message(buffer)
|
|
66
|
-
|
|
67
|
-
# expect the following KEXECDH_REPLY message
|
|
68
|
-
## byte SSH_MSG_KEX_ECDH_REPLY
|
|
69
|
-
## string K_S, server's public host key
|
|
70
|
-
## string Q_S, server's ephemeral public key octet string
|
|
71
|
-
## string the signature on the exchange hash
|
|
72
|
-
buffer = connection.next_message
|
|
73
|
-
raise Net::SSH::Exception, "expected REPLY" unless buffer.type == reply
|
|
74
|
-
|
|
75
|
-
result = Hash.new
|
|
76
|
-
result[:key_blob] = buffer.read_string
|
|
77
|
-
result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
|
|
78
|
-
result[:server_ecdh_pubkey] = buffer.read_string
|
|
79
|
-
|
|
80
|
-
# compute shared secret from server's public key and client's private key
|
|
23
|
+
|
|
24
|
+
# compute shared secret from server's public key and client's private key
|
|
25
|
+
def compute_shared_secret(server_ecdh_pubkey)
|
|
81
26
|
pk = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(curve_name).group,
|
|
82
|
-
OpenSSL::BN.new(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"host key algorithm mismatch for signature " +
|
|
90
|
-
"'#{sig_type}' != '#{algorithms.host_key_format}'"
|
|
91
|
-
end
|
|
92
|
-
result[:server_sig] = sig_buffer.read_string
|
|
93
|
-
|
|
94
|
-
return result
|
|
27
|
+
OpenSSL::BN.new(server_ecdh_pubkey, 2))
|
|
28
|
+
OpenSSL::BN.new(ecdh.dh_compute_key(pk), 2)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
## string Q_C, client's ephemeral public key octet string
|
|
32
|
+
def ecdh_public_key_bytes
|
|
33
|
+
ecdh.public_key.to_bn.to_s(2)
|
|
95
34
|
end
|
|
96
35
|
end
|
|
97
36
|
end
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
module SSH
|
|
3
|
-
module Transport
|
|
4
|
-
module Kex
|
|
1
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
|
|
5
2
|
|
|
3
|
+
module Net
|
|
4
|
+
module SSH
|
|
5
|
+
module Transport
|
|
6
|
+
module Kex
|
|
6
7
|
# A key-exchange service implementing the "ecdh-sha2-nistp256"
|
|
7
8
|
# key-exchange algorithm. (defined in RFC 5656)
|
|
8
9
|
class EcdhSHA2NistP384 < EcdhSHA2NistP256
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
module SSH
|
|
3
|
-
module Transport
|
|
4
|
-
module Kex
|
|
1
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
|
|
5
2
|
|
|
3
|
+
module Net
|
|
4
|
+
module SSH
|
|
5
|
+
module Transport
|
|
6
|
+
module Kex
|
|
6
7
|
# A key-exchange service implementing the "ecdh-sha2-nistp521"
|
|
7
8
|
# key-exchange algorithm. (defined in RFC 5656)
|
|
8
9
|
class EcdhSHA2NistP521 < EcdhSHA2NistP256
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
|
|
2
2
|
require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
|
|
3
|
+
require 'net/ssh/transport/kex/diffie_hellman_group14_sha256'
|
|
3
4
|
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
|
|
4
5
|
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha256'
|
|
6
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
|
|
7
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp384'
|
|
8
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp521'
|
|
9
|
+
require 'net/ssh/transport/kex/curve25519_sha256_loader'
|
|
5
10
|
|
|
6
11
|
module Net::SSH::Transport
|
|
7
12
|
module Kex
|
|
8
13
|
# Maps the supported key-exchange algorithms as named by the SSH protocol
|
|
9
14
|
# to their corresponding implementors.
|
|
10
15
|
MAP = {
|
|
16
|
+
'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1,
|
|
17
|
+
'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
|
|
18
|
+
'diffie-hellman-group14-sha256' => DiffieHellmanGroup14SHA256,
|
|
11
19
|
'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1,
|
|
12
|
-
'diffie-hellman-
|
|
13
|
-
'
|
|
20
|
+
'diffie-hellman-group-exchange-sha256' => DiffieHellmanGroupExchangeSHA256,
|
|
21
|
+
'ecdh-sha2-nistp256' => EcdhSHA2NistP256,
|
|
22
|
+
'ecdh-sha2-nistp384' => EcdhSHA2NistP384,
|
|
23
|
+
'ecdh-sha2-nistp521' => EcdhSHA2NistP521
|
|
14
24
|
}
|
|
15
|
-
MAP['diffie-hellman-group-exchange-sha256'] = DiffieHellmanGroupExchangeSHA256 if defined?(DiffieHellmanGroupExchangeSHA256)
|
|
16
|
-
if defined?(OpenSSL::PKey::EC)
|
|
17
|
-
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
|
|
18
|
-
require 'net/ssh/transport/kex/ecdh_sha2_nistp384'
|
|
19
|
-
require 'net/ssh/transport/kex/ecdh_sha2_nistp521'
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
MAP['
|
|
23
|
-
MAP['
|
|
26
|
+
if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
|
|
27
|
+
MAP['curve25519-sha256'] = Curve25519Sha256
|
|
28
|
+
MAP['curve25519-sha256@libssh.org'] = Curve25519Sha256
|
|
24
29
|
end
|
|
25
30
|
end
|
|
26
31
|
end
|
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
module Net
|
|
2
|
-
module SSH
|
|
1
|
+
module Net
|
|
2
|
+
module SSH
|
|
3
3
|
module Transport
|
|
4
4
|
module KeyExpander
|
|
5
|
-
|
|
6
5
|
# Generate a key value in accordance with the SSH2 specification.
|
|
7
6
|
# (RFC4253 7.2. "Output from Key Exchange")
|
|
8
|
-
def self.expand_key(bytes, start, options={})
|
|
7
|
+
def self.expand_key(bytes, start, options = {})
|
|
9
8
|
if bytes == 0
|
|
10
9
|
return ""
|
|
11
10
|
end
|
|
12
|
-
|
|
11
|
+
|
|
13
12
|
k = start[0, bytes]
|
|
14
13
|
return k if k.length >= bytes
|
|
15
|
-
|
|
14
|
+
|
|
16
15
|
digester = options[:digester] or raise 'No digester supplied'
|
|
17
16
|
shared = options[:shared] or raise 'No shared secret supplied'
|
|
18
17
|
hash = options[:hash] or raise 'No hash supplied'
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
while k.length < bytes
|
|
21
20
|
step = digester.digest(shared + hash + k)
|
|
22
21
|
bytes_needed = bytes - k.length
|
|
23
22
|
k << step[0, bytes_needed]
|
|
24
23
|
end
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
return k
|
|
27
26
|
end
|
|
28
27
|
end
|
|
@@ -2,7 +2,6 @@ require 'openssl'
|
|
|
2
2
|
require 'net/ssh/authentication/pub_key_fingerprint'
|
|
3
3
|
|
|
4
4
|
module OpenSSL
|
|
5
|
-
|
|
6
5
|
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
7
6
|
# have been added to it by the Net::SSH module for convenience in dealing with
|
|
8
7
|
# SSH functionality.
|
|
@@ -24,7 +23,6 @@ module OpenSSL
|
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
module PKey
|
|
27
|
-
|
|
28
26
|
class PKey
|
|
29
27
|
include Net::SSH::Authentication::PubKeyFingerprint
|
|
30
28
|
end
|
|
@@ -37,6 +35,7 @@ module OpenSSL
|
|
|
37
35
|
# lifted more-or-less directly from OpenSSH, dh.c, dh_pub_is_valid.)
|
|
38
36
|
def valid?
|
|
39
37
|
return false if pub_key.nil? || pub_key < 0
|
|
38
|
+
|
|
40
39
|
bits_set = 0
|
|
41
40
|
pub_key.num_bits.times { |i| bits_set += 1 if pub_key.bit_set?(i) }
|
|
42
41
|
return (bits_set > 1 && pub_key < p)
|
|
@@ -53,9 +52,7 @@ module OpenSSL
|
|
|
53
52
|
"ssh-rsa"
|
|
54
53
|
end
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
ssh_type
|
|
58
|
-
end
|
|
55
|
+
alias ssh_signature_type ssh_type
|
|
59
56
|
|
|
60
57
|
# Converts the key to a blob, according to the SSH2 protocol.
|
|
61
58
|
def to_blob
|
|
@@ -63,13 +60,30 @@ module OpenSSL
|
|
|
63
60
|
end
|
|
64
61
|
|
|
65
62
|
# Verifies the given signature matches the given data.
|
|
66
|
-
def ssh_do_verify(sig, data)
|
|
67
|
-
|
|
63
|
+
def ssh_do_verify(sig, data, options = {})
|
|
64
|
+
digester =
|
|
65
|
+
if options[:host_key] == "rsa-sha2-512"
|
|
66
|
+
OpenSSL::Digest::SHA512.new
|
|
67
|
+
elsif options[:host_key] == "rsa-sha2-256"
|
|
68
|
+
OpenSSL::Digest::SHA256.new
|
|
69
|
+
else
|
|
70
|
+
OpenSSL::Digest::SHA1.new
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
verify(digester, sig, data)
|
|
68
74
|
end
|
|
69
75
|
|
|
70
76
|
# Returns the signature for the given data.
|
|
71
|
-
def ssh_do_sign(data)
|
|
72
|
-
|
|
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)
|
|
73
87
|
end
|
|
74
88
|
end
|
|
75
89
|
|
|
@@ -83,36 +97,35 @@ module OpenSSL
|
|
|
83
97
|
"ssh-dss"
|
|
84
98
|
end
|
|
85
99
|
|
|
86
|
-
|
|
87
|
-
ssh_type
|
|
88
|
-
end
|
|
100
|
+
alias ssh_signature_type ssh_type
|
|
89
101
|
|
|
90
102
|
# Converts the key to a blob, according to the SSH2 protocol.
|
|
91
103
|
def to_blob
|
|
92
104
|
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
|
93
|
-
|
|
105
|
+
:bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
|
|
94
106
|
end
|
|
95
107
|
|
|
96
108
|
# Verifies the given signature matches the given data.
|
|
97
|
-
def ssh_do_verify(sig, data)
|
|
98
|
-
sig_r = sig[0,20].unpack("H*")[0].to_i(16)
|
|
99
|
-
sig_s = sig[20,20].unpack("H*")[0].to_i(16)
|
|
109
|
+
def ssh_do_verify(sig, data, options = {})
|
|
110
|
+
sig_r = sig[0, 20].unpack("H*")[0].to_i(16)
|
|
111
|
+
sig_s = sig[20, 20].unpack("H*")[0].to_i(16)
|
|
100
112
|
a1sig = OpenSSL::ASN1::Sequence([
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
113
|
+
OpenSSL::ASN1::Integer(sig_r),
|
|
114
|
+
OpenSSL::ASN1::Integer(sig_s)
|
|
115
|
+
])
|
|
104
116
|
return verify(OpenSSL::Digest::SHA1.new, a1sig.to_der, data)
|
|
105
117
|
end
|
|
106
118
|
|
|
107
119
|
# Signs the given data.
|
|
108
|
-
def ssh_do_sign(data)
|
|
120
|
+
def ssh_do_sign(data, sig_alg = nil)
|
|
109
121
|
sig = sign(OpenSSL::Digest::SHA1.new, data)
|
|
110
122
|
a1sig = OpenSSL::ASN1.decode(sig)
|
|
111
123
|
|
|
112
124
|
sig_r = a1sig.value[0].value.to_s(2)
|
|
113
125
|
sig_s = a1sig.value[1].value.to_s(2)
|
|
114
126
|
|
|
115
|
-
|
|
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
|
|
116
129
|
|
|
117
130
|
sig_r = "\0" * (20 - sig_r.length) + sig_r if sig_r.length < 20
|
|
118
131
|
sig_s = "\0" * (20 - sig_s.length) + sig_s if sig_s.length < 20
|
|
@@ -121,116 +134,141 @@ module OpenSSL
|
|
|
121
134
|
end
|
|
122
135
|
end
|
|
123
136
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
begin
|
|
146
|
-
key = OpenSSL::PKey::EC.new(OpenSSL::PKey::EC::CurveNameAlias[curve_name_in_key])
|
|
147
|
-
group = key.group
|
|
148
|
-
point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_oct, 2))
|
|
149
|
-
key.public_key = point
|
|
150
|
-
|
|
151
|
-
return key
|
|
152
|
-
rescue OpenSSL::PKey::ECError
|
|
153
|
-
raise NotImplementedError, "unsupported key type `#{type}'"
|
|
154
|
-
end
|
|
137
|
+
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
138
|
+
# have been added to it by the Net::SSH module for convenience in dealing
|
|
139
|
+
# with SSH functionality.
|
|
140
|
+
class EC
|
|
141
|
+
CurveNameAlias = {
|
|
142
|
+
'nistp256' => 'prime256v1',
|
|
143
|
+
'nistp384' => 'secp384r1',
|
|
144
|
+
'nistp521' => 'secp521r1'
|
|
145
|
+
}.freeze
|
|
146
|
+
|
|
147
|
+
CurveNameAliasInv = {
|
|
148
|
+
'prime256v1' => 'nistp256',
|
|
149
|
+
'secp384r1' => 'nistp384',
|
|
150
|
+
'secp521r1' => 'nistp521'
|
|
151
|
+
}.freeze
|
|
152
|
+
|
|
153
|
+
def self.read_keyblob(curve_name_in_type, buffer)
|
|
154
|
+
curve_name_in_key = buffer.read_string
|
|
155
|
+
|
|
156
|
+
unless curve_name_in_type == curve_name_in_key
|
|
157
|
+
raise Net::SSH::Exception, "curve name mismatched (`#{curve_name_in_key}' with `#{curve_name_in_type}')"
|
|
155
158
|
end
|
|
156
159
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
public_key_oct = buffer.read_string
|
|
161
|
+
begin
|
|
162
|
+
curvename = OpenSSL::PKey::EC::CurveNameAlias[curve_name_in_key]
|
|
163
|
+
group = OpenSSL::PKey::EC::Group.new(curvename)
|
|
164
|
+
point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_oct, 2))
|
|
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)
|
|
178
|
+
|
|
179
|
+
return key
|
|
180
|
+
rescue OpenSSL::PKey::ECError
|
|
181
|
+
raise NotImplementedError, "unsupported key type `#{type}'"
|
|
161
182
|
end
|
|
183
|
+
end
|
|
162
184
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
185
|
+
# Returns the description of this key type used by the
|
|
186
|
+
# SSH2 protocol, like "ecdsa-sha2-nistp256"
|
|
187
|
+
def ssh_type
|
|
188
|
+
"ecdsa-sha2-#{CurveNameAliasInv[group.curve_name]}"
|
|
189
|
+
end
|
|
166
190
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
OpenSSL::Digest::SHA384.new
|
|
174
|
-
else
|
|
175
|
-
OpenSSL::Digest::SHA512.new
|
|
176
|
-
end
|
|
177
|
-
else
|
|
191
|
+
alias ssh_signature_type ssh_type
|
|
192
|
+
|
|
193
|
+
def digester
|
|
194
|
+
if group.curve_name =~ /^[a-z]+(\d+)\w*\z/
|
|
195
|
+
curve_size = Regexp.last_match(1).to_i
|
|
196
|
+
if curve_size <= 256
|
|
178
197
|
OpenSSL::Digest::SHA256.new
|
|
198
|
+
elsif curve_size <= 384
|
|
199
|
+
OpenSSL::Digest::SHA384.new
|
|
200
|
+
else
|
|
201
|
+
OpenSSL::Digest::SHA512.new
|
|
179
202
|
end
|
|
203
|
+
else
|
|
204
|
+
OpenSSL::Digest::SHA256.new
|
|
180
205
|
end
|
|
181
|
-
|
|
206
|
+
end
|
|
207
|
+
private :digester
|
|
182
208
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
209
|
+
# Converts the key to a blob, according to the SSH2 protocol.
|
|
210
|
+
def to_blob
|
|
211
|
+
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
|
212
|
+
:string, CurveNameAliasInv[group.curve_name],
|
|
213
|
+
:mstring, public_key.to_bn.to_s(2)).to_s
|
|
214
|
+
@blob
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Verifies the given signature matches the given data.
|
|
218
|
+
def ssh_do_verify(sig, data, options = {})
|
|
219
|
+
digest = digester.digest(data)
|
|
220
|
+
a1sig = nil
|
|
221
|
+
|
|
222
|
+
begin
|
|
223
|
+
sig_r_len = sig[0, 4].unpack('H*')[0].to_i(16)
|
|
224
|
+
sig_l_len = sig[4 + sig_r_len, 4].unpack('H*')[0].to_i(16)
|
|
225
|
+
|
|
226
|
+
sig_r = sig[4, sig_r_len].unpack('H*')[0]
|
|
227
|
+
sig_s = sig[4 + sig_r_len + 4, sig_l_len].unpack('H*')[0]
|
|
228
|
+
|
|
229
|
+
a1sig = OpenSSL::ASN1::Sequence([
|
|
230
|
+
OpenSSL::ASN1::Integer(sig_r.to_i(16)),
|
|
231
|
+
OpenSSL::ASN1::Integer(sig_s.to_i(16))
|
|
232
|
+
])
|
|
233
|
+
rescue StandardError
|
|
189
234
|
end
|
|
190
235
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
a1sig
|
|
236
|
+
if a1sig.nil?
|
|
237
|
+
return false
|
|
238
|
+
else
|
|
239
|
+
dsa_verify_asn1(digest, a1sig.to_der)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
195
242
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
243
|
+
# Returns the signature for the given data.
|
|
244
|
+
def ssh_do_sign(data, sig_alg = nil)
|
|
245
|
+
digest = digester.digest(data)
|
|
246
|
+
sig = dsa_sign_asn1(digest)
|
|
247
|
+
a1sig = OpenSSL::ASN1.decode(sig)
|
|
199
248
|
|
|
200
|
-
|
|
201
|
-
|
|
249
|
+
sig_r = a1sig.value[0].value
|
|
250
|
+
sig_s = a1sig.value[1].value
|
|
202
251
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
OpenSSL::ASN1::Integer(sig_s.to_i(16))
|
|
206
|
-
])
|
|
207
|
-
rescue StandardError
|
|
208
|
-
end
|
|
252
|
+
Net::SSH::Buffer.from(:bignum, sig_r, :bignum, sig_s).to_s
|
|
253
|
+
end
|
|
209
254
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
255
|
+
class Point
|
|
256
|
+
# Returns the description of this key type used by the
|
|
257
|
+
# SSH2 protocol, like "ecdsa-sha2-nistp256"
|
|
258
|
+
def ssh_type
|
|
259
|
+
"ecdsa-sha2-#{CurveNameAliasInv[group.curve_name]}"
|
|
215
260
|
end
|
|
216
261
|
|
|
217
|
-
|
|
218
|
-
def ssh_do_sign(data)
|
|
219
|
-
digest = digester.digest(data)
|
|
220
|
-
sig = dsa_sign_asn1(digest)
|
|
221
|
-
a1sig = OpenSSL::ASN1.decode(sig)
|
|
222
|
-
|
|
223
|
-
sig_r = a1sig.value[0].value
|
|
224
|
-
sig_s = a1sig.value[1].value
|
|
262
|
+
alias ssh_signature_type ssh_type
|
|
225
263
|
|
|
226
|
-
|
|
264
|
+
# Converts the key to a blob, according to the SSH2 protocol.
|
|
265
|
+
def to_blob
|
|
266
|
+
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
|
267
|
+
:string, CurveNameAliasInv[group.curve_name],
|
|
268
|
+
:mstring, to_bn.to_s(2)).to_s
|
|
269
|
+
@blob
|
|
227
270
|
end
|
|
228
271
|
end
|
|
229
|
-
else
|
|
230
|
-
class OpenSSL::PKey::ECError < RuntimeError
|
|
231
|
-
# for compatibility with interpreters
|
|
232
|
-
# without EC support (i.e. JRuby)
|
|
233
|
-
end
|
|
234
272
|
end
|
|
235
273
|
end
|
|
236
274
|
end
|