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,396 +1,449 @@
1
- require 'net/ssh/ruby_compat'
2
1
  require 'net/ssh/transport/openssl'
3
2
 
4
3
  require 'net/ssh/authentication/certificate'
5
4
  require 'net/ssh/authentication/ed25519_loader'
6
5
 
7
- module Net; module SSH
8
-
9
- # Net::SSH::Buffer is a flexible class for building and parsing binary
10
- # data packets. It provides a stream-like interface for sequentially
11
- # reading data items from the buffer, as well as a useful helper method
12
- # for building binary packets given a signature.
13
- #
14
- # Writing to a buffer always appends to the end, regardless of where the
15
- # read cursor is. Reading, on the other hand, always begins at the first
16
- # byte of the buffer and increments the read cursor, with subsequent reads
17
- # taking up where the last left off.
18
- #
19
- # As a consumer of the Net::SSH library, you will rarely come into contact
20
- # with these buffer objects directly, but it could happen. Also, if you
21
- # are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
22
- # class can be quite handy.
23
- class Buffer
24
- # This is a convenience method for creating and populating a new buffer
25
- # from a single command. The arguments must be even in length, with the
26
- # first of each pair of arguments being a symbol naming the type of the
27
- # data that follows. If the type is :raw, the value is written directly
28
- # to the hash.
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.
29
12
  #
30
- # b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
31
- # #-> "\1\0\0\0\5hello\1\2\3\4"
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.
32
17
  #
33
- # The supported data types are:
34
- #
35
- # * :raw => write the next value verbatim (#write)
36
- # * :int64 => write an 8-byte integer (#write_int64)
37
- # * :long => write a 4-byte integer (#write_long)
38
- # * :byte => write a single byte (#write_byte)
39
- # * :string => write a 4-byte length followed by character data (#write_string)
40
- # * :mstring => same as string, but caller cannot resuse the string, avoids potential duplication (#write_moved)
41
- # * :bool => write a single byte, interpreted as a boolean (#write_bool)
42
- # * :bignum => write an SSH-encoded bignum (#write_bignum)
43
- # * :key => write an SSH-encoded key value (#write_key)
44
- #
45
- # Any of these, except for :raw, accepts an Array argument, to make it
46
- # easier to write multiple values of the same type in a briefer manner.
47
- def self.from(*args)
48
- raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
49
-
50
- buffer = new
51
- 0.step(args.length-1, 2) do |index|
52
- type = args[index]
53
- value = args[index+1]
54
- if type == :raw
55
- buffer.append(value.to_s)
56
- elsif Array === value
57
- buffer.send("write_#{type}", *value)
58
- else
59
- 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
60
60
  end
61
+
62
+ buffer
61
63
  end
62
64
 
63
- buffer
64
- end
65
+ # exposes the raw content of the buffer
66
+ attr_reader :content
65
67
 
66
- # exposes the raw content of the buffer
67
- attr_reader :content
68
+ # the current position of the pointer in the buffer
69
+ attr_accessor :position
68
70
 
69
- # the current position of the pointer in the buffer
70
- 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
71
77
 
72
- # Creates a new buffer, initialized to the given content. The position
73
- # is initialized to the beginning of the buffer.
74
- def initialize(content="")
75
- @content = content.to_s
76
- @position = 0
77
- end
78
+ # Returns the length of the buffer's content.
79
+ def length
80
+ @content.length
81
+ end
78
82
 
79
- # Returns the length of the buffer's content.
80
- def length
81
- @content.length
82
- 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
83
88
 
84
- # Returns the number of bytes available to be read (e.g., how many bytes
85
- # remain between the current position and the end of the buffer).
86
- def available
87
- length - position
88
- end
89
+ # Returns a copy of the buffer's content.
90
+ def to_s
91
+ (@content || "").dup
92
+ end
89
93
 
90
- # Returns a copy of the buffer's content.
91
- def to_s
92
- (@content || "").dup
93
- 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
94
99
 
