net-ssh 2.7.0 → 7.3.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 (199) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/FUNDING.yml +1 -0
  5. data/.github/config/rubocop_linter_action.yml +4 -0
  6. data/.github/workflows/ci-with-docker.yml +44 -0
  7. data/.github/workflows/ci.yml +94 -0
  8. data/.github/workflows/rubocop.yml +16 -0
  9. data/.gitignore +15 -0
  10. data/.rubocop.yml +22 -0
  11. data/.rubocop_todo.yml +1081 -0
  12. data/CHANGES.txt +387 -0
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +29 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +13 -0
  17. data/Gemfile.noed25519 +12 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/ISSUE_TEMPLATE.md +30 -0
  20. data/Manifest +4 -5
  21. data/README.md +303 -0
  22. data/Rakefile +174 -40
  23. data/SECURITY.md +4 -0
  24. data/THANKS.txt +25 -0
  25. data/appveyor.yml +58 -0
  26. data/docker-compose.yml +25 -0
  27. data/lib/net/ssh/authentication/agent.rb +279 -18
  28. data/lib/net/ssh/authentication/certificate.rb +183 -0
  29. data/lib/net/ssh/authentication/constants.rb +17 -15
  30. data/lib/net/ssh/authentication/ed25519.rb +184 -0
  31. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  32. data/lib/net/ssh/authentication/key_manager.rb +125 -54
  33. data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
  34. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  35. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +19 -12
  36. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  37. data/lib/net/ssh/authentication/methods/password.rb +56 -19
  38. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  39. data/lib/net/ssh/authentication/pageant.rb +483 -246
  40. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  41. data/lib/net/ssh/authentication/session.rb +138 -120
  42. data/lib/net/ssh/buffer.rb +399 -300
  43. data/lib/net/ssh/buffered_io.rb +154 -150
  44. data/lib/net/ssh/config.rb +361 -166
  45. data/lib/net/ssh/connection/channel.rb +640 -596
  46. data/lib/net/ssh/connection/constants.rb +29 -29
  47. data/lib/net/ssh/connection/event_loop.rb +123 -0
  48. data/lib/net/ssh/connection/keepalive.rb +59 -0
  49. data/lib/net/ssh/connection/session.rb +628 -548
  50. data/lib/net/ssh/connection/term.rb +125 -123
  51. data/lib/net/ssh/errors.rb +101 -95
  52. data/lib/net/ssh/key_factory.rb +198 -100
  53. data/lib/net/ssh/known_hosts.rb +221 -98
  54. data/lib/net/ssh/loggable.rb +50 -49
  55. data/lib/net/ssh/packet.rb +83 -79
  56. data/lib/net/ssh/prompt.rb +50 -81
  57. data/lib/net/ssh/proxy/command.rb +108 -60
  58. data/lib/net/ssh/proxy/errors.rb +12 -10
  59. data/lib/net/ssh/proxy/http.rb +82 -78
  60. data/lib/net/ssh/proxy/https.rb +50 -0
  61. data/lib/net/ssh/proxy/jump.rb +54 -0
  62. data/lib/net/ssh/proxy/socks4.rb +5 -8
  63. data/lib/net/ssh/proxy/socks5.rb +18 -20
  64. data/lib/net/ssh/service/forward.rb +383 -255
  65. data/lib/net/ssh/test/channel.rb +145 -136
  66. data/lib/net/ssh/test/extensions.rb +131 -110
  67. data/lib/net/ssh/test/kex.rb +34 -32
  68. data/lib/net/ssh/test/local_packet.rb +46 -44
  69. data/lib/net/ssh/test/packet.rb +89 -70
  70. data/lib/net/ssh/test/remote_packet.rb +32 -30
  71. data/lib/net/ssh/test/script.rb +156 -142
  72. data/lib/net/ssh/test/socket.rb +49 -48
  73. data/lib/net/ssh/test.rb +82 -77
  74. data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
  75. data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
  76. data/lib/net/ssh/transport/algorithms.rb +472 -348
  77. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  78. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  79. data/lib/net/ssh/transport/cipher_factory.rb +124 -100
  80. data/lib/net/ssh/transport/constants.rb +32 -24
  81. data/lib/net/ssh/transport/ctr.rb +42 -22
  82. data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
  83. data/lib/net/ssh/transport/hmac/abstract.rb +97 -63
  84. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  87. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  88. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  89. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  90. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  91. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  92. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  93. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  94. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  95. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  96. data/lib/net/ssh/transport/hmac.rb +14 -12
  97. data/lib/net/ssh/transport/identity_cipher.rb +54 -44
  98. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  99. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  100. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  101. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  102. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  103. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  104. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
  105. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
  106. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  107. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  108. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  109. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  110. data/lib/net/ssh/transport/kex.rb +15 -12
  111. data/lib/net/ssh/transport/key_expander.rb +24 -20
  112. data/lib/net/ssh/transport/openssl.rb +161 -124
  113. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  114. data/lib/net/ssh/transport/packet_stream.rb +246 -183
  115. data/lib/net/ssh/transport/server_version.rb +57 -51
  116. data/lib/net/ssh/transport/session.rb +307 -235
  117. data/lib/net/ssh/transport/state.rb +178 -176
  118. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  119. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  120. data/lib/net/ssh/verifiers/always.rb +58 -0
  121. data/lib/net/ssh/verifiers/never.rb +19 -0
  122. data/lib/net/ssh/version.rb +57 -51
  123. data/lib/net/ssh.rb +140 -40
  124. data/net-ssh-public_cert.pem +21 -0
  125. data/net-ssh.gemspec +39 -184
  126. data/support/ssh_tunnel_bug.rb +5 -5
  127. data.tar.gz.sig +0 -0
  128. metadata +205 -99
  129. metadata.gz.sig +0 -0
  130. data/README.rdoc +0 -219
  131. data/Rudyfile +0 -96
  132. data/gem-public_cert.pem +0 -20
  133. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  134. data/lib/net/ssh/authentication/agent/socket.rb +0 -170
  135. data/lib/net/ssh/ruby_compat.rb +0 -51
  136. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  137. data/lib/net/ssh/verifiers/null.rb +0 -12
  138. data/lib/net/ssh/verifiers/secure.rb +0 -54
  139. data/lib/net/ssh/verifiers/strict.rb +0 -24
  140. data/setup.rb +0 -1585
  141. data/support/arcfour_check.rb +0 -20
  142. data/test/README.txt +0 -47
  143. data/test/authentication/methods/common.rb +0 -28
  144. data/test/authentication/methods/test_abstract.rb +0 -51
  145. data/test/authentication/methods/test_hostbased.rb +0 -114
  146. data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
  147. data/test/authentication/methods/test_none.rb +0 -41
  148. data/test/authentication/methods/test_password.rb +0 -52
  149. data/test/authentication/methods/test_publickey.rb +0 -148
  150. data/test/authentication/test_agent.rb +0 -205
  151. data/test/authentication/test_key_manager.rb +0 -218
  152. data/test/authentication/test_session.rb +0 -108
  153. data/test/common.rb +0 -108
  154. data/test/configs/eqsign +0 -3
  155. data/test/configs/exact_match +0 -8
  156. data/test/configs/host_plus +0 -10
  157. data/test/configs/multihost +0 -4
  158. data/test/configs/nohost +0 -19
  159. data/test/configs/numeric_host +0 -4
  160. data/test/configs/send_env +0 -2
  161. data/test/configs/substitutes +0 -8
  162. data/test/configs/wild_cards +0 -14
  163. data/test/connection/test_channel.rb +0 -467
  164. data/test/connection/test_session.rb +0 -526
  165. data/test/known_hosts/github +0 -1
  166. data/test/manual/test_forward.rb +0 -223
  167. data/test/start/test_options.rb +0 -36
  168. data/test/start/test_transport.rb +0 -28
  169. data/test/test_all.rb +0 -11
  170. data/test/test_buffer.rb +0 -433
  171. data/test/test_buffered_io.rb +0 -63
  172. data/test/test_config.rb +0 -151
  173. data/test/test_key_factory.rb +0 -173
  174. data/test/test_known_hosts.rb +0 -13
  175. data/test/transport/hmac/test_md5.rb +0 -41
  176. data/test/transport/hmac/test_md5_96.rb +0 -27
  177. data/test/transport/hmac/test_none.rb +0 -34
  178. data/test/transport/hmac/test_ripemd160.rb +0 -36
  179. data/test/transport/hmac/test_sha1.rb +0 -36
  180. data/test/transport/hmac/test_sha1_96.rb +0 -27
  181. data/test/transport/hmac/test_sha2_256.rb +0 -37
  182. data/test/transport/hmac/test_sha2_256_96.rb +0 -27
  183. data/test/transport/hmac/test_sha2_512.rb +0 -37
  184. data/test/transport/hmac/test_sha2_512_96.rb +0 -27
  185. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
  186. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
  187. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
  188. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
  189. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
  190. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
  191. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
  192. data/test/transport/test_algorithms.rb +0 -330
  193. data/test/transport/test_cipher_factory.rb +0 -443
  194. data/test/transport/test_hmac.rb +0 -34
  195. data/test/transport/test_identity_cipher.rb +0 -40
  196. data/test/transport/test_packet_stream.rb +0 -1755
  197. data/test/transport/test_server_version.rb +0 -78
  198. data/test/transport/test_session.rb +0 -319
  199. data/test/transport/test_state.rb +0 -181
