net-ssh 3.2.0.rc2 → 7.1.0

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 (204) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +2 -2
  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 +16 -0
  8. data/.gitignore +13 -0
  9. data/.rubocop.yml +22 -0
  10. data/.rubocop_todo.yml +1081 -0
  11. data/CHANGES.txt +228 -7
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +13 -0
  15. data/Gemfile.noed25519 +12 -0
  16. data/ISSUE_TEMPLATE.md +30 -0
  17. data/Manifest +4 -5
  18. data/README.md +297 -0
  19. data/Rakefile +125 -74
  20. data/SECURITY.md +4 -0
  21. data/appveyor.yml +58 -0
  22. data/docker-compose.yml +23 -0
  23. data/lib/net/ssh/authentication/agent.rb +279 -18
  24. data/lib/net/ssh/authentication/certificate.rb +183 -0
  25. data/lib/net/ssh/authentication/constants.rb +17 -15
  26. data/lib/net/ssh/authentication/ed25519.rb +186 -0
  27. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  28. data/lib/net/ssh/authentication/key_manager.rb +86 -39
  29. data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
  30. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  31. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +13 -13
  32. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  33. data/lib/net/ssh/authentication/methods/password.rb +27 -17
  34. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  35. data/lib/net/ssh/authentication/pageant.rb +471 -367
  36. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  37. data/lib/net/ssh/authentication/session.rb +131 -121
  38. data/lib/net/ssh/buffer.rb +399 -300
  39. data/lib/net/ssh/buffered_io.rb +154 -150
  40. data/lib/net/ssh/config.rb +308 -185
  41. data/lib/net/ssh/connection/channel.rb +635 -613
  42. data/lib/net/ssh/connection/constants.rb +29 -29
  43. data/lib/net/ssh/connection/event_loop.rb +123 -0
  44. data/lib/net/ssh/connection/keepalive.rb +55 -51
  45. data/lib/net/ssh/connection/session.rb +620 -551
  46. data/lib/net/ssh/connection/term.rb +125 -123
  47. data/lib/net/ssh/errors.rb +101 -99
  48. data/lib/net/ssh/key_factory.rb +197 -105
  49. data/lib/net/ssh/known_hosts.rb +214 -127
  50. data/lib/net/ssh/loggable.rb +50 -49
  51. data/lib/net/ssh/packet.rb +83 -79
  52. data/lib/net/ssh/prompt.rb +50 -81
  53. data/lib/net/ssh/proxy/command.rb +105 -90
  54. data/lib/net/ssh/proxy/errors.rb +12 -10
  55. data/lib/net/ssh/proxy/http.rb +82 -79
  56. data/lib/net/ssh/proxy/https.rb +50 -0
  57. data/lib/net/ssh/proxy/jump.rb +54 -0
  58. data/lib/net/ssh/proxy/socks4.rb +2 -6
  59. data/lib/net/ssh/proxy/socks5.rb +14 -17
  60. data/lib/net/ssh/service/forward.rb +370 -317
  61. data/lib/net/ssh/test/channel.rb +145 -136
  62. data/lib/net/ssh/test/extensions.rb +131 -110
  63. data/lib/net/ssh/test/kex.rb +34 -32
  64. data/lib/net/ssh/test/local_packet.rb +46 -44
  65. data/lib/net/ssh/test/packet.rb +89 -70
  66. data/lib/net/ssh/test/remote_packet.rb +32 -30
  67. data/lib/net/ssh/test/script.rb +156 -142
  68. data/lib/net/ssh/test/socket.rb +49 -48
  69. data/lib/net/ssh/test.rb +82 -77
  70. data/lib/net/ssh/transport/algorithms.rb +441 -360
  71. data/lib/net/ssh/transport/cipher_factory.rb +96 -98
  72. data/lib/net/ssh/transport/constants.rb +32 -24
  73. data/lib/net/ssh/transport/ctr.rb +42 -22
  74. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  75. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  80. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  81. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  82. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  83. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  84. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  85. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  86. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  87. data/lib/net/ssh/transport/hmac.rb +14 -12
  88. data/lib/net/ssh/transport/identity_cipher.rb +54 -52
  89. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  90. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  91. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  92. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
  96. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
  97. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  99. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  100. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  101. data/lib/net/ssh/transport/kex.rb +15 -12
  102. data/lib/net/ssh/transport/key_expander.rb +24 -20
  103. data/lib/net/ssh/transport/openssl.rb +161 -124
  104. data/lib/net/ssh/transport/packet_stream.rb +225 -185
  105. data/lib/net/ssh/transport/server_version.rb +55 -56
  106. data/lib/net/ssh/transport/session.rb +306 -255
  107. data/lib/net/ssh/transport/state.rb +178 -176
  108. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  109. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  110. data/lib/net/ssh/verifiers/always.rb +58 -0
  111. data/lib/net/ssh/verifiers/never.rb +19 -0
  112. data/lib/net/ssh/version.rb +55 -53
  113. data/lib/net/ssh.rb +110 -47
  114. data/net-ssh-public_cert.pem +18 -18
  115. data/net-ssh.gemspec +36 -205
  116. data/support/ssh_tunnel_bug.rb +5 -5
  117. data.tar.gz.sig +0 -0
  118. metadata +153 -118
  119. metadata.gz.sig +0 -0
  120. data/.travis.yml +0 -18
  121. data/README.rdoc +0 -182
  122. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  123. data/lib/net/ssh/authentication/agent/socket.rb +0 -178
  124. data/lib/net/ssh/ruby_compat.rb +0 -46
  125. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  126. data/lib/net/ssh/verifiers/null.rb +0 -12
  127. data/lib/net/ssh/verifiers/secure.rb +0 -52
  128. data/lib/net/ssh/verifiers/strict.rb +0 -24
  129. data/setup.rb +0 -1585
  130. data/support/arcfour_check.rb +0 -20
  131. data/test/README.txt +0 -18
  132. data/test/authentication/methods/common.rb +0 -28
  133. data/test/authentication/methods/test_abstract.rb +0 -51
  134. data/test/authentication/methods/test_hostbased.rb +0 -114
  135. data/test/authentication/methods/test_keyboard_interactive.rb +0 -121
  136. data/test/authentication/methods/test_none.rb +0 -41
  137. data/test/authentication/methods/test_password.rb +0 -95
  138. data/test/authentication/methods/test_publickey.rb +0 -148
  139. data/test/authentication/test_agent.rb +0 -232
  140. data/test/authentication/test_key_manager.rb +0 -240
  141. data/test/authentication/test_session.rb +0 -107
  142. data/test/common.rb +0 -125
  143. data/test/configs/auth_off +0 -5
  144. data/test/configs/auth_on +0 -4
  145. data/test/configs/empty +0 -0
  146. data/test/configs/eqsign +0 -3
  147. data/test/configs/exact_match +0 -8
  148. data/test/configs/host_plus +0 -10
  149. data/test/configs/multihost +0 -4
  150. data/test/configs/negative_match +0 -6
  151. data/test/configs/nohost +0 -19
  152. data/test/configs/numeric_host +0 -4
  153. data/test/configs/proxy_remote_user +0 -2
  154. data/test/configs/send_env +0 -2
  155. data/test/configs/substitutes +0 -8
  156. data/test/configs/wild_cards +0 -14
  157. data/test/connection/test_channel.rb +0 -487
  158. data/test/connection/test_session.rb +0 -564
  159. data/test/integration/README.txt +0 -17
  160. data/test/integration/Vagrantfile +0 -12
  161. data/test/integration/common.rb +0 -63
  162. data/test/integration/playbook.yml +0 -56
  163. data/test/integration/test_forward.rb +0 -637
  164. data/test/integration/test_id_rsa_keys.rb +0 -96
  165. data/test/integration/test_proxy.rb +0 -93
  166. data/test/known_hosts/github +0 -1
  167. data/test/known_hosts/github_hash +0 -1
  168. data/test/manual/test_pageant.rb +0 -37
  169. data/test/start/test_connection.rb +0 -53
  170. data/test/start/test_options.rb +0 -57
  171. data/test/start/test_transport.rb +0 -28
  172. data/test/start/test_user_nil.rb +0 -27
  173. data/test/test_all.rb +0 -12
  174. data/test/test_buffer.rb +0 -433
  175. data/test/test_buffered_io.rb +0 -63
  176. data/test/test_config.rb +0 -268
  177. data/test/test_key_factory.rb +0 -191
  178. data/test/test_known_hosts.rb +0 -66
  179. data/test/transport/hmac/test_md5.rb +0 -41
  180. data/test/transport/hmac/test_md5_96.rb +0 -27
  181. data/test/transport/hmac/test_none.rb +0 -34
  182. data/test/transport/hmac/test_ripemd160.rb +0 -36
  183. data/test/transport/hmac/test_sha1.rb +0 -36
  184. data/test/transport/hmac/test_sha1_96.rb +0 -27
  185. data/test/transport/hmac/test_sha2_256.rb +0 -37
  186. data/test/transport/hmac/test_sha2_256_96.rb +0 -27
  187. data/test/transport/hmac/test_sha2_512.rb +0 -37
  188. data/test/transport/hmac/test_sha2_512_96.rb +0 -27
  189. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
  190. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -150
  191. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -96
  192. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -19
  193. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
  194. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
  195. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
  196. data/test/transport/test_algorithms.rb +0 -328
  197. data/test/transport/test_cipher_factory.rb +0 -443
  198. data/test/transport/test_hmac.rb +0 -34
  199. data/test/transport/test_identity_cipher.rb +0 -40
  200. data/test/transport/test_packet_stream.rb +0 -1762
  201. data/test/transport/test_server_version.rb +0 -74
  202. data/test/transport/test_session.rb +0 -331
  203. data/test/transport/test_state.rb +0 -181
  204. data/test/verifiers/test_secure.rb +0 -40