95
- # Compares the contents of the two buffers, returning +true+ only if they
96
- # are identical in size and content.
97
- def ==(buffer)
98
- to_s == buffer.to_s
99
- 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
100
104
 
101
- # Returns +true+ if the buffer contains no data (e.g., it is of zero length).
102
- def empty?
103
- @content.empty?
104
- 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
105
110
 
106
- # Resets the pointer to the start of the buffer. Subsequent reads will
107
- # begin at position 0.
108
- def reset!
109
- @position = 0
110
- 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
111
116
 
112
- # Returns true if the pointer is at the end of the buffer. Subsequent
113
- # reads will return nil, in this case.
114
- def eof?
115
- @position >= length
116
- 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
117
123
 
118
- # Resets the buffer, making it empty. Also, resets the read position to
119
- # 0.
120
- def clear!
121
- @content = ""
122
- @position = 0
123
- 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
124
142
 
125
- # Consumes n bytes from the buffer, where n is the current position
126
- # unless otherwise specified. This is useful for removing data from the
127
- # buffer that has previously been read, when you are expecting more data
128
- # to be appended. It helps to keep the size of buffers down when they
129
- # would otherwise tend to grow without bound.
130
- #
131
- # Returns the buffer object itself.
132
- def consume!(n=position)
133
- if n >= length
134
- # optimize for a fairly common case
135
- clear!
136
- elsif n > 0
137
- @content = @content[n..-1] || ""
138
- @position -= n
139
- @position = 0 if @position < 0
140
- end
141
- self
142
- 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
143
149
 
144
- # Appends the given text to the end of the buffer. Does not alter the
145
- # read position. Returns the buffer object itself.
146
- def append(text)
147
- @content << text
148
- self
149
- 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
150
155
 
151
- # Returns all text from the current pointer to the end of the buffer as
152
- # a new Net::SSH::Buffer object.
153
- def remainder_as_buffer
154
- Buffer.new(@content[@position..-1])
155
- 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
156
170
 
157
- # Reads all data up to and including the given pattern, which may be a
158
- # String, Fixnum, or Regexp and is interpreted exactly as String#index
159
- # does. Returns nil if nothing matches. Increments the position to point
160
- # immediately after the pattern, if it does match. Returns all data up to
161
- # and including the text that matched the pattern.
162
- def read_to(pattern)
163
- index = @content.index(pattern, @position) or return nil
164
- length = case pattern
165
- when String then pattern.length
166
- when Integer then 1
167
- when Regexp then $&.length
168
- end
169
- index && read(index+length)
170
- 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
171
180
 
172
- # Reads and returns the next +count+ bytes from the buffer, starting from
173
- # the read position. If +count+ is +nil+, this will return all remaining
174
- # text in the buffer. This method will increment the pointer.
175
- def read(count=nil)
176
- count ||= length
177
- count = length - @position if @position + count > length
178
- @position += count
179
- @content[@position-count, count]
180
- 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
181
188
 
182
- # Reads (as #read) and returns the given number of bytes from the buffer,
183
- # and then consumes (as #consume!) all data up to the new read position.
184
- def read!(count=nil)
185
- data = read(count)
186
- consume!
187
- data
188
- 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
189
193
 
190
- # Calls block(self) until the buffer is empty, and returns all results.
191
- def read_all(&block)
192
- Enumerator.new { |e| e << yield(self) until eof? }.to_a
193
- 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
194
202
 
195
- # Return the next 8 bytes as a 64-bit integer (in network byte order).
196
- # Returns nil if there are less than 8 bytes remaining to be read in the
197
- # buffer.
198
- def read_int64
199
- hi = read_long or return nil
200
- lo = read_long or return nil
201
- return (hi << 32) + lo
202
- 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
203
210
 
204
- # Return the next four bytes as a long integer (in network byte order).
205
- # Returns nil if there are less than 4 bytes remaining to be read in the
206
- # buffer.
207
- def read_long
208
- b = read(4) or return nil
209
- b.unpack("N").first
210
- 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
211
217
 