@@ -1,350 +1,449 @@
1
- require 'net/ssh/ruby_compat'
2
1
  require 'net/ssh/transport/openssl'
3
2
 
4
- module Net; module SSH
5
-
6
- # Net::SSH::Buffer is a flexible class for building and parsing binary
7
- # data packets. It provides a stream-like interface for sequentially
8
- # reading data items from the buffer, as well as a useful helper method
9
- # for building binary packets given a signature.
10
- #
11
- # Writing to a buffer always appends to the end, regardless of where the
12
- # read cursor is. Reading, on the other hand, always begins at the first
13
- # byte of the buffer and increments the read cursor, with subsequent reads
14
- # taking up where the last left off.
15
- #
16
- # As a consumer of the Net::SSH library, you will rarely come into contact
17
- # with these buffer objects directly, but it could happen. Also, if you
18
- # are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
19
- # class can be quite handy.
20
- class Buffer
21
- # This is a convenience method for creating and populating a new buffer
22
- # from a single command. The arguments must be even in length, with the
23
- # first of each pair of arguments being a symbol naming the type of the
24
- # data that follows. If the type is :raw, the value is written directly
25
- # to the hash.
26
- #
27
- # b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
28
- # #-> "\1\0\0\0\5hello\1\2\3\4"
29
- #
30
- # The supported data types are:
3
+ require 'net/ssh/authentication/certificate'
4
+ require 'net/ssh/authentication/ed25519_loader'
5
+
6
+ module Net
7
+ module SSH
8
+ # Net::SSH::Buffer is a flexible class for building and parsing binary
9
+ # data packets. It provides a stream-like interface for sequentially
10
+ # reading data items from the buffer, as well as a useful helper method
11
+ # for building binary packets given a signature.
31
12
  #
