net-ssh 4.2.0 → 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 +5 -5
- 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 +7 -0
- data/.rubocop.yml +19 -2
- data/.rubocop_todo.yml +619 -667
- data/CHANGES.txt +110 -1
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +3 -7
- data/{Gemfile.norbnacl → Gemfile.noed25519} +3 -1
- data/Manifest +4 -5
- data/README.md +293 -0
- data/Rakefile +45 -29
- data/appveyor.yml +8 -6
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +248 -223
- data/lib/net/ssh/authentication/certificate.rb +178 -164
- data/lib/net/ssh/authentication/constants.rb +17 -15
- data/lib/net/ssh/authentication/ed25519.rb +141 -116
- data/lib/net/ssh/authentication/ed25519_loader.rb +28 -28
- data/lib/net/ssh/authentication/key_manager.rb +79 -36
- data/lib/net/ssh/authentication/methods/abstract.rb +62 -47
- data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -3
- data/lib/net/ssh/authentication/methods/none.rb +16 -19
- data/lib/net/ssh/authentication/methods/password.rb +15 -16
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
- data/lib/net/ssh/authentication/pageant.rb +468 -465
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +131 -122
- data/lib/net/ssh/buffer.rb +385 -332
- data/lib/net/ssh/buffered_io.rb +150 -151
- data/lib/net/ssh/config.rb +316 -239
- data/lib/net/ssh/connection/channel.rb +635 -613
- data/lib/net/ssh/connection/constants.rb +29 -29
- data/lib/net/ssh/connection/event_loop.rb +104 -95
- data/lib/net/ssh/connection/keepalive.rb +55 -51
- data/lib/net/ssh/connection/session.rb +614 -611
- data/lib/net/ssh/connection/term.rb +125 -123
- data/lib/net/ssh/errors.rb +101 -99
- data/lib/net/ssh/key_factory.rb +194 -108
- data/lib/net/ssh/known_hosts.rb +212 -134
- data/lib/net/ssh/loggable.rb +50 -49
- data/lib/net/ssh/packet.rb +83 -79
- data/lib/net/ssh/prompt.rb +51 -51
- data/lib/net/ssh/proxy/command.rb +105 -91
- data/lib/net/ssh/proxy/errors.rb +12 -10
- data/lib/net/ssh/proxy/http.rb +81 -81
- data/lib/net/ssh/proxy/https.rb +37 -36
- data/lib/net/ssh/proxy/jump.rb +49 -48
- data/lib/net/ssh/proxy/socks4.rb +2 -6
- data/lib/net/ssh/proxy/socks5.rb +14 -17
- data/lib/net/ssh/service/forward.rb +365 -362
- data/lib/net/ssh/test/channel.rb +145 -143
- data/lib/net/ssh/test/extensions.rb +131 -127
- data/lib/net/ssh/test/kex.rb +34 -32
- data/lib/net/ssh/test/local_packet.rb +46 -44
- data/lib/net/ssh/test/packet.rb +87 -84
- data/lib/net/ssh/test/remote_packet.rb +32 -30
- data/lib/net/ssh/test/script.rb +155 -155
- data/lib/net/ssh/test/socket.rb +49 -48
- data/lib/net/ssh/test.rb +82 -80
- data/lib/net/ssh/transport/algorithms.rb +433 -364
- data/lib/net/ssh/transport/cipher_factory.rb +95 -91
- data/lib/net/ssh/transport/constants.rb +32 -24
- data/lib/net/ssh/transport/ctr.rb +37 -15
- data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
- 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 +14 -12
- data/lib/net/ssh/transport/identity_cipher.rb +54 -52
- 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 +33 -40
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -63
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
- data/lib/net/ssh/transport/kex.rb +15 -12
- data/lib/net/ssh/transport/key_expander.rb +24 -21
- data/lib/net/ssh/transport/openssl.rb +158 -133
- data/lib/net/ssh/transport/packet_stream.rb +223 -191
- data/lib/net/ssh/transport/server_version.rb +55 -56
- data/lib/net/ssh/transport/session.rb +306 -259
- data/lib/net/ssh/transport/state.rb +178 -176
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +55 -53
- data/lib/net/ssh.rb +47 -34
- data/net-ssh-public_cert.pem +18 -19
- data/net-ssh.gemspec +12 -11
- data/support/ssh_tunnel_bug.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +78 -73
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -51
- data/Gemfile.norbnacl.lock +0 -41
- data/README.rdoc +0 -169
- data/lib/net/ssh/ruby_compat.rb +0 -24
- data/lib/net/ssh/verifiers/lenient.rb +0 -30
- data/lib/net/ssh/verifiers/null.rb +0 -12
- data/lib/net/ssh/verifiers/secure.rb +0 -52
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/support/arcfour_check.rb +0 -20
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
module Net
|
|
4
|
+
module SSH
|
|
5
|
+
module Transport
|
|
6
|
+
module Kex
|
|
7
|
+
# A key-exchange service implementing the "ecdh-sha2-nistp521"
|
|
8
|
+
# key-exchange algorithm. (defined in RFC 5656)
|
|
9
|
+
class EcdhSHA2NistP521 < EcdhSHA2NistP256
|
|
10
|
+
def digester
|
|
11
|
+
OpenSSL::Digest::SHA512
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def curve_name
|
|
15
|
+
OpenSSL::PKey::EC::CurveNameAlias['nistp521']
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
11
19
|
end
|
|
12
20
|
end
|
|
13
|
-
end
|
|
21
|
+
end
|
|
@@ -1,28 +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
|
-
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
25
|
|
|
23
|
-
|
|
24
|
-
MAP['
|
|
25
|
-
MAP['
|
|
26
|
+
if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
|
|
27
|
+
MAP['curve25519-sha256'] = Curve25519Sha256
|
|
28
|
+
MAP['curve25519-sha256@libssh.org'] = Curve25519Sha256
|
|
26
29
|
end
|
|
27
30
|
end
|
|
28
31
|
end
|
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
module Net
|
|
2
|
-
module
|
|
1
|
+
module Net
|
|
2
|
+
module SSH
|
|
3
|
+
module Transport
|
|
4
|
+
module KeyExpander
|
|
5
|
+
# Generate a key value in accordance with the SSH2 specification.
|
|
6
|
+
# (RFC4253 7.2. "Output from Key Exchange")
|
|
7
|
+
def self.expand_key(bytes, start, options = {})
|
|
8
|
+
if bytes == 0
|
|
9
|
+
return ""
|
|
10
|
+
end
|
|
3
11
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def self.expand_key(bytes, start, options={})
|
|
7
|
-
if bytes == 0
|
|
8
|
-
return ""
|
|
9
|
-
end
|
|
12
|
+
k = start[0, bytes]
|
|
13
|
+
return k if k.length >= bytes
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
digester = options[:digester] or raise 'No digester supplied'
|
|
16
|
+
shared = options[:shared] or raise 'No shared secret supplied'
|
|
17
|
+
hash = options[:hash] or raise 'No hash supplied'
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
while k.length < bytes
|
|
20
|
+
step = digester.digest(shared + hash + k)
|
|
21
|
+
bytes_needed = bytes - k.length
|
|
22
|
+
k << step[0, bytes_needed]
|
|
23
|
+
end
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
k << step[0, bytes_needed]
|
|
25
|
+
return k
|
|
26
|
+
end
|
|
27
|
+
end
|
|
22
28
|
end
|
|
23
|
-
|
|
24
|
-
return k
|
|
25
|
-
end
|
|
26
29
|
end
|
|
27
|
-
end
|
|
30
|
+
end
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
require 'openssl'
|
|
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.
|
|
9
8
|
class BN
|
|
10
|
-
|
|
11
9
|
# Converts a BN object to a string. The format used is that which is
|
|
12
10
|
# required by the SSH2 protocol.
|
|
13
11
|
def to_ssh
|
|
@@ -16,53 +14,45 @@ module OpenSSL
|
|
|
16
14
|
else
|
|
17
15
|
buf = to_s(2)
|
|
18
16
|
if buf.getbyte(0)[7] == 1
|
|
19
|
-
return [buf.length+1, 0, buf].pack("NCA*")
|
|
17
|
+
return [buf.length + 1, 0, buf].pack("NCA*")
|
|
20
18
|
else
|
|
21
19
|
return [buf.length, buf].pack("NA*")
|
|
22
20
|
end
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
|
-
|
|
26
23
|
end
|
|
27
24
|
|
|
28
25
|
module PKey
|
|
29
|
-
|
|
30
26
|
class PKey
|
|
31
|
-
|
|
32
|
-
@fingerprint ||= OpenSSL::Digest::MD5.hexdigest(to_blob).scan(/../).join(":")
|
|
33
|
-
end
|
|
27
|
+
include Net::SSH::Authentication::PubKeyFingerprint
|
|
34
28
|
end
|
|
35
29
|
|
|
36
30
|
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
37
31
|
# have been added to it by the Net::SSH module for convenience in dealing
|
|
38
32
|
# with SSH functionality.
|
|
39
33
|
class DH
|
|
40
|
-
|
|
41
34
|
# Determines whether the pub_key for this key is valid. (This algorithm
|
|
42
35
|
# lifted more-or-less directly from OpenSSH, dh.c, dh_pub_is_valid.)
|
|
43
36
|
def valid?
|
|
44
37
|
return false if pub_key.nil? || pub_key < 0
|
|
38
|
+
|
|
45
39
|
bits_set = 0
|
|
46
40
|
pub_key.num_bits.times { |i| bits_set += 1 if pub_key.bit_set?(i) }
|
|
47
|
-
return (
|
|
41
|
+
return (bits_set > 1 && pub_key < p)
|
|
48
42
|
end
|
|
49
|
-
|
|
50
43
|
end
|
|
51
44
|
|
|
52
45
|
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
53
46
|
# have been added to it by the Net::SSH module for convenience in dealing
|
|
54
47
|
# with SSH functionality.
|
|
55
48
|
class RSA
|
|
56
|
-
|
|
57
49
|
# Returns "ssh-rsa", which is the description of this key type used by the
|
|
58
50
|
# SSH2 protocol.
|
|
59
51
|
def ssh_type
|
|
60
52
|
"ssh-rsa"
|
|
61
53
|
end
|
|
62
54
|
|
|
63
|
-
|
|
64
|
-
ssh_type
|
|
65
|
-
end
|
|
55
|
+
alias ssh_signature_type ssh_type
|
|
66
56
|
|
|
67
57
|
# Converts the key to a blob, according to the SSH2 protocol.
|
|
68
58
|
def to_blob
|
|
@@ -70,13 +60,30 @@ module OpenSSL
|
|
|
70
60
|
end
|
|
71
61
|
|
|
72
62
|
# Verifies the given signature matches the given data.
|
|
73
|
-
def ssh_do_verify(sig, data)
|
|
74
|
-
|
|
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)
|
|
75
74
|
end
|
|
76
75
|
|
|
77
76
|
# Returns the signature for the given data.
|
|
78
|
-
def ssh_do_sign(data)
|
|
79
|
-
|
|
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)
|
|
80
87
|
end
|
|
81
88
|
end
|
|
82
89
|
|
|
@@ -84,166 +91,184 @@ module OpenSSL
|
|
|
84
91
|
# have been added to it by the Net::SSH module for convenience in dealing
|
|
85
92
|
# with SSH functionality.
|
|
86
93
|
class DSA
|
|
87
|
-
|
|
88
94
|
# Returns "ssh-dss", which is the description of this key type used by the
|
|
89
95
|
# SSH2 protocol.
|
|
90
96
|
def ssh_type
|
|
91
97
|
"ssh-dss"
|
|
92
98
|
end
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
ssh_type
|
|
96
|
-
end
|
|
100
|
+
alias ssh_signature_type ssh_type
|
|
97
101
|
|
|
98
102
|
# Converts the key to a blob, according to the SSH2 protocol.
|
|
99
103
|
def to_blob
|
|
100
104
|
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
|
101
|
-
|
|
105
|
+
:bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
|
|
102
106
|
end
|
|
103
107
|
|
|
104
108
|
# Verifies the given signature matches the given data.
|
|
105
|
-
def ssh_do_verify(sig, data)
|
|
106
|
-
sig_r = sig[0,20].unpack("H*")[0].to_i(16)
|
|
107
|
-
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)
|
|
108
112
|
a1sig = OpenSSL::ASN1::Sequence([
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return verify(OpenSSL::Digest::
|
|
113
|
+
OpenSSL::ASN1::Integer(sig_r),
|
|
114
|
+
OpenSSL::ASN1::Integer(sig_s)
|
|
115
|
+
])
|
|
116
|
+
return verify(OpenSSL::Digest::SHA1.new, a1sig.to_der, data)
|
|
113
117
|
end
|
|
114
118
|
|
|
115
119
|
# Signs the given data.
|
|
116
|
-
def ssh_do_sign(data)
|
|
117
|
-
sig = sign(
|
|
118
|
-
a1sig = OpenSSL::ASN1.decode(
|
|
120
|
+
def ssh_do_sign(data, sig_alg = nil)
|
|
121
|
+
sig = sign(OpenSSL::Digest::SHA1.new, data)
|
|
122
|
+
a1sig = OpenSSL::ASN1.decode(sig)
|
|
119
123
|
|
|
120
124
|
sig_r = a1sig.value[0].value.to_s(2)
|
|
121
125
|
sig_s = a1sig.value[1].value.to_s(2)
|
|
122
126
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
end
|
|
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
|
|
126
129
|
|
|
127
|
-
sig_r = "\0" * (
|
|
128
|
-
sig_s = "\0" * (
|
|
130
|
+
sig_r = "\0" * (20 - sig_r.length) + sig_r if sig_r.length < 20
|
|
131
|
+
sig_s = "\0" * (20 - sig_s.length) + sig_s if sig_s.length < 20
|
|
129
132
|
|
|
130
133
|
return sig_r + sig_s
|
|
131
134
|
end
|
|
132
135
|
end
|
|
133
136
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
end
|
|
156
|
-
public_key_oct = buffer.read_string
|
|
157
|
-
begin
|
|
158
|
-
key = OpenSSL::PKey::EC.new(OpenSSL::PKey::EC::CurveNameAlias[curve_name_in_key])
|
|
159
|
-
group = key.group
|
|
160
|
-
point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_oct, 2))
|
|
161
|
-
key.public_key = point
|
|
162
|
-
|
|
163
|
-
return key
|
|
164
|
-
rescue OpenSSL::PKey::ECError
|
|
165
|
-
raise NotImplementedError, "unsupported key type `#{type}'"
|
|
166
|
-
end
|
|
167
|
-
|
|
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}')"
|
|
168
158
|
end
|
|
169
159
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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}'"
|
|
174
182
|
end
|
|
183
|
+
end
|
|
175
184
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
|
179
190
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
OpenSSL::Digest::SHA384.new
|
|
187
|
-
else
|
|
188
|
-
OpenSSL::Digest::SHA512.new
|
|
189
|
-
end
|
|
190
|
-
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
|
|
191
197
|
OpenSSL::Digest::SHA256.new
|
|
198
|
+
elsif curve_size <= 384
|
|
199
|
+
OpenSSL::Digest::SHA384.new
|
|
200
|
+
else
|
|
201
|
+
OpenSSL::Digest::SHA512.new
|
|
192
202
|
end
|
|
203
|
+
else
|
|
204
|
+
OpenSSL::Digest::SHA256.new
|
|
193
205
|
end
|
|
194
|
-
|
|
206
|
+
end
|
|
207
|
+
private :digester
|
|
195
208
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
|
202
234
|
end
|
|
203
235
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
a1sig
|
|
236
|
+
if a1sig.nil?
|
|
237
|
+
return false
|
|
238
|
+
else
|
|
239
|
+
dsa_verify_asn1(digest, a1sig.to_der)
|
|
240
|
+
end
|
|
241
|
+
end
|
|
208
242
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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)
|
|
212
248
|
|
|
213
|
-
|
|
214
|
-
|
|
249
|
+
sig_r = a1sig.value[0].value
|
|
250
|
+
sig_s = a1sig.value[1].value
|
|
215
251
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
OpenSSL::ASN1::Integer(sig_s.to_i(16)),
|
|
219
|
-
])
|
|
220
|
-
rescue
|
|
221
|
-
end
|
|
252
|
+
Net::SSH::Buffer.from(:bignum, sig_r, :bignum, sig_s).to_s
|
|
253
|
+
end
|
|
222
254
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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]}"
|
|
228
260
|
end
|
|
229
261
|
|
|
230
|
-
|
|
231
|
-
def ssh_do_sign(data)
|
|
232
|
-
digest = digester.digest(data)
|
|
233
|
-
sig = dsa_sign_asn1(digest)
|
|
234
|
-
a1sig = OpenSSL::ASN1.decode( sig )
|
|
262
|
+
alias ssh_signature_type ssh_type
|
|
235
263
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
|
240
270
|
end
|
|
241
271
|
end
|
|
242
|
-
else
|
|
243
|
-
class OpenSSL::PKey::ECError < RuntimeError
|
|
244
|
-
# for compatibility with interpreters
|
|
245
|
-
# without EC support (i.e. JRuby)
|
|
246
|
-
end
|
|
247
272
|
end
|
|
248
273
|
end
|
|
249
274
|
end
|