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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +94 -0
- data/.github/workflows/rubocop.yml +16 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +22 -0
- data/.rubocop_todo.yml +1081 -0
- data/CHANGES.txt +387 -0
- data/DEVELOPMENT.md +23 -0
- data/Dockerfile +29 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/Gemfile.norbnacl +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/Manifest +4 -5
- data/README.md +303 -0
- data/Rakefile +174 -40
- data/SECURITY.md +4 -0
- data/THANKS.txt +25 -0
- data/appveyor.yml +58 -0
- data/docker-compose.yml +25 -0
- data/lib/net/ssh/authentication/agent.rb +279 -18
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +17 -15
- data/lib/net/ssh/authentication/ed25519.rb +184 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +125 -54
- data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
- data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +19 -12
- data/lib/net/ssh/authentication/methods/none.rb +16 -19
- data/lib/net/ssh/authentication/methods/password.rb +56 -19
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
- data/lib/net/ssh/authentication/pageant.rb +483 -246
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +138 -120
- data/lib/net/ssh/buffer.rb +399 -300
- data/lib/net/ssh/buffered_io.rb +154 -150
- data/lib/net/ssh/config.rb +361 -166
- data/lib/net/ssh/connection/channel.rb +640 -596
- data/lib/net/ssh/connection/constants.rb +29 -29
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +59 -0
- data/lib/net/ssh/connection/session.rb +628 -548
- data/lib/net/ssh/connection/term.rb +125 -123
- data/lib/net/ssh/errors.rb +101 -95
- data/lib/net/ssh/key_factory.rb +198 -100
- data/lib/net/ssh/known_hosts.rb +221 -98
- data/lib/net/ssh/loggable.rb +50 -49
- data/lib/net/ssh/packet.rb +83 -79
- data/lib/net/ssh/prompt.rb +50 -81
- data/lib/net/ssh/proxy/command.rb +108 -60
- data/lib/net/ssh/proxy/errors.rb +12 -10
- data/lib/net/ssh/proxy/http.rb +82 -78
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +5 -8
- data/lib/net/ssh/proxy/socks5.rb +18 -20
- data/lib/net/ssh/service/forward.rb +383 -255
- data/lib/net/ssh/test/channel.rb +145 -136
- data/lib/net/ssh/test/extensions.rb +131 -110
- data/lib/net/ssh/test/kex.rb +34 -32
- data/lib/net/ssh/test/local_packet.rb +46 -44
- data/lib/net/ssh/test/packet.rb +89 -70
- data/lib/net/ssh/test/remote_packet.rb +32 -30
- data/lib/net/ssh/test/script.rb +156 -142
- data/lib/net/ssh/test/socket.rb +49 -48
- data/lib/net/ssh/test.rb +82 -77
- data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
- data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
- data/lib/net/ssh/transport/algorithms.rb +472 -348
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
- data/lib/net/ssh/transport/cipher_factory.rb +124 -100
- data/lib/net/ssh/transport/constants.rb +32 -24
- data/lib/net/ssh/transport/ctr.rb +42 -22
- data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +97 -63
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +14 -12
- data/lib/net/ssh/transport/identity_cipher.rb +54 -44
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
- data/lib/net/ssh/transport/kex.rb +15 -12
- data/lib/net/ssh/transport/key_expander.rb +24 -20
- data/lib/net/ssh/transport/openssl.rb +161 -124
- data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
- data/lib/net/ssh/transport/packet_stream.rb +246 -183
- data/lib/net/ssh/transport/server_version.rb +57 -51
- data/lib/net/ssh/transport/session.rb +307 -235
- data/lib/net/ssh/transport/state.rb +178 -176
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +57 -51
- data/lib/net/ssh.rb +140 -40
- data/net-ssh-public_cert.pem +21 -0
- data/net-ssh.gemspec +39 -184
- data/support/ssh_tunnel_bug.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +205 -99
- metadata.gz.sig +0 -0
- data/README.rdoc +0 -219
- data/Rudyfile +0 -96
- data/gem-public_cert.pem +0 -20
- data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
- data/lib/net/ssh/authentication/agent/socket.rb +0 -170
- data/lib/net/ssh/ruby_compat.rb +0 -51
- data/lib/net/ssh/verifiers/lenient.rb +0 -30
- data/lib/net/ssh/verifiers/null.rb +0 -12
- data/lib/net/ssh/verifiers/secure.rb +0 -54
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/setup.rb +0 -1585
- data/support/arcfour_check.rb +0 -20
- data/test/README.txt +0 -47
- data/test/authentication/methods/common.rb +0 -28
- data/test/authentication/methods/test_abstract.rb +0 -51
- data/test/authentication/methods/test_hostbased.rb +0 -114
- data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
- data/test/authentication/methods/test_none.rb +0 -41
- data/test/authentication/methods/test_password.rb +0 -52
- data/test/authentication/methods/test_publickey.rb +0 -148
- data/test/authentication/test_agent.rb +0 -205
- data/test/authentication/test_key_manager.rb +0 -218
- data/test/authentication/test_session.rb +0 -108
- data/test/common.rb +0 -108
- data/test/configs/eqsign +0 -3
- data/test/configs/exact_match +0 -8
- data/test/configs/host_plus +0 -10
- data/test/configs/multihost +0 -4
- data/test/configs/nohost +0 -19
- data/test/configs/numeric_host +0 -4
- data/test/configs/send_env +0 -2
- data/test/configs/substitutes +0 -8
- data/test/configs/wild_cards +0 -14
- data/test/connection/test_channel.rb +0 -467
- data/test/connection/test_session.rb +0 -526
- data/test/known_hosts/github +0 -1
- data/test/manual/test_forward.rb +0 -223
- data/test/start/test_options.rb +0 -36
- data/test/start/test_transport.rb +0 -28
- data/test/test_all.rb +0 -11
- data/test/test_buffer.rb +0 -433
- data/test/test_buffered_io.rb +0 -63
- data/test/test_config.rb +0 -151
- data/test/test_key_factory.rb +0 -173
- data/test/test_known_hosts.rb +0 -13
- data/test/transport/hmac/test_md5.rb +0 -41
- data/test/transport/hmac/test_md5_96.rb +0 -27
- data/test/transport/hmac/test_none.rb +0 -34
- data/test/transport/hmac/test_ripemd160.rb +0 -36
- data/test/transport/hmac/test_sha1.rb +0 -36
- data/test/transport/hmac/test_sha1_96.rb +0 -27
- data/test/transport/hmac/test_sha2_256.rb +0 -37
- data/test/transport/hmac/test_sha2_256_96.rb +0 -27
- data/test/transport/hmac/test_sha2_512.rb +0 -37
- data/test/transport/hmac/test_sha2_512_96.rb +0 -27
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
- data/test/transport/test_algorithms.rb +0 -330
- data/test/transport/test_cipher_factory.rb +0 -443
- data/test/transport/test_hmac.rb +0 -34
- data/test/transport/test_identity_cipher.rb +0 -40
- data/test/transport/test_packet_stream.rb +0 -1755
- data/test/transport/test_server_version.rb +0 -78
- data/test/transport/test_session.rb +0 -319
- data/test/transport/test_state.rb +0 -181
data/lib/net/ssh/buffer.rb
CHANGED
@@ -1,350 +1,449 @@
|
|
1
|
-
require 'net/ssh/ruby_compat'
|
2
1
|
require 'net/ssh/transport/openssl'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
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
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
65
|
+
# exposes the raw content of the buffer
|
66
|
+
attr_reader :content
|
61
67
|
|
62
|
-
|
63
|
-
|
68
|
+
# the current position of the pointer in the buffer
|
69
|
+
attr_accessor :position
|
64
70
|
|
65
|
-
|
66
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
89
|
+
# Returns a copy of the buffer's content.
|
90
|
+
def to_s
|
91
|
+
(@content || "").dup
|
92
|
+
end
|
85
93
|
|
86
|
-
|
87
|
-
|
88
|
-
(
|
89
|
-
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
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
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
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
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
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
|
-
|
243
|
-
|
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
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
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
|
-
|
273
|
-
|
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
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
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
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
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
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
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
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
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
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
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
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
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;
|
449
|
+
end;
|