32
- # * :raw => write the next value verbatim (#write)
33
- # * :int64 => write an 8-byte integer (#write_int64)
34
- # * :long => write a 4-byte integer (#write_long)
35
- # * :byte => write a single byte (#write_byte)
36
- # * :string => write a 4-byte length followed by character data (#write_string)
37
- # * :bool => write a single byte, interpreted as a boolean (#write_bool)
38
- # * :bignum => write an SSH-encoded bignum (#write_bignum)
39
- # * :key => write an SSH-encoded key value (#write_key)
13
+ # Writing to a buffer always appends to the end, regardless of where the
14
+ # read cursor is. Reading, on the other hand, always begins at the first
15
+ # byte of the buffer and increments the read cursor, with subsequent reads
16
+ # taking up where the last left off.
40
17
  #
41
- # Any of these, except for :raw, accepts an Array argument, to make it
42
- # easier to write multiple values of the same type in a briefer manner.
43
- def self.from(*args)
44
- raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
45
-
46
- buffer = new
47
- 0.step(args.length-1, 2) do |index|
48
- type = args[index]
49
- value = args[index+1]
50
- if type == :raw
51
- buffer.append(value.to_s)
52
- elsif Array === value
53
- buffer.send("write_#{type}", *value)
54
- else
55
- buffer.send("write_#{type}", value)
18
+ # As a consumer of the Net::SSH library, you will rarely come into contact
19
+ # with these buffer objects directly, but it could happen. Also, if you
20
+ # are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
21
+ # class can be quite handy.
22
+ class Buffer
23
+ # This is a convenience method for creating and populating a new buffer
24
+ # from a single command. The arguments must be even in length, with the
25
+ # first of each pair of arguments being a symbol naming the type of the
26
+ # data that follows. If the type is :raw, the value is written directly
27
+ # to the hash.
28
+ #
29
+ # b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
30
+ # #-> "\1\0\0\0\5hello\1\2\3\4"
31
+ #
32
+ # The supported data types are:
33
+ #
34
+ # * :raw => write the next value verbatim (#write)
35
+ # * :int64 => write an 8-byte integer (#write_int64)
36
+ # * :long => write a 4-byte integer (#write_long)
37
+ # * :byte => write a single byte (#write_byte)
38
+ # * :string => write a 4-byte length followed by character data (#write_string)
39
+ # * :mstring => same as string, but caller cannot resuse the string, avoids potential duplication (#write_moved)
40
+ # * :bool => write a single byte, interpreted as a boolean (#write_bool)
41
+ # * :bignum => write an SSH-encoded bignum (#write_bignum)
42
+ # * :key => write an SSH-encoded key value (#write_key)
43
+ #
44
+ # Any of these, except for :raw, accepts an Array argument, to make it
45
+ # easier to write multiple values of the same type in a briefer manner.
46
+ def self.from(*args)
47
+ raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
48
+
49
+ buffer = new
50
+ 0.step(args.length - 1, 2) do |index|
51
+ type = args[index]
52
+ value = args[index + 1]
53
+ if type == :raw
54
+ buffer.append(value.to_s)
55
+ elsif Array === value
56
+ buffer.send("write_#{type}", *value)
57
+ else
58
+ buffer.send("write_#{type}", value)
59
+ end
56
60
  end