212
- # Read and return the next byte in the buffer. Returns nil if called at
213
- # the end of the buffer.
214
- def read_byte
215
- b = read(1) or return nil
216
- b.getbyte(0)
217
- 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
218
225
 
219
- # Read and return an SSH2-encoded string. The string starts with a long
220
- # integer that describes the number of bytes remaining in the string.
221
- # Returns nil if there are not enough bytes to satisfy the request.
222
- def read_string
223
- length = read_long or return nil
224
- read(length)
225
- 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
226
232
 
227
- # Read a single byte and convert it into a boolean, using 'C' rules
228
- # (i.e., zero is false, non-zero is true).
229
- def read_bool
230
- b = read_byte or return nil
231
- b != 0
232
- 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
233
239
 
234
- # Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
235
- # essentially just a string, which is reinterpreted to be a bignum in
236
- # binary format.
237
- def read_bignum
238
- data = read_string
239
- return unless data
240
- OpenSSL::BN.new(data, 2)
241
- end
240
+ OpenSSL::BN.new(data, 2)
241
+ end
242
242
 
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
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
250
 
251
- # Read a keyblob of the given type from the buffer, and return it as
252
- # a key. Only RSA, DSA, and ECDSA keys are supported.
253
- def read_keyblob(type)
254
- case type
255
- when /^(.*)-cert-v01@openssh\.com$/
256
- key = Net::SSH::Authentication::Certificate.read_certblob(self, $1)
257
- when /^ssh-dss$/
258
- key = OpenSSL::PKey::DSA.new
259
- if key.respond_to?(:set_pqg)
260
- key.set_pqg(read_bignum, read_bignum, read_bignum)
251
+ def read_private_keyblob(type)
252
+ case type
253
+ when /^ssh-rsa$/
254
+ key = OpenSSL::PKey::RSA.new
255
+ n = read_bignum
256
+ e = read_bignum
257
+ d = read_bignum
258
+ iqmp = read_bignum
259
+ p = read_bignum
260
+ q = read_bignum
261
+ _unkown1 = read_bignum
262
+ _unkown2 = read_bignum
263
+ dmp1 = d % (p - 1)
264
+ dmq1 = d % (q - 1)
265
+ if key.respond_to?(:set_key)
266
+ key.set_key(n, e, d)
261
267
  else
262
- key.p = read_bignum
263
- key.q = read_bignum
264
- key.g = read_bignum
268
+ key.e = e
269
+ key.n = n
270
+ key.d = d
265
271
  end
266
- if key.respond_to?(:set_key)
267
- key.set_key(read_bignum, nil)
272
+ if key.respond_to?(:set_factors)
273
+ key.set_factors(p, q)
268
274
  else
269
- key.pub_key = read_bignum
275
+ key.p = p
276
+ key.q = q
270
277
  end
271
- when /^ssh-rsa$/
272
- key = OpenSSL::PKey::RSA.new
273
- if key.respond_to?(:set_key)
274
- e = read_bignum
275
- n = read_bignum
276
- key.set_key(n, e, nil)
278
+ if key.respond_to?(:set_crt_params)
279
+ key.set_crt_params(dmp1, dmq1, iqmp)
277
280
  else
278
- key.e = read_bignum
279
- key.n = read_bignum
281
+ key.dmp1 = dmp1
282
+ key.dmq1 = dmq1
283
+ key.iqmp = iqmp
280
284
  end
285
+ key
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)
281
336
  when /^ssh-ed25519$/
282
337
  Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("unsupported key type `#{type}'")
283
338
  key = Net::SSH::Authentication::ED25519::PubKey.read_keyblob(self)
284
339
  when /^ecdsa\-sha2\-(\w*)$/