@@ -1,126 +1,218 @@
1
1
  require 'net/ssh/transport/openssl'
2
2
  require 'net/ssh/prompt'
3
3
 
4
- module Net; module SSH
5
-
6
- # A factory class for returning new Key classes. It is used for obtaining
7
- # OpenSSL key instances via their SSH names, and for loading both public and
8
- # private keys. It used used primarily by Net::SSH itself, internally, and
9
- # will rarely (if ever) be directly used by consumers of the library.
10
- #
11
- # klass = Net::SSH::KeyFactory.get("rsa")
12
- # assert klass.is_a?(OpenSSL::PKey::RSA)
13
- #
14
- # key = Net::SSH::KeyFactory.load_public_key("~/.ssh/id_dsa.pub")
15
- class KeyFactory
16
- # Specifies the mapping of SSH names to OpenSSL key classes.
17
- MAP = {
18
- "dh" => OpenSSL::PKey::DH,
19
- "rsa" => OpenSSL::PKey::RSA,
20
- "dsa" => OpenSSL::PKey::DSA,
21
- }
22
- if defined?(OpenSSL::PKey::EC)
23
- MAP["ecdsa"] = OpenSSL::PKey::EC
24
- end
4
+ require 'net/ssh/authentication/ed25519_loader'
25
5
 