61
+
62
+ buffer
57
63
  end
58
64
 
59
- buffer
60
- end
65
+ # exposes the raw content of the buffer
66
+ attr_reader :content
61
67
 
62
- # exposes the raw content of the buffer
63
- attr_reader :content
68
+ # the current position of the pointer in the buffer
69
+ attr_accessor :position
64
70
 
65
- # the current position of the pointer in the buffer
66
- attr_accessor :position
71
+ # Creates a new buffer, initialized to the given content. The position
72
+ # is initialized to the beginning of the buffer.
73
+ def initialize(content = String.new)
74
+ @content = content.to_s
75
+ @position = 0
76
+ end
67
77
 
68
- # Creates a new buffer, initialized to the given content. The position
69
- # is initialized to the beginning of the buffer.
70
- def initialize(content="")
71
- @content = content.to_s
72
- @position = 0
73
- end
78
+ # Returns the length of the buffer's content.
79
+ def length
80
+ @content.length
81
+ end
74
82
 
75
- # Returns the length of the buffer's content.
76
- def length
77
- @content.length
78
- end
83
+ # Returns the number of bytes available to be read (e.g., how many bytes
84
+ # remain between the current position and the end of the buffer).
85
+ def available
86
+ length - position
87
+ end
79
88
 
80
- # Returns the number of bytes available to be read (e.g., how many bytes
81
- # remain between the current position and the end of the buffer).
82
- def available
83
- length - position
84
- end
89
+ # Returns a copy of the buffer's content.
90
+ def to_s
91
+ (@content || "").dup
92
+ end
85
93
 
86
- # Returns a copy of the buffer's content.
87
- def to_s
88
- (@content || "").dup
89
- end
94
+ # Compares the contents of the two buffers, returning +true+ only if they
95
+ # are identical in size and content.
96
+ def ==(buffer)
97
+ to_s == buffer.to_s
98
+ end
90
99
 
91
- # Compares the contents of the two buffers, returning +true+ only if they
92
- # are identical in size and content.
93
- def ==(buffer)
94
- to_s == buffer.to_s
95
- end
100
+ # Returns +true+ if the buffer contains no data (e.g., it is of zero length).
101
+ def empty?
102
+ @content.empty?
103
+ end
96
104
 
97
- # Returns +true+ if the buffer contains no data (e.g., it is of zero length).
98
- def empty?
99
- @content.empty?
100
- end
105
+ # Resets the pointer to the start of the buffer. Subsequent reads will
106
+ # begin at position 0.
107
+ def reset!
108
+ @position = 0
109
+ end
101
110
 
102
- # Resets the pointer to the start of the buffer. Subsequent reads will
103
- # begin at position 0.
104
- def reset!
105
- @position = 0
106
- end
111
+ # Returns true if the pointer is at the end of the buffer. Subsequent
112
+ # reads will return nil, in this case.
113
+ def eof?
114
+ @position >= length
115
+ end
107
116
 
108
- # Returns true if the pointer is at the end of the buffer. Subsequent
109
- # reads will return nil, in this case.
110
- def eof?
111
- @position >= length
112
- end
117
+ # Resets the buffer, making it empty. Also, resets the read position to
118
+ # 0.
119
+ def clear!
120
+ @content = String.new
121
+ @position = 0
122
+ end
113
123
 
114
- # Resets the buffer, making it empty. Also, resets the read position to
115
- # 0.
116
- def clear!
117
- @content = ""
118
- @position = 0
119
- end
124
+ # Consumes n bytes from the buffer, where n is the current position
125
+ # unless otherwise specified. This is useful for removing data from the
126
+ # buffer that has previously been read, when you are expecting more data
127
+ # to be appended. It helps to keep the size of buffers down when they
128
+ # would otherwise tend to grow without bound.
129
+ #
130
+ # Returns the buffer object itself.
131
+ def consume!(n = position)
132
+ if n >= length
133
+ # optimize for a fairly common case
134
+ clear!
135
+ elsif n > 0
136
+ @content = @content[n..-1] || String.new
137
+ @position -= n
138
+ @position = 0 if @position < 0
139
+ end
140
+ self
141
+ end
120
142
 
