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.
Files changed (126) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/config/rubocop_linter_action.yml +4 -0
  5. data/.github/workflows/ci-with-docker.yml +44 -0
  6. data/.github/workflows/ci.yml +87 -0
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.gitignore +7 -0
  9. data/.rubocop.yml +19 -2
  10. data/.rubocop_todo.yml +619 -667
  11. data/CHANGES.txt +110 -1
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +3 -7
  15. data/{Gemfile.norbnacl → Gemfile.noed25519} +3 -1
  16. data/Manifest +4 -5
  17. data/README.md +293 -0
  18. data/Rakefile +45 -29
  19. data/appveyor.yml +8 -6
  20. data/docker-compose.yml +23 -0
  21. data/lib/net/ssh/authentication/agent.rb +248 -223
  22. data/lib/net/ssh/authentication/certificate.rb +178 -164
  23. data/lib/net/ssh/authentication/constants.rb +17 -15
  24. data/lib/net/ssh/authentication/ed25519.rb +141 -116
  25. data/lib/net/ssh/authentication/ed25519_loader.rb +28 -28
  26. data/lib/net/ssh/authentication/key_manager.rb +79 -36
  27. data/lib/net/ssh/authentication/methods/abstract.rb +62 -47
  28. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  29. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -3
  30. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  31. data/lib/net/ssh/authentication/methods/password.rb +15 -16
  32. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  33. data/lib/net/ssh/authentication/pageant.rb +468 -465
  34. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  35. data/lib/net/ssh/authentication/session.rb +131 -122
  36. data/lib/net/ssh/buffer.rb +385 -332
  37. data/lib/net/ssh/buffered_io.rb +150 -151
  38. data/lib/net/ssh/config.rb +316 -239
  39. data/lib/net/ssh/connection/channel.rb +635 -613
  40. data/lib/net/ssh/connection/constants.rb +29 -29
  41. data/lib/net/ssh/connection/event_loop.rb +104 -95
  42. data/lib/net/ssh/connection/keepalive.rb +55 -51
  43. data/lib/net/ssh/connection/session.rb +614 -611
  44. data/lib/net/ssh/connection/term.rb +125 -123
  45. data/lib/net/ssh/errors.rb +101 -99
  46. data/lib/net/ssh/key_factory.rb +194 -108
  47. data/lib/net/ssh/known_hosts.rb +212 -134
  48. data/lib/net/ssh/loggable.rb +50 -49
  49. data/lib/net/ssh/packet.rb +83 -79
  50. data/lib/net/ssh/prompt.rb +51 -51
  51. data/lib/net/ssh/proxy/command.rb +105 -91
  52. data/lib/net/ssh/proxy/errors.rb +12 -10
  53. data/lib/net/ssh/proxy/http.rb +81 -81
  54. data/lib/net/ssh/proxy/https.rb +37 -36
  55. data/lib/net/ssh/proxy/jump.rb +49 -48
  56. data/lib/net/ssh/proxy/socks4.rb +2 -6
  57. data/lib/net/ssh/proxy/socks5.rb +14 -17
  58. data/lib/net/ssh/service/forward.rb +365 -362
  59. data/lib/net/ssh/test/channel.rb +145 -143
  60. data/lib/net/ssh/test/extensions.rb +131 -127
  61. data/lib/net/ssh/test/kex.rb +34 -32
  62. data/lib/net/ssh/test/local_packet.rb +46 -44
  63. data/lib/net/ssh/test/packet.rb +87 -84
  64. data/lib/net/ssh/test/remote_packet.rb +32 -30
  65. data/lib/net/ssh/test/script.rb +155 -155
  66. data/lib/net/ssh/test/socket.rb +49 -48
  67. data/lib/net/ssh/test.rb +82 -80
  68. data/lib/net/ssh/transport/algorithms.rb +433 -364
  69. data/lib/net/ssh/transport/cipher_factory.rb +95 -91
  70. data/lib/net/ssh/transport/constants.rb +32 -24
  71. data/lib/net/ssh/transport/ctr.rb +37 -15
  72. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  73. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  80. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  81. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  82. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  83. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  84. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  85. data/lib/net/ssh/transport/hmac.rb +14 -12
  86. data/lib/net/ssh/transport/identity_cipher.rb +54 -52
  87. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  88. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  89. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  90. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -63
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  96. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  97. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  99. data/lib/net/ssh/transport/kex.rb +15 -12
  100. data/lib/net/ssh/transport/key_expander.rb +24 -21
  101. data/lib/net/ssh/transport/openssl.rb +158 -133
  102. data/lib/net/ssh/transport/packet_stream.rb +223 -191
  103. data/lib/net/ssh/transport/server_version.rb +55 -56
  104. data/lib/net/ssh/transport/session.rb +306 -259
  105. data/lib/net/ssh/transport/state.rb +178 -176
  106. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  107. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  108. data/lib/net/ssh/verifiers/always.rb +58 -0
  109. data/lib/net/ssh/verifiers/never.rb +19 -0
  110. data/lib/net/ssh/version.rb +55 -53
  111. data/lib/net/ssh.rb +47 -34
  112. data/net-ssh-public_cert.pem +18 -19
  113. data/net-ssh.gemspec +12 -11
  114. data/support/ssh_tunnel_bug.rb +5 -5
  115. data.tar.gz.sig +0 -0
  116. metadata +78 -73
  117. metadata.gz.sig +0 -0
  118. data/.travis.yml +0 -51
  119. data/Gemfile.norbnacl.lock +0 -41
  120. data/README.rdoc +0 -169
  121. data/lib/net/ssh/ruby_compat.rb +0 -24
  122. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  123. data/lib/net/ssh/verifiers/null.rb +0 -12
  124. data/lib/net/ssh/verifiers/secure.rb +0 -52
  125. data/lib/net/ssh/verifiers/strict.rb +0 -24
  126. data/support/arcfour_check.rb +0 -20