26
- class <<self
27
- include Prompt
6
+ module Net
7
+ module SSH
8
+ # A factory class for returning new Key classes. It is used for obtaining
9
+ # OpenSSL key instances via their SSH names, and for loading both public and
10
+ # private keys. It used used primarily by Net::SSH itself, internally, and
11
+ # will rarely (if ever) be directly used by consumers of the library.
12
+ #
13
+ # klass = Net::SSH::KeyFactory.get("rsa")
14
+ # assert klass.is_a?(OpenSSL::PKey::RSA)
15
+ #
16
+ # key = Net::SSH::KeyFactory.load_public_key("~/.ssh/id_dsa.pub")
17
+ class KeyFactory
18
+ # Specifies the mapping of SSH names to OpenSSL key classes.
19
+ MAP = {
20
+ 'dh' => OpenSSL::PKey::DH,
21
+ 'rsa' => OpenSSL::PKey::RSA,
22
+ 'dsa' => OpenSSL::PKey::DSA,
23
+ 'ecdsa' => OpenSSL::PKey::EC
24
+ }
25
+ MAP["ed25519"] = Net::SSH::Authentication::ED25519::PrivKey if defined? Net::SSH::Authentication::ED25519
28
26
 
29
- # Fetch an OpenSSL key instance by its SSH name. It will be a new,
30
- # empty key of the given type.
31
- def get(name)
32
- MAP.fetch(name).new
33
- end
27
+ class << self
28
+ # Fetch an OpenSSL key instance by its SSH name. It will be a new,
29
+ # empty key of the given type.
30
+ def get(name)
31
+ MAP.fetch(name).new
32
+ end
34
33
 