121
- # Consumes n bytes from the buffer, where n is the current position
122
- # unless otherwise specified. This is useful for removing data from the
123
- # buffer that has previously been read, when you are expecting more data
124
- # to be appended. It helps to keep the size of buffers down when they
125
- # would otherwise tend to grow without bound.
126
- #
127
- # Returns the buffer object itself.
128
- def consume!(n=position)
129
- if n >= length
130
- # optimize for a fairly common case
131
- clear!
132
- elsif n > 0
133
- @content = @content[n..-1] || ""
134
- @position -= n
135
- @position = 0 if @position < 0
136
- end
137
- self
138
- end
143
+ # Appends the given text to the end of the buffer. Does not alter the
144
+ # read position. Returns the buffer object itself.
145
+ def append(text)
146
+ @content << text
147
+ self
148
+ end
139
149
 
140
- # Appends the given text to the end of the buffer. Does not alter the
141
- # read position. Returns the buffer object itself.
142
- def append(text)
143
- @content << text
144
- self
145
- end
150
+ # Returns all text from the current pointer to the end of the buffer as
151
+ # a new Net::SSH::Buffer object.
152
+ def remainder_as_buffer
153
+ Buffer.new(@content[@position..-1])
154
+ end
146
155
 
147
- # Returns all text from the current pointer to the end of the buffer as
148
- # a new Net::SSH::Buffer object.
149
- def remainder_as_buffer
150
- Buffer.new(@content[@position..-1])
151
- end
156
+ # Reads all data up to and including the given pattern, which may be a
157
+ # String, Fixnum, or Regexp and is interpreted exactly as String#index
158
+ # does. Returns nil if nothing matches. Increments the position to point
159
+ # immediately after the pattern, if it does match. Returns all data up to
160
+ # and including the text that matched the pattern.
161
+ def read_to(pattern)
162
+ index = @content.index(pattern, @position) or return nil
163
+ length = case pattern
164
+ when String then pattern.length
165
+ when Integer then 1
166
+ when Regexp then $&.length
167
+ end
168
+ index && read(index + length)
169
+ end
152
170
 
153
- # Reads all data up to and including the given pattern, which may be a
154
- # String, Fixnum, or Regexp and is interpreted exactly as String#index
155
- # does. Returns nil if nothing matches. Increments the position to point
156
- # immediately after the pattern, if it does match. Returns all data up to
157
- # and including the text that matched the pattern.
158
- def read_to(pattern)
159
- index = @content.index(pattern, @position) or return nil
160
- length = case pattern
161
- when String then pattern.length
162
- when Fixnum then 1
163
- when Regexp then $&.length
164
- end
165
- index && read(index+length)
166
- end
171
+ # Reads and returns the next +count+ bytes from the buffer, starting from
172
+ # the read position. If +count+ is +nil+, this will return all remaining
173
+ # text in the buffer. This method will increment the pointer.
174
+ def read(count = nil)
175
+ count ||= length
176
+ count = length - @position if @position + count > length
177
+ @position += count
178
+ @content[@position - count, count]
179
+ end
167
180
 
168
- # Reads and returns the next +count+ bytes from the buffer, starting from
169
- # the read position. If +count+ is +nil+, this will return all remaining
170
- # text in the buffer. This method will increment the pointer.
171
- def read(count=nil)
172
- count ||= length
173
- count = length - @position if @position + count > length
174
- @position += count
175
- @content[@position-count, count]
176
- end
181
+ # Reads (as #read) and returns the given number of bytes from the buffer,
182
+ # and then consumes (as #consume!) all data up to the new read position.
183
+ def read!(count = nil)
184
+ data = read(count)
185
+ consume!
186
+ data
187
+ end
177
188
 
178
- # Reads (as #read) and returns the given number of bytes from the buffer,
179
- # and then consumes (as #consume!) all data up to the new read position.
180
- def read!(count=nil)
181
- data = read(count)
182
- consume!
183
- data
184
- end
185
-
186
- # Return the next 8 bytes as a 64-bit integer (in network byte order).
187
- # Returns nil if there are less than 8 bytes remaining to be read in the
188
- # buffer.
189
- def read_int64
190
- hi = read_long or return nil
191
- lo = read_long or return nil
192
- return (hi << 32) + lo
193
- end
189
+ # Calls block(self) until the buffer is empty, and returns all results.
190
+ def read_all(&block)
191
+ Enumerator.new { |e| e << yield(self) until eof? }.to_a
192
+ end
194
193
 
195
- # Return the next four bytes as a long integer (in network byte order).
196
- # Returns nil if there are less than 4 bytes remaining to be read in the
197
- # buffer.
198
- def read_long
199
- b = read(4) or return nil
200
- b.unpack("N").first
201
- end
194
+ # Return the next 8 bytes as a 64-bit integer (in network byte order).
195
+ # Returns nil if there are less than 8 bytes remaining to be read in the
196
+ # buffer.
197
+ def read_int64
198
+ hi = read_long or return nil
199
+ lo = read_long or return nil
200
+ return (hi << 32) + lo
201
+ end
202
202
 