285
- unless defined?(OpenSSL::PKey::EC)
286
- raise NotImplementedError, "unsupported key type `#{type}'"
287
- else
288
- begin
289
- key = OpenSSL::PKey::EC.read_keyblob($1, self)
290
- rescue OpenSSL::PKey::ECError
291
- raise NotImplementedError, "unsupported key type `#{type}'"
292
- end
293
- end
340
+ key = OpenSSL::PKey::EC.read_keyblob($1, self)
294
341
  else
295
342
  raise NotImplementedError, "unsupported key type `#{type}'"
296
- end
343
+ end
297
344
 
298
- return key
299
- end
345
+ return key
346
+ end
300
347
 
301
- # Reads the next string from the buffer, and returns a new Buffer
302
- # object that wraps it.
303
- def read_buffer
304
- Buffer.new(read_string)
305
- 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
306
353
 
307
- # Writes the given data literally into the string. Does not alter the
308
- # read position. Returns the buffer object.
309
- def write(*data)
310
- data.each { |datum| @content << datum.dup.force_encoding('BINARY') }
311
- self
312
- 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
313
360
 
314
- # Optimized version of write where the caller gives up ownership of string
315
- # to the method. This way we can mutate the string.
316
- def write_moved(string)
317
- @content << string.force_encoding('BINARY')
318
- self
319
- 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
320
372
 
321
- # Writes each argument to the buffer as a network-byte-order-encoded
322
- # 64-bit integer (8 bytes). Does not alter the read position. Returns the
323
- # buffer object.
324
- def write_int64(*n)
325
- n.each do |i|
326
- hi = (i >> 32) & 0xFFFFFFFF
327
- lo = i & 0xFFFFFFFF
328
- @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
329
383
  end
330
- self
331
- end
332
384
 
333
- # Writes each argument to the buffer as a network-byte-order-encoded
334
- # long (4-byte) integer. Does not alter the read position. Returns the
335
- # buffer object.
336
- def write_long(*n)
337
- @content << n.pack("N*")
338
- self
339
- 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
340
392
 
341
- # Writes each argument to the buffer as a byte. Does not alter the read
342
- # position. Returns the buffer object.
343
- def write_byte(*n)
344
- n.each { |b| @content << b.chr }
345
- self
346
- 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
347
399
 
348
- # Writes each argument to the buffer as an SSH2-encoded string. Each
349
- # string is prefixed by its length, encoded as a 4-byte long integer.
350
- # Does not alter the read position. Returns the buffer object.
351
- def write_string(*text)
352
- text.each do |string|
353
- s = string.to_s
354
- write_long(s.bytesize)
355
- 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
356
410
  end
357
- self
358
- end
359
411
 
360
- # Writes each argument to the buffer as an SSH2-encoded string. Each
361
- # string is prefixed by its length, encoded as a 4-byte long integer.
362
- # Does not alter the read position. Returns the buffer object.
363
- # Might alter arguments see write_moved
364
- def write_mstring(*text)
365
- text.each do |string|
366
- s = string.to_s
367
- write_long(s.bytesize)
368
- write_moved(s)
369
- end
370
- self
371
- 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
372
424
 
373
- # Writes each argument to the buffer as a (C-style) boolean, with 1
374
- # meaning true, and 0 meaning false. Does not alter the read position.
375
- # Returns the buffer object.
376
- def write_bool(*b)
377
- b.each { |v| @content << (v ? "\1" : "\0") }
378
- self
379
- 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
380
432
 
381
- # Writes each argument to the buffer as a bignum (SSH2-style). No
382
- # checking is done to ensure that the arguments are, in fact, bignums.
383
- # Does not alter the read position. Returns the buffer object.
384
- def write_bignum(*n)
385
- @content << n.map { |b| b.to_ssh }.join
386
- self
387
- end
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
388
440
 
389
- # Writes the given arguments to the buffer as SSH2-encoded keys. Does not
390
- # alter the read position. Returns the buffer object.
391
- def write_key(*key)
392
- key.each { |k| append(k.to_blob) }
393
- self
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
394
447
  end
395
448
  end
396
- end; end;
449
+ end;