35
- # Loads a private key from a file. It will correctly determine
36
- # whether the file describes an RSA or DSA key, and will load it
37
- # appropriately. The new key is returned. If the key itself is
38
- # encrypted (requiring a passphrase to use), the user will be
39
- # prompted to enter their password unless passphrase works.
40
- def load_private_key(filename, passphrase=nil, ask_passphrase=true)
41
- data = File.read(File.expand_path(filename))
42
- load_data_private_key(data, passphrase, ask_passphrase, filename)
43
- end
34
+ # Loads a private key from a file. It will correctly determine
35
+ # whether the file describes an RSA or DSA key, and will load it
36
+ # appropriately. The new key is returned. If the key itself is
37
+ # encrypted (requiring a passphrase to use), the user will be
38
+ # prompted to enter their password unless passphrase works.
39
+ def load_private_key(filename, passphrase = nil, ask_passphrase = true, prompt = Prompt.default)
40
+ data = File.read(File.expand_path(filename))
41
+ load_data_private_key(data, passphrase, ask_passphrase, filename, prompt)
42
+ end
44
43
 
45
- # Loads a private key. It will correctly determine
46
- # whether the file describes an RSA or DSA key, and will load it
47
- # appropriately. The new key is returned. If the key itself is
48
- # encrypted (requiring a passphrase to use), the user will be
49
- # prompted to enter their password unless passphrase works.
50
- def load_data_private_key(data, passphrase=nil, ask_passphrase=true, filename="")
51
- if OpenSSL::PKey.respond_to?(:read)
52
- pkey_read = true
53
- error_class = ArgumentError
54
- else
55
- pkey_read = false
56
- if data.match(/-----BEGIN DSA PRIVATE KEY-----/)
57
- key_type = OpenSSL::PKey::DSA
58
- error_class = OpenSSL::PKey::DSAError
59
- elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
60
- key_type = OpenSSL::PKey::RSA
61
- error_class = OpenSSL::PKey::RSAError
62
- elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
63
- key_type = OpenSSL::PKey::EC
64
- error_class = OpenSSL::PKey::ECError
65
- elsif data.match(/-----BEGIN (.+) PRIVATE KEY-----/)
66
- raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
67
- else
68
- raise OpenSSL::PKey::PKeyError, "not a private key (#{filename})"
44
+ # Loads a private key. It will correctly determine
45
+ # whether the file describes an RSA or DSA key, and will load it
46
+ # appropriately. The new key is returned. If the key itself is
47
+ # encrypted (requiring a passphrase to use), the user will be
48
+ # prompted to enter their password unless passphrase works.
49
+ def load_data_private_key(data, passphrase = nil, ask_passphrase = true, filename = "", prompt = Prompt.default)
50
+ key_type = classify_key(data, filename)
51
+
52
+ encrypted_key = nil
53
+ tries = 0
54
+
55
+ prompter = nil
56
+ result =
57
+ begin
58
+ key_type.read(data, passphrase || 'invalid')
59
+ rescue *key_type.error_classes => e
60
+ encrypted_key = !!key_type.encrypted_key?(data, e) if encrypted_key.nil?
61
+ if encrypted_key && ask_passphrase
62
+ tries += 1
63
+ if tries <= 3
64
+ prompter ||= prompt.start(type: 'private_key', filename: filename, sha: Digest::SHA256.digest(data))
65
+ passphrase = prompter.ask("Enter passphrase for #{filename}:", false)
66
+ retry
67
+ else
68
+ raise
69
+ end
70
+ else
71
+ raise
72
+ end
73
+ end
74
+ prompter.success if prompter
75
+ result
76
+ end
77
+
78
+ # Loads a public key from a file. It will correctly determine whether
79
+ # the file describes an RSA or DSA key, and will load it
80
+ # appropriately. The new public key is returned.
81
+ def load_public_key(filename)
82
+ data = File.read(File.expand_path(filename))
83
+ load_data_public_key(data, filename)
84
+ end
85
+
86
+ # Loads a public key. It will correctly determine whether
87
+ # the file describes an RSA or DSA key, and will load it
88
+ # appropriately. The new public key is returned.
89
+ def load_data_public_key(data, filename = "")
90
+ fields = data.split(/ /)
91
+
92
+ blob = nil
93
+ begin
94
+ blob = fields.shift
95
+ end while !blob.nil? && !/^(ssh-(rsa|dss|ed25519)|ecdsa-sha2-nistp\d+)(-cert-v01@openssh\.com)?$/.match(blob)
96
+ blob = fields.shift
97
+
98
+ raise Net::SSH::Exception, "public key at #{filename} is not valid" if blob.nil?
99
+
100
+ blob = blob.unpack("m*").first
101
+ reader = Net::SSH::Buffer.new(blob)
102
+ reader.read_key or raise OpenSSL::PKey::PKeyError, "not a public key #{filename.inspect}"
103
+ end
104
+
105
+ private
106
+
107
+ # rubocop:disable Style/Documentation, Lint/DuplicateMethods
108
+ class KeyType
109
+ def self.read(key_data, passphrase)
110
+ raise Exception, "TODO subclasses should implement read"
111
+ end
112
+
113
+ def self.error_classes
114
+ raise Exception, "TODO subclasses should implement read"
115
+ end
116
+
117
+ def self.encrypted_key?(data, error)
118
+ raise Exception, "TODO subclasses should implement is_encrypted_key"
69
119
  end