203
- # Read and return the next byte in the buffer. Returns nil if called at
204
- # the end of the buffer.
205
- def read_byte
206
- b = read(1) or return nil
207
- b.getbyte(0)
208
- end
203
+ # Return the next four bytes as a long integer (in network byte order).
204
+ # Returns nil if there are less than 4 bytes remaining to be read in the
205
+ # buffer.
206
+ def read_long
207
+ b = read(4) or return nil
208
+ b.unpack("N").first
209
+ end
209
210
 
210
- # Read and return an SSH2-encoded string. The string starts with a long
211
- # integer that describes the number of bytes remaining in the string.
212
- # Returns nil if there are not enough bytes to satisfy the request.
213
- def read_string
214
- length = read_long or return nil
215
- read(length)
216
- end
211
+ # Read and return the next byte in the buffer. Returns nil if called at
212
+ # the end of the buffer.
213
+ def read_byte
214
+ b = read(1) or return nil
215
+ b.getbyte(0)
216
+ end
217
217
 
218
- # Read a single byte and convert it into a boolean, using 'C' rules
219
- # (i.e., zero is false, non-zero is true).
220
- def read_bool
221
- b = read_byte or return nil
222
- b != 0
223
- end
218
+ # Read and return an SSH2-encoded string. The string starts with a long
219
+ # integer that describes the number of bytes remaining in the string.
220
+ # Returns nil if there are not enough bytes to satisfy the request.
221
+ def read_string
222
+ length = read_long or return nil
223
+ read(length)
224
+ end
224
225
 
225
- # Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
226
- # essentially just a string, which is reinterpreted to be a bignum in
227
- # binary format.
228
- def read_bignum
229
- data = read_string
230
- return unless data
231
- OpenSSL::BN.new(data, 2)
232
- end
226
+ # Read a single byte and convert it into a boolean, using 'C' rules
227
+ # (i.e., zero is false, non-zero is true).
228
+ def read_bool
229
+ b = read_byte or return nil
230
+ b != 0
231
+ end
233
232
 
234
- # Read a key from the buffer. The key will start with a string
235
- # describing its type. The remainder of the key is defined by the
236
- # type that was read.
237
- def read_key
238
- type = read_string
239
- return (type ? read_keyblob(type) : nil)
240
- end
233
+ # Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
234
+ # essentially just a string, which is reinterpreted to be a bignum in
235
+ # binary format.
236
+ def read_bignum
237
+ data = read_string
238
+ return unless data
241
239
 
242
- # Read a keyblob of the given type from the buffer, and return it as
243
- # a key. Only RSA, DSA, and ECDSA keys are supported.
244
- def read_keyblob(type)
245
- case type
246
- when "ssh-dss"
247
- key = OpenSSL::PKey::DSA.new
248
- key.p = read_bignum
249
- key.q = read_bignum
250
- key.g = read_bignum
251
- key.pub_key = read_bignum
252
-
253
- when "ssh-rsa"
254
- key = OpenSSL::PKey::RSA.new
255
- key.e = read_bignum
256
- key.n = read_bignum
240
+ OpenSSL::BN.new(data, 2)
241
+ end
257
242
 
258
- when /^ecdsa\-sha2\-(\w*)$/
259
- unless defined?(OpenSSL::PKey::EC)
260
- raise NotImplementedError, "unsupported key type `#{type}'"
261
- else
262
- begin
263
- key = OpenSSL::PKey::EC.read_keyblob($1, self)
264
- rescue OpenSSL::PKey::ECError
265
- raise NotImplementedError, "unsupported key type `#{type}'"
266
- end
243
+ # Read a key from the buffer. The key will start with a string
244
+ # describing its type. The remainder of the key is defined by the
245
+ # type that was read.
246
+ def read_key
247
+ type = read_string
248
+ return (type ? read_keyblob(type) : nil)
249
+ end
250
+
251
+ def read_private_keyblob(type)
252
+ case type
253
+ when /^ssh-rsa$/
254
+ n = read_bignum
255
+ e = read_bignum
256
+ d = read_bignum
257
+ iqmp = read_bignum
258
+ p = read_bignum
259
+ q = read_bignum
260
+ _unkown1 = read_bignum
261
+ _unkown2 = read_bignum
262
+ dmp1 = d % (p - 1)
263
+ dmq1 = d % (q - 1)
264
+ # Public key
265
+ data_sequence = OpenSSL::ASN1::Sequence([
266
+ OpenSSL::ASN1::Integer(n),
267
+ OpenSSL::ASN1::Integer(e)
268
+ ])
269
+
270
+ if d && p && q && dmp1 && dmq1 && iqmp
271
+ data_sequence = OpenSSL::ASN1::Sequence([
272
+ OpenSSL::ASN1::Integer(0),
273
+ OpenSSL::ASN1::Integer(n),
274
+ OpenSSL::ASN1::Integer(e),
275
+ OpenSSL::ASN1::Integer(d),
276
+ OpenSSL::ASN1::Integer(p),
277
+ OpenSSL::ASN1::Integer(q),
278
+ OpenSSL::ASN1::Integer(dmp1),
279
+ OpenSSL::ASN1::Integer(dmq1),
280
+ OpenSSL::ASN1::Integer(iqmp)
281
+ ])
267
282
  end