@@ -1,13 +1,21 @@
1
- module Net; module SSH; module Transport; module Kex
1
+ require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
2
2
 
3
- # A key-exchange service implementing the "ecdh-sha2-nistp521"
4
- # key-exchange algorithm. (defined in RFC 5656)
5
- class EcdhSHA2NistP521 < EcdhSHA2NistP256
6
- def digester
7
- OpenSSL::Digest::SHA512
8
- end
9
- def curve_name
10
- OpenSSL::PKey::EC::CurveNameAlias['nistp521']
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; end; end; 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-group1-sha1' => DiffieHellmanGroup1SHA1,
13
- 'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
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
- MAP['ecdh-sha2-nistp256'] = EcdhSHA2NistP256
24
- MAP['ecdh-sha2-nistp384'] = EcdhSHA2NistP384
25
- MAP['ecdh-sha2-nistp521'] = EcdhSHA2NistP521
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; module SSH; module Transport
2
- module KeyExpander
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
- # Generate a key value in accordance with the SSH2 specification.
5
- # (RFC4253 7.2. "Output from Key Exchange")
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
- k = start[0, bytes]
12
- return k if k.length >= bytes
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
- digester = options[:digester] or raise 'No digester supplied'
15
- shared = options[:shared] or raise 'No shared secret supplied'
16
- hash = options[:hash] or raise 'No hash supplied'
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
- while k.length < bytes
19
- step = digester.digest(shared + hash + k)
20
- bytes_needed = bytes - k.length
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; end; 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
- def fingerprint
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 ( bits_set > 1 && pub_key < p )
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
- def ssh_signature_type
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
- verify(OpenSSL::Digest::SHA1.new, sig, data)
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
- sign(OpenSSL::Digest::SHA1.new, data)
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
- def ssh_signature_type
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
- :bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
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
- OpenSSL::ASN1::Integer(sig_r),
110
- OpenSSL::ASN1::Integer(sig_s)
111
- ])
112
- return verify(OpenSSL::Digest::DSS1.new, a1sig.to_der, data)
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( OpenSSL::Digest::DSS1.new, data)
118
- a1sig = OpenSSL::ASN1.decode( sig )
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
- if sig_r.length > 20 || sig_s.length > 20
124
- raise OpenSSL::PKey::DSAError, "bad sig size"
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" * ( 20 - sig_r.length ) + sig_r if sig_r.length < 20
128
- sig_s = "\0" * ( 20 - sig_s.length ) + sig_s if sig_s.length < 20
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
- if defined?(OpenSSL::PKey::EC)
135
- # This class is originally defined in the OpenSSL module. As needed, methods
136
- # have been added to it by the Net::SSH module for convenience in dealing
137
- # with SSH functionality.
138
- class EC
139
- CurveNameAlias = {
140
- "nistp256" => "prime256v1",
141
- "nistp384" => "secp384r1",
142
- "nistp521" => "secp521r1",
143
- }
144
-
145
- CurveNameAliasInv = {
146
- "prime256v1" => "nistp256",
147
- "secp384r1" => "nistp384",
148
- "secp521r1" => "nistp521",
149
- }
150
-
151
- def self.read_keyblob(curve_name_in_type, buffer)
152
- curve_name_in_key = buffer.read_string
153
- unless curve_name_in_type == curve_name_in_key
154
- raise Net::SSH::Exception, "curve name mismatched (`#{curve_name_in_key}' with `#{curve_name_in_type}')"
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
- # Returns the description of this key type used by the
171
- # SSH2 protocol, like "ecdsa-sha2-nistp256"
172
- def ssh_type
173
- "ecdsa-sha2-#{CurveNameAliasInv[self.group.curve_name]}"
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
- def ssh_signature_type
177
- ssh_type
178
- end
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
- def digester
181
- if self.group.curve_name =~ /^[a-z]+(\d+)\w*\z/
182
- curve_size = $1.to_i
183
- if curve_size <= 256
184
- OpenSSL::Digest::SHA256.new
185
- elsif curve_size <= 384
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
- private :digester
206
+ end
207
+ private :digester
195
208
 