70
120
  end
71
121
 
72
- encrypted_key = data.match(/ENCRYPTED/)
73
- tries = 0
122
+ class OpenSSHPrivateKeyType < KeyType
123
+ def self.read(key_data, passphrase)
124
+ Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader.read(key_data, passphrase)
125
+ end
74
126
 
75
- begin
76
- if pkey_read
77
- return OpenSSL::PKey.read(data, passphrase || 'invalid')
78
- else
79
- return key_type.new(data, passphrase || 'invalid')
80
- end
81
- rescue error_class
82
- if encrypted_key && ask_passphrase
83
- tries += 1
84
- if tries <= 3
85
- passphrase = prompt("Enter passphrase for #{filename}:", false)
86
- retry
87
- else
88
- raise
89
- end
90
- else
91
- raise
127
+ def self.error_classes
128
+ [Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader::DecryptError]
129
+ end
130
+
131
+ def self.encrypted_key?(key_data, decode_error)
132
+ decode_error.is_a?(Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader::DecryptError) && decode_error.encrypted_key?
92
133
  end
93
134
  end
94
- end
95
135
 
96
- # Loads a public key from a file. It will correctly determine whether
97
- # the file describes an RSA or DSA key, and will load it
98
- # appropriately. The new public key is returned.
99
- def load_public_key(filename)
100
- data = File.read(File.expand_path(filename))
101
- load_data_public_key(data, filename)
102
- end
136
+ class OpenSSLKeyTypeBase < KeyType
137
+ def self.open_ssl_class
138
+ raise Exception, "TODO: subclasses should implement"
139
+ end
103
140
 