283
+
284
+ asn1 = OpenSSL::ASN1::Sequence(data_sequence)
285
+ OpenSSL::PKey::RSA.new(asn1.to_der)
286
+ when /^ecdsa\-sha2\-(\w*)$/
287
+ OpenSSL::PKey::EC.read_keyblob($1, self)
288
+ else
289
+ raise Exception, "Cannot decode private key of type #{type}"
290
+ end
291
+ end
292
+
293
+ # Read a keyblob of the given type from the buffer, and return it as
294
+ # a key. Only RSA, DSA, and ECDSA keys are supported.
295
+ def read_keyblob(type)
296
+ case type
297
+ when /^(.*)-cert-v01@openssh\.com$/
298
+ key = Net::SSH::Authentication::Certificate.read_certblob(self, $1)
299
+ when /^ssh-dss$/
300
+ p = read_bignum
301
+ q = read_bignum
302
+ g = read_bignum
303
+ pub_key = read_bignum
304
+
305
+ asn1 = OpenSSL::ASN1::Sequence.new(
306
+ [
307
+ OpenSSL::ASN1::Sequence.new(
308
+ [
309
+ OpenSSL::ASN1::ObjectId.new('DSA'),
310
+ OpenSSL::ASN1::Sequence.new(
311
+ [
312
+ OpenSSL::ASN1::Integer.new(p),
313
+ OpenSSL::ASN1::Integer.new(q),
314
+ OpenSSL::ASN1::Integer.new(g)
315
+ ]
316
+ )
317
+ ]
318
+ ),
319
+ OpenSSL::ASN1::BitString.new(OpenSSL::ASN1::Integer.new(pub_key).to_der)
320
+ ]
321
+ )
322
+
323
+ key = OpenSSL::PKey::DSA.new(asn1.to_der)
324
+ when /^ssh-rsa$/
325
+ e = read_bignum
326
+ n = read_bignum
327
+
328
+ asn1 = OpenSSL::ASN1::Sequence(
329
+ [
330
+ OpenSSL::ASN1::Integer(n),
331
+ OpenSSL::ASN1::Integer(e)
332
+ ]
333
+ )
334
+
335
+ key = OpenSSL::PKey::RSA.new(asn1.to_der)
336
+ when /^ssh-ed25519$/
337
+ Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("unsupported key type `#{type}'")
338
+ key = Net::SSH::Authentication::ED25519::PubKey.read_keyblob(self)
339
+ when /^ecdsa\-sha2\-(\w*)$/
340
+ key = OpenSSL::PKey::EC.read_keyblob($1, self)
268
341
  else
269
342
  raise NotImplementedError, "unsupported key type `#{type}'"
343
+ end
344
+
345
+ return key
270
346
  end
271
347
 
272
- return key
273
- end
348
+ # Reads the next string from the buffer, and returns a new Buffer
349
+ # object that wraps it.
350
+ def read_buffer
351
+ Buffer.new(read_string)
352
+ end
274
353
 
275
- # Reads the next string from the buffer, and returns a new Buffer
276
- # object that wraps it.
277
- def read_buffer
278
- Buffer.new(read_string)
279
- end
354
+ # Writes the given data literally into the string. Does not alter the
355
+ # read position. Returns the buffer object.
356
+ def write(*data)
357
+ data.each { |datum| @content << datum.dup.force_encoding('BINARY') }
358
+ self
359
+ end
280
360
 
281
- # Writes the given data literally into the string. Does not alter the
282
- # read position. Returns the buffer object.
283
- def write(*data)
284
- data.each { |datum| @content << datum }
285
- self
286
- end
361
+ # Optimized version of write where the caller gives up ownership of string
362
+ # to the method. This way we can mutate the string.
363
+ def write_moved(string)
364
+ @content <<
365
+ if string.frozen?
366
+ string.dup.force_encoding('BINARY')
367
+ else
368
+ string.force_encoding('BINARY')
369
+ end
370
+ self
371
+ end
287
372
 