196
- # Converts the key to a blob, according to the SSH2 protocol.
197
- def to_blob
198
- @blob ||= Net::SSH::Buffer.from(:string, ssh_type,
199
- :string, CurveNameAliasInv[self.group.curve_name],
200
- :mstring, self.public_key.to_bn.to_s(2)).to_s
201
- @blob
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
- # Verifies the given signature matches the given data.
205
- def ssh_do_verify(sig, data)
206
- digest = digester.digest(data)
207
- a1sig = nil
236
+ if a1sig.nil?
237
+ return false
238
+ else
239
+ dsa_verify_asn1(digest, a1sig.to_der)
240
+ end
241
+ end
208
242
 
209
- begin
210
- sig_r_len = sig[0,4].unpack("H*")[0].to_i(16)
211
- sig_l_len = sig[4+sig_r_len,4].unpack("H*")[0].to_i(16)
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
- sig_r = sig[4,sig_r_len].unpack("H*")[0]
214
- sig_s = sig[4+sig_r_len+4,sig_l_len].unpack("H*")[0]
249
+ sig_r = a1sig.value[0].value
250
+ sig_s = a1sig.value[1].value
215
251
 
216
- a1sig = OpenSSL::ASN1::Sequence([
217
- OpenSSL::ASN1::Integer(sig_r.to_i(16)),
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
- if a1sig == nil
224
- return false
225
- else
226
- dsa_verify_asn1(digest, a1sig.to_der)
227
- end
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
- # Returns the signature for the given data.
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
- sig_r = a1sig.value[0].value
237
- sig_s = a1sig.value[1].value
238
-
239
- return Net::SSH::Buffer.from(:bignum, sig_r, :bignum, sig_s).to_s
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