104
- # Loads a public key. It will correctly determine whether
105
- # the file describes an RSA or DSA key, and will load it
106
- # appropriately. The new public key is returned.
107
- def load_data_public_key(data, filename="")
108
- fields = data.split(/ /)
141
+ def self.read(key_data, passphrase)
142
+ open_ssl_class.new(key_data, passphrase)
143
+ end
109
144
 
110
- blob = nil
111
- begin
112
- blob = fields.shift
113
- end while !blob.nil? && !/^(ssh-(rsa|dss)|ecdsa-sha2-nistp\d+)$/.match(blob)
114
- blob = fields.shift
145
+ def self.encrypted_key?(key_data, error)
146
+ key_data.match(/ENCRYPTED/)
147
+ end
148
+ end
149
+
150
+ class OpenSSLPKeyType < OpenSSLKeyTypeBase
151
+ def self.read(key_data, passphrase)
152
+ open_ssl_class.read(key_data, passphrase)
153
+ end
154
+
155
+ def self.open_ssl_class
156
+ OpenSSL::PKey
157
+ end
115
158
 
116
- raise Net::SSH::Exception, "public key at #{filename} is not valid" if blob.nil?
159
+ def self.error_classes
160
+ [ArgumentError, OpenSSL::PKey::PKeyError]
161
+ end
162
+ end
163
+
164
+ class OpenSSLDSAKeyType < OpenSSLKeyTypeBase
165
+ def self.open_ssl_class
166
+ OpenSSL::PKey::DSA
167
+ end
168
+
169
+ def self.error_classes
170
+ [OpenSSL::PKey::DSAError]
171
+ end
172
+ end
173
+
174
+ class OpenSSLRSAKeyType < OpenSSLKeyTypeBase
175
+ def self.open_ssl_class
176
+ OpenSSL::PKey::RSA
177
+ end
117
178
 
118
- blob = blob.unpack("m*").first
119
- reader = Net::SSH::Buffer.new(blob)
120
- reader.read_key or raise OpenSSL::PKey::PKeyError, "not a public key #{filename.inspect}"
179
+ def self.error_classes
180
+ [OpenSSL::PKey::RSAError]
181
+ end
182
+ end
183
+
184
+ class OpenSSLECKeyType < OpenSSLKeyTypeBase
185
+ def self.open_ssl_class
186
+ OpenSSL::PKey::EC
187
+ end
188
+
189
+ def self.error_classes
190
+ [OpenSSL::PKey::ECError]
191
+ end
192
+ end
193
+ # rubocop:enable Style/Documentation, Lint/DuplicateMethods
194
+
195
+ # Determine whether the file describes an RSA or DSA key, and return how load it
196
+ # appropriately.
197
+ def classify_key(data, filename)
198
+ if data.match(/-----BEGIN OPENSSH PRIVATE KEY-----/)
199
+ Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("OpenSSH keys only supported if ED25519 is available")
200
+ return OpenSSHPrivateKeyType
201
+ elsif OpenSSL::PKey.respond_to?(:read)
202
+ return OpenSSLPKeyType
203
+ elsif data.match(/-----BEGIN DSA PRIVATE KEY-----/)
204
+ return OpenSSLDSAKeyType
205
+ elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
206
+ return OpenSSLRSAKeyType
207
+ elsif data.match(/-----BEGIN EC PRIVATE KEY-----/)
208
+ return OpenSSLECKeyType
209
+ elsif data.match(/-----BEGIN (.+) PRIVATE KEY-----/)
210
+ raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
211
+ else
212
+ raise OpenSSL::PKey::PKeyError, "not a private key (#{filename})"
213
+ end
214
+ end
121
215
  end
122
216
  end
123
-
124
217
  end
125
-
126
- end; end
218
+ end