288
- # Writes each argument to the buffer as a network-byte-order-encoded
289
- # 64-bit integer (8 bytes). Does not alter the read position. Returns the
290
- # buffer object.
291
- def write_int64(*n)
292
- n.each do |i|
293
- hi = (i >> 32) & 0xFFFFFFFF
294
- lo = i & 0xFFFFFFFF
295
- @content << [hi, lo].pack("N2")
373
+ # Writes each argument to the buffer as a network-byte-order-encoded
374
+ # 64-bit integer (8 bytes). Does not alter the read position. Returns the
375
+ # buffer object.
376
+ def write_int64(*n)
377
+ n.each do |i|
378
+ hi = (i >> 32) & 0xFFFFFFFF
379
+ lo = i & 0xFFFFFFFF
380
+ @content << [hi, lo].pack("N2")
381
+ end
382
+ self
296
383
  end
297
- self
298
- end
299
384
 
300
- # Writes each argument to the buffer as a network-byte-order-encoded
301
- # long (4-byte) integer. Does not alter the read position. Returns the
302
- # buffer object.
303
- def write_long(*n)
304
- @content << n.pack("N*")
305
- self
306
- end
385
+ # Writes each argument to the buffer as a network-byte-order-encoded
386
+ # long (4-byte) integer. Does not alter the read position. Returns the
387
+ # buffer object.
388
+ def write_long(*n)
389
+ @content << n.pack("N*")
390
+ self
391
+ end
307
392
 
308
- # Writes each argument to the buffer as a byte. Does not alter the read
309
- # position. Returns the buffer object.
310
- def write_byte(*n)
311
- n.each { |b| @content << b.chr }
312
- self
313
- end
393
+ # Writes each argument to the buffer as a byte. Does not alter the read
394
+ # position. Returns the buffer object.
395
+ def write_byte(*n)
396
+ n.each { |b| @content << b.chr }
397
+ self
398
+ end
314
399
 
315
- # Writes each argument to the buffer as an SSH2-encoded string. Each
316
- # string is prefixed by its length, encoded as a 4-byte long integer.
317
- # Does not alter the read position. Returns the buffer object.
318
- def write_string(*text)
319
- text.each do |string|
320
- s = string.to_s
321
- write_long(s.bytesize)
322
- write(s)
400
+ # Writes each argument to the buffer as an SSH2-encoded string. Each
401
+ # string is prefixed by its length, encoded as a 4-byte long integer.
402
+ # Does not alter the read position. Returns the buffer object.
403
+ def write_string(*text)
404
+ text.each do |string|
405
+ s = string.to_s
406
+ write_long(s.bytesize)
407
+ write(s)
408
+ end
409
+ self
323
410
  end
324
- self
325
- end
326
411
 
327
- # Writes each argument to the buffer as a (C-style) boolean, with 1
328
- # meaning true, and 0 meaning false. Does not alter the read position.
329
- # Returns the buffer object.
330
- def write_bool(*b)
331
- b.each { |v| @content << (v ? "\1" : "\0") }
332
- self
333
- end
412
+ # Writes each argument to the buffer as an SSH2-encoded string. Each
413
+ # string is prefixed by its length, encoded as a 4-byte long integer.
414
+ # Does not alter the read position. Returns the buffer object.
415
+ # Might alter arguments see write_moved
416
+ def write_mstring(*text)
417
+ text.each do |string|
418
+ s = string.to_s
419
+ write_long(s.bytesize)
420
+ write_moved(s)
421
+ end
422
+ self
423
+ end
334
424
 
335
- # Writes each argument to the buffer as a bignum (SSH2-style). No
336
- # checking is done to ensure that the arguments are, in fact, bignums.
337
- # Does not alter the read position. Returns the buffer object.
338
- def write_bignum(*n)
339
- @content << n.map { |b| b.to_ssh }.join
340
- self
341
- end
425
+ # Writes each argument to the buffer as a (C-style) boolean, with 1
426
+ # meaning true, and 0 meaning false. Does not alter the read position.
427
+ # Returns the buffer object.
428
+ def write_bool(*b)
429
+ b.each { |v| @content << (v ? "\1" : "\0") }
430
+ self
431
+ end
342
432
 
343
- # Writes the given arguments to the buffer as SSH2-encoded keys. Does not
344
- # alter the read position. Returns the buffer object.
345
- def write_key(*key)
346
- key.each { |k| append(k.to_blob) }
347
- self
433
+ # Writes each argument to the buffer as a bignum (SSH2-style). No
434
+ # checking is done to ensure that the arguments are, in fact, bignums.
435
+ # Does not alter the read position. Returns the buffer object.
436
+ def write_bignum(*n)
437
+ @content << n.map { |b| b.to_ssh }.join
438
+ self
439
+ end
440
+
441
+ # Writes the given arguments to the buffer as SSH2-encoded keys. Does not
442
+ # alter the read position. Returns the buffer object.
443
+ def write_key(*key)
444
+ key.each { |k| append(k.to_blob) }
445
+ self
446
+ end
348
447
  end
349
448
  end
350
- end; end;
449
+ end;