net-ssh 1.1.4 → 2.0.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.
- data/CHANGELOG.rdoc +37 -0
- data/Manifest +101 -0
- data/README.rdoc +110 -0
- data/Rakefile +26 -0
- data/{THANKS → THANKS.rdoc} +2 -5
- data/lib/net/ssh.rb +189 -57
- data/lib/net/ssh/authentication/agent.rb +175 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +166 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
- data/lib/net/ssh/authentication/methods/password.rb +39 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +92 -0
- data/lib/net/ssh/authentication/pageant.rb +176 -0
- data/lib/net/ssh/authentication/session.rb +116 -0
- data/lib/net/ssh/buffer.rb +339 -0
- data/lib/net/ssh/buffered_io.rb +149 -0
- data/lib/net/ssh/config.rb +173 -0
- data/lib/net/ssh/connection/channel.rb +575 -454
- data/lib/net/ssh/connection/constants.rb +31 -45
- data/lib/net/ssh/connection/session.rb +569 -0
- data/lib/net/ssh/connection/term.rb +176 -88
- data/lib/net/ssh/errors.rb +83 -61
- data/lib/net/ssh/key_factory.rb +85 -0
- data/lib/net/ssh/known_hosts.rb +129 -0
- data/lib/net/ssh/loggable.rb +61 -0
- data/lib/net/ssh/packet.rb +102 -0
- data/lib/net/ssh/prompt.rb +93 -0
- data/lib/net/ssh/proxy/errors.rb +8 -28
- data/lib/net/ssh/proxy/http.rb +75 -107
- data/lib/net/ssh/proxy/socks4.rb +35 -48
- data/lib/net/ssh/proxy/socks5.rb +76 -108
- data/lib/net/ssh/service/forward.rb +267 -0
- data/lib/net/ssh/test.rb +89 -0
- data/lib/net/ssh/test/channel.rb +129 -0
- data/lib/net/ssh/test/extensions.rb +152 -0
- data/lib/net/ssh/test/kex.rb +44 -0
- data/lib/net/ssh/test/local_packet.rb +51 -0
- data/lib/net/ssh/test/packet.rb +81 -0
- data/lib/net/ssh/test/remote_packet.rb +38 -0
- data/lib/net/ssh/test/script.rb +157 -0
- data/lib/net/ssh/test/socket.rb +59 -0
- data/lib/net/ssh/transport/algorithms.rb +384 -0
- data/lib/net/ssh/transport/cipher_factory.rb +72 -0
- data/lib/net/ssh/transport/constants.rb +22 -58
- data/lib/net/ssh/transport/hmac.rb +31 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +48 -0
- data/lib/net/ssh/transport/hmac/md5.rb +12 -0
- data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
- data/lib/net/ssh/transport/hmac/none.rb +15 -0
- data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
- data/lib/net/ssh/transport/identity_cipher.rb +40 -0
- data/lib/net/ssh/transport/kex.rb +13 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
- data/lib/net/ssh/{util → transport}/openssl.rb +22 -40
- data/lib/net/ssh/transport/packet_stream.rb +230 -0
- data/lib/net/ssh/transport/server_version.rb +61 -0
- data/lib/net/ssh/transport/session.rb +225 -303
- data/lib/net/ssh/transport/state.rb +170 -0
- data/lib/net/ssh/verifiers/lenient.rb +30 -0
- data/lib/net/ssh/verifiers/null.rb +12 -0
- data/lib/net/ssh/verifiers/strict.rb +53 -0
- data/lib/net/ssh/version.rb +57 -26
- data/net-ssh.gemspec +54 -0
- data/setup.rb +1585 -0
- data/test/authentication/methods/common.rb +28 -0
- data/test/authentication/methods/test_abstract.rb +51 -0
- data/test/authentication/methods/test_hostbased.rb +108 -0
- data/test/authentication/methods/test_keyboard_interactive.rb +98 -0
- data/test/authentication/methods/test_password.rb +50 -0
- data/test/authentication/methods/test_publickey.rb +123 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +100 -0
- data/test/authentication/test_session.rb +93 -0
- data/test/common.rb +106 -0
- data/test/configs/exact_match +8 -0
- data/test/configs/wild_cards +14 -0
- data/test/connection/test_channel.rb +452 -0
- data/test/connection/test_session.rb +483 -0
- data/test/test_all.rb +6 -0
- data/test/test_buffer.rb +336 -0
- data/test/test_buffered_io.rb +63 -0
- data/test/test_config.rb +78 -0
- data/test/test_key_factory.rb +67 -0
- data/test/transport/hmac/test_md5.rb +34 -0
- data/test/transport/hmac/test_md5_96.rb +25 -0
- data/test/transport/hmac/test_none.rb +34 -0
- data/test/transport/hmac/test_sha1.rb +34 -0
- data/test/transport/hmac/test_sha1_96.rb +25 -0
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
- data/test/transport/test_algorithms.rb +302 -0
- data/test/transport/test_cipher_factory.rb +163 -0
- data/test/transport/test_hmac.rb +34 -0
- data/test/transport/test_identity_cipher.rb +40 -0
- data/test/transport/test_packet_stream.rb +433 -0
- data/test/transport/test_server_version.rb +55 -0
- data/test/transport/test_session.rb +312 -0
- data/test/transport/test_state.rb +173 -0
- metadata +102 -253
- data/ChangeLog +0 -560
- data/LICENSE +0 -7
- data/NEWS +0 -152
- data/README +0 -14
- data/bin/rb-keygen +0 -210
- data/doc/LICENSE-BSD +0 -27
- data/doc/LICENSE-GPL +0 -280
- data/doc/LICENSE-RUBY +0 -56
- data/doc/manual-html/chapter-1.html +0 -388
- data/doc/manual-html/chapter-2.html +0 -552
- data/doc/manual-html/chapter-3.html +0 -470
- data/doc/manual-html/chapter-4.html +0 -413
- data/doc/manual-html/chapter-5.html +0 -525
- data/doc/manual-html/chapter-6.html +0 -456
- data/doc/manual-html/chapter-7.html +0 -343
- data/doc/manual-html/index.html +0 -235
- data/doc/manual-html/stylesheets/manual.css +0 -270
- data/doc/manual-html/stylesheets/ruby.css +0 -17
- data/doc/manual/chapter.erb +0 -38
- data/doc/manual/example.erb +0 -18
- data/doc/manual/index.erb +0 -29
- data/doc/manual/manual.rb +0 -311
- data/doc/manual/manual.yml +0 -73
- data/doc/manual/page.erb +0 -87
- data/doc/manual/parts/0000.txt +0 -5
- data/doc/manual/parts/0001.txt +0 -3
- data/doc/manual/parts/0002.txt +0 -40
- data/doc/manual/parts/0003.txt +0 -6
- data/doc/manual/parts/0004.txt +0 -7
- data/doc/manual/parts/0005.txt +0 -1
- data/doc/manual/parts/0006.txt +0 -49
- data/doc/manual/parts/0007.txt +0 -67
- data/doc/manual/parts/0008.txt +0 -43
- data/doc/manual/parts/0009.txt +0 -14
- data/doc/manual/parts/0010.txt +0 -7
- data/doc/manual/parts/0011.txt +0 -14
- data/doc/manual/parts/0012.txt +0 -3
- data/doc/manual/parts/0013.txt +0 -20
- data/doc/manual/parts/0014.txt +0 -32
- data/doc/manual/parts/0015.txt +0 -14
- data/doc/manual/parts/0016.txt +0 -28
- data/doc/manual/parts/0017.txt +0 -50
- data/doc/manual/parts/0018.txt +0 -35
- data/doc/manual/parts/0019.txt +0 -7
- data/doc/manual/parts/0020.txt +0 -72
- data/doc/manual/parts/0021.txt +0 -50
- data/doc/manual/parts/0022.txt +0 -42
- data/doc/manual/parts/0023.txt +0 -51
- data/doc/manual/parts/0024.txt +0 -18
- data/doc/manual/parts/0025.txt +0 -18
- data/doc/manual/parts/0026.txt +0 -15
- data/doc/manual/parts/0027.txt +0 -37
- data/doc/manual/parts/0028.txt +0 -16
- data/doc/manual/parts/0029.txt +0 -1
- data/doc/manual/parts/0030.txt +0 -52
- data/doc/manual/parts/0031.txt +0 -25
- data/doc/manual/stylesheets/manual.css +0 -270
- data/doc/manual/stylesheets/ruby.css +0 -17
- data/doc/manual/tutorial.erb +0 -30
- data/examples/auth-forward.rb +0 -41
- data/examples/channel-demo.rb +0 -81
- data/examples/port-forward.rb +0 -51
- data/examples/process-demo.rb +0 -91
- data/examples/remote-net-port-forward.rb +0 -45
- data/examples/remote-port-forward.rb +0 -80
- data/examples/shell-demo.rb +0 -46
- data/examples/ssh-client.rb +0 -67
- data/examples/sync-shell-demo.rb +0 -69
- data/examples/tail-demo.rb +0 -49
- data/lib/net/ssh/connection/driver.rb +0 -446
- data/lib/net/ssh/connection/services.rb +0 -72
- data/lib/net/ssh/host-key-verifier.rb +0 -52
- data/lib/net/ssh/known-hosts.rb +0 -96
- data/lib/net/ssh/lenient-host-key-verifier.rb +0 -25
- data/lib/net/ssh/null-host-key-verifier.rb +0 -14
- data/lib/net/ssh/service/agentforward/driver.rb +0 -78
- data/lib/net/ssh/service/agentforward/services.rb +0 -41
- data/lib/net/ssh/service/forward/driver.rb +0 -319
- data/lib/net/ssh/service/forward/local-network-handler.rb +0 -71
- data/lib/net/ssh/service/forward/remote-network-handler.rb +0 -83
- data/lib/net/ssh/service/forward/services.rb +0 -76
- data/lib/net/ssh/service/process/driver.rb +0 -153
- data/lib/net/ssh/service/process/open.rb +0 -193
- data/lib/net/ssh/service/process/popen3.rb +0 -178
- data/lib/net/ssh/service/process/services.rb +0 -66
- data/lib/net/ssh/service/services.rb +0 -60
- data/lib/net/ssh/service/shell/driver.rb +0 -86
- data/lib/net/ssh/service/shell/services.rb +0 -54
- data/lib/net/ssh/service/shell/shell.rb +0 -222
- data/lib/net/ssh/service/shell/sync.rb +0 -114
- data/lib/net/ssh/session.rb +0 -305
- data/lib/net/ssh/transport/algorithm-negotiator.rb +0 -275
- data/lib/net/ssh/transport/compress/compressor.rb +0 -53
- data/lib/net/ssh/transport/compress/decompressor.rb +0 -53
- data/lib/net/ssh/transport/compress/none-compressor.rb +0 -39
- data/lib/net/ssh/transport/compress/none-decompressor.rb +0 -39
- data/lib/net/ssh/transport/compress/services.rb +0 -68
- data/lib/net/ssh/transport/compress/zlib-compressor.rb +0 -60
- data/lib/net/ssh/transport/compress/zlib-decompressor.rb +0 -52
- data/lib/net/ssh/transport/errors.rb +0 -47
- data/lib/net/ssh/transport/identity-cipher.rb +0 -61
- data/lib/net/ssh/transport/kex/dh-gex.rb +0 -106
- data/lib/net/ssh/transport/kex/dh.rb +0 -249
- data/lib/net/ssh/transport/kex/services.rb +0 -62
- data/lib/net/ssh/transport/ossl/buffer-factory.rb +0 -52
- data/lib/net/ssh/transport/ossl/buffer.rb +0 -87
- data/lib/net/ssh/transport/ossl/cipher-factory.rb +0 -98
- data/lib/net/ssh/transport/ossl/digest-factory.rb +0 -51
- data/lib/net/ssh/transport/ossl/hmac-factory.rb +0 -71
- data/lib/net/ssh/transport/ossl/hmac/hmac.rb +0 -62
- data/lib/net/ssh/transport/ossl/hmac/md5-96.rb +0 -44
- data/lib/net/ssh/transport/ossl/hmac/md5.rb +0 -46
- data/lib/net/ssh/transport/ossl/hmac/none.rb +0 -46
- data/lib/net/ssh/transport/ossl/hmac/services.rb +0 -68
- data/lib/net/ssh/transport/ossl/hmac/sha1-96.rb +0 -44
- data/lib/net/ssh/transport/ossl/hmac/sha1.rb +0 -45
- data/lib/net/ssh/transport/ossl/key-factory.rb +0 -116
- data/lib/net/ssh/transport/ossl/services.rb +0 -149
- data/lib/net/ssh/transport/packet-stream.rb +0 -236
- data/lib/net/ssh/transport/services.rb +0 -146
- data/lib/net/ssh/transport/version-negotiator.rb +0 -73
- data/lib/net/ssh/userauth/agent.rb +0 -222
- data/lib/net/ssh/userauth/constants.rb +0 -35
- data/lib/net/ssh/userauth/driver.rb +0 -183
- data/lib/net/ssh/userauth/methods/hostbased.rb +0 -119
- data/lib/net/ssh/userauth/methods/keyboard-interactive.rb +0 -104
- data/lib/net/ssh/userauth/methods/password.rb +0 -70
- data/lib/net/ssh/userauth/methods/publickey.rb +0 -137
- data/lib/net/ssh/userauth/methods/services.rb +0 -90
- data/lib/net/ssh/userauth/pageant.rb +0 -197
- data/lib/net/ssh/userauth/services.rb +0 -141
- data/lib/net/ssh/userauth/userkeys.rb +0 -258
- data/lib/net/ssh/util/buffer.rb +0 -274
- data/lib/net/ssh/util/prompter.rb +0 -73
- data/test/ALL-TESTS.rb +0 -18
- data/test/connection/tc_channel.rb +0 -136
- data/test/connection/tc_driver.rb +0 -287
- data/test/connection/tc_integration.rb +0 -87
- data/test/proxy/tc_http.rb +0 -209
- data/test/proxy/tc_socks4.rb +0 -148
- data/test/proxy/tc_socks5.rb +0 -214
- data/test/service/agentforward/tc_driver.rb +0 -138
- data/test/service/forward/tc_driver.rb +0 -289
- data/test/service/forward/tc_local_network_handler.rb +0 -123
- data/test/service/forward/tc_remote_network_handler.rb +0 -111
- data/test/service/process/tc_driver.rb +0 -79
- data/test/service/process/tc_integration.rb +0 -119
- data/test/service/process/tc_open.rb +0 -179
- data/test/service/process/tc_popen3.rb +0 -164
- data/test/tc_integration.rb +0 -80
- data/test/transport/compress/tc_none_compress.rb +0 -41
- data/test/transport/compress/tc_none_decompress.rb +0 -45
- data/test/transport/compress/tc_zlib_compress.rb +0 -61
- data/test/transport/compress/tc_zlib_decompress.rb +0 -48
- data/test/transport/kex/tc_dh.rb +0 -312
- data/test/transport/kex/tc_dh_gex.rb +0 -71
- data/test/transport/ossl/fixtures/dsa-encrypted +0 -15
- data/test/transport/ossl/fixtures/dsa-encrypted-bad +0 -15
- data/test/transport/ossl/fixtures/dsa-unencrypted +0 -12
- data/test/transport/ossl/fixtures/dsa-unencrypted-bad +0 -12
- data/test/transport/ossl/fixtures/dsa-unencrypted.pub +0 -1
- data/test/transport/ossl/fixtures/not-a-private-key +0 -4
- data/test/transport/ossl/fixtures/not-supported +0 -2
- data/test/transport/ossl/fixtures/rsa-encrypted +0 -18
- data/test/transport/ossl/fixtures/rsa-encrypted-bad +0 -18
- data/test/transport/ossl/fixtures/rsa-unencrypted +0 -15
- data/test/transport/ossl/fixtures/rsa-unencrypted-bad +0 -15
- data/test/transport/ossl/fixtures/rsa-unencrypted.pub +0 -1
- data/test/transport/ossl/hmac/tc_hmac.rb +0 -58
- data/test/transport/ossl/hmac/tc_md5.rb +0 -50
- data/test/transport/ossl/hmac/tc_md5_96.rb +0 -50
- data/test/transport/ossl/hmac/tc_none.rb +0 -50
- data/test/transport/ossl/hmac/tc_sha1.rb +0 -50
- data/test/transport/ossl/hmac/tc_sha1_96.rb +0 -50
- data/test/transport/ossl/tc_buffer.rb +0 -97
- data/test/transport/ossl/tc_buffer_factory.rb +0 -67
- data/test/transport/ossl/tc_cipher_factory.rb +0 -84
- data/test/transport/ossl/tc_digest_factory.rb +0 -39
- data/test/transport/ossl/tc_hmac_factory.rb +0 -72
- data/test/transport/ossl/tc_key_factory.rb +0 -199
- data/test/transport/tc_algorithm_negotiator.rb +0 -170
- data/test/transport/tc_identity_cipher.rb +0 -52
- data/test/transport/tc_integration.rb +0 -115
- data/test/transport/tc_packet_stream.rb +0 -184
- data/test/transport/tc_session.rb +0 -296
- data/test/transport/tc_version_negotiator.rb +0 -86
- data/test/userauth/methods/tc_hostbased.rb +0 -136
- data/test/userauth/methods/tc_password.rb +0 -89
- data/test/userauth/methods/tc_publickey.rb +0 -167
- data/test/userauth/tc_agent.rb +0 -223
- data/test/userauth/tc_driver.rb +0 -190
- data/test/userauth/tc_integration.rb +0 -97
- data/test/userauth/tc_userkeys.rb +0 -265
- data/test/util/tc_buffer.rb +0 -217
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'net/ssh/errors'
|
2
|
+
require 'net/ssh/transport/constants'
|
3
|
+
require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
|
4
|
+
|
5
|
+
module Net::SSH::Transport::Kex
|
6
|
+
|
7
|
+
# A key-exchange service implementing the
|
8
|
+
# "diffie-hellman-group-exchange-sha1" key-exchange algorithm.
|
9
|
+
class DiffieHellmanGroupExchangeSHA1 < DiffieHellmanGroup1SHA1
|
10
|
+
MINIMUM_BITS = 1024
|
11
|
+
MAXIMUM_BITS = 8192
|
12
|
+
|
13
|
+
KEXDH_GEX_GROUP = 31
|
14
|
+
KEXDH_GEX_INIT = 32
|
15
|
+
KEXDH_GEX_REPLY = 33
|
16
|
+
KEXDH_GEX_REQUEST = 34
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Compute the number of bits needed for the given number of bytes.
|
21
|
+
def compute_need_bits
|
22
|
+
need_bits = data[:need_bytes] * 8
|
23
|
+
if need_bits < MINIMUM_BITS
|
24
|
+
need_bits = MINIMUM_BITS
|
25
|
+
elsif need_bits > MAXIMUM_BITS
|
26
|
+
need_bits = MAXIMUM_BITS
|
27
|
+
end
|
28
|
+
|
29
|
+
data[:need_bits ] = need_bits
|
30
|
+
data[:need_bytes] = need_bits / 8
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the DH key parameters for the given session.
|
34
|
+
def get_parameters
|
35
|
+
compute_need_bits
|
36
|
+
|
37
|
+
# request the DH key parameters for the given number of bits.
|
38
|
+
buffer = Net::SSH::Buffer.from(:byte, KEXDH_GEX_REQUEST, :long, MINIMUM_BITS,
|
39
|
+
:long, data[:need_bits], :long, MAXIMUM_BITS)
|
40
|
+
connection.send_message(buffer)
|
41
|
+
|
42
|
+
buffer = connection.next_message
|
43
|
+
unless buffer.type == KEXDH_GEX_GROUP
|
44
|
+
raise Net::SSH::Exception, "expected KEXDH_GEX_GROUP, got #{buffer.type}"
|
45
|
+
end
|
46
|
+
|
47
|
+
p = buffer.read_bignum
|
48
|
+
g = buffer.read_bignum
|
49
|
+
|
50
|
+
[p, g]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the INIT/REPLY constants used by this algorithm.
|
54
|
+
def get_message_types
|
55
|
+
[KEXDH_GEX_INIT, KEXDH_GEX_REPLY]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Build the signature buffer to use when verifying a signature from
|
59
|
+
# the server.
|
60
|
+
def build_signature_buffer(result)
|
61
|
+
response = Net::SSH::Buffer.new
|
62
|
+
response.write_string data[:client_version_string],
|
63
|
+
data[:server_version_string],
|
64
|
+
data[:client_algorithm_packet],
|
65
|
+
data[:server_algorithm_packet],
|
66
|
+
result[:key_blob]
|
67
|
+
response.write_long MINIMUM_BITS,
|
68
|
+
data[:need_bits],
|
69
|
+
MAXIMUM_BITS
|
70
|
+
response.write_bignum dh.p, dh.g, dh.pub_key,
|
71
|
+
result[:server_dh_pubkey],
|
72
|
+
result[:shared_secret]
|
73
|
+
response
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -1,22 +1,5 @@
|
|
1
|
-
#--
|
2
|
-
# =============================================================================
|
3
|
-
# Copyright (c) 2004,2005 Jamis Buck (jamis@37signals.com)
|
4
|
-
# All rights reserved.
|
5
|
-
#
|
6
|
-
# This source file is distributed as part of the Net::SSH Secure Shell Client
|
7
|
-
# library for Ruby. This file (and the library as a whole) may be used only as
|
8
|
-
# allowed by either the BSD license, or the Ruby license (or, by association
|
9
|
-
# with the Ruby license, the GPL). See the "doc" subdirectory of the Net::SSH
|
10
|
-
# distribution for the texts of these licenses.
|
11
|
-
# -----------------------------------------------------------------------------
|
12
|
-
# net-ssh website : http://net-ssh.rubyforge.org
|
13
|
-
# project website: http://rubyforge.org/projects/net-ssh
|
14
|
-
# =============================================================================
|
15
|
-
#++
|
16
|
-
|
17
|
-
require 'base64'
|
18
1
|
require 'openssl'
|
19
|
-
require 'net/ssh/
|
2
|
+
require 'net/ssh/buffer'
|
20
3
|
|
21
4
|
module OpenSSL
|
22
5
|
|
@@ -29,13 +12,13 @@ module OpenSSL
|
|
29
12
|
# required by the SSH2 protocol.
|
30
13
|
def to_ssh
|
31
14
|
if zero?
|
32
|
-
return [
|
15
|
+
return [0].pack("N")
|
33
16
|
else
|
34
|
-
buf = to_s(
|
17
|
+
buf = to_s(2)
|
35
18
|
if buf[0][7] == 1
|
36
|
-
return [
|
19
|
+
return [buf.length+1, 0, buf].pack("NCA*")
|
37
20
|
else
|
38
|
-
return [
|
21
|
+
return [buf.length, buf].pack("NA*")
|
39
22
|
end
|
40
23
|
end
|
41
24
|
end
|
@@ -44,6 +27,12 @@ module OpenSSL
|
|
44
27
|
|
45
28
|
module PKey
|
46
29
|
|
30
|
+
class PKey
|
31
|
+
def fingerprint
|
32
|
+
@fingerprint ||= OpenSSL::Digest::MD5.hexdigest(to_blob).scan(/../).join(":")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
47
36
|
# This class is originally defined in the OpenSSL module. As needed, methods
|
48
37
|
# have been added to it by the Net::SSH module for convenience in dealing
|
49
38
|
# with SSH functionality.
|
@@ -52,9 +41,9 @@ module OpenSSL
|
|
52
41
|
# Determines whether the pub_key for this key is valid. (This algorithm
|
53
42
|
# lifted more-or-less directly from OpenSSH, dh.c, dh_pub_is_valid.)
|
54
43
|
def valid?
|
55
|
-
return false if pub_key < 0
|
44
|
+
return false if pub_key.nil? || pub_key < 0
|
56
45
|
bits_set = 0
|
57
|
-
pub_key.num_bits.times { |i| bits_set += 1 if pub_key.bit_set?
|
46
|
+
pub_key.num_bits.times { |i| bits_set += 1 if pub_key.bit_set?(i) }
|
58
47
|
return ( bits_set > 1 && pub_key < p )
|
59
48
|
end
|
60
49
|
|
@@ -73,20 +62,17 @@ module OpenSSL
|
|
73
62
|
|
74
63
|
# Converts the key to a blob, according to the SSH2 protocol.
|
75
64
|
def to_blob
|
76
|
-
|
77
|
-
buffer.write_bignum( e )
|
78
|
-
buffer.write_bignum( n )
|
79
|
-
return buffer.to_s
|
65
|
+
@blob ||= Net::SSH::Buffer.from(:string, ssh_type, :bignum, e, :bignum, n).to_s
|
80
66
|
end
|
81
67
|
|
82
68
|
# Verifies the given signature matches the given data.
|
83
|
-
def ssh_do_verify(
|
84
|
-
verify(
|
69
|
+
def ssh_do_verify(sig, data)
|
70
|
+
verify(OpenSSL::Digest::SHA1.new, sig, data)
|
85
71
|
end
|
86
72
|
|
87
73
|
# Returns the signature for the given data.
|
88
|
-
def ssh_do_sign(
|
89
|
-
sign(
|
74
|
+
def ssh_do_sign(data)
|
75
|
+
sign(OpenSSL::Digest::SHA1.new, data)
|
90
76
|
end
|
91
77
|
end
|
92
78
|
|
@@ -103,16 +89,12 @@ module OpenSSL
|
|
103
89
|
|
104
90
|
# Converts the key to a blob, according to the SSH2 protocol.
|
105
91
|
def to_blob
|
106
|
-
|
107
|
-
|
108
|
-
buffer.write_bignum( q )
|
109
|
-
buffer.write_bignum( g )
|
110
|
-
buffer.write_bignum( pub_key )
|
111
|
-
return buffer.to_s
|
92
|
+
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
93
|
+
:bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
|
112
94
|
end
|
113
95
|
|
114
96
|
# Verifies the given signature matches the given data.
|
115
|
-
def ssh_do_verify(
|
97
|
+
def ssh_do_verify(sig, data)
|
116
98
|
sig_r = sig[0,20].unpack("H*")[0].to_i(16)
|
117
99
|
sig_s = sig[20,20].unpack("H*")[0].to_i(16)
|
118
100
|
a1sig = OpenSSL::ASN1::Sequence([
|
@@ -123,7 +105,7 @@ module OpenSSL
|
|
123
105
|
end
|
124
106
|
|
125
107
|
# Signs the given data.
|
126
|
-
def ssh_do_sign(
|
108
|
+
def ssh_do_sign(data)
|
127
109
|
sig = sign( OpenSSL::Digest::DSS1.new, data)
|
128
110
|
a1sig = OpenSSL::ASN1.decode( sig )
|
129
111
|
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'net/ssh/buffered_io'
|
2
|
+
require 'net/ssh/errors'
|
3
|
+
require 'net/ssh/packet'
|
4
|
+
require 'net/ssh/transport/cipher_factory'
|
5
|
+
require 'net/ssh/transport/hmac'
|
6
|
+
require 'net/ssh/transport/state'
|
7
|
+
|
8
|
+
module Net; module SSH; module Transport
|
9
|
+
|
10
|
+
# A module that builds additional functionality onto the Net::SSH::BufferedIo
|
11
|
+
# module. It adds SSH encryption, compression, and packet validation, as
|
12
|
+
# per the SSH2 protocol. It also adds an abstraction for polling packets,
|
13
|
+
# to allow for both blocking and non-blocking reads.
|
14
|
+
module PacketStream
|
15
|
+
include BufferedIo
|
16
|
+
|
17
|
+
def self.extended(object)
|
18
|
+
object.__send__(:initialize_ssh)
|
19
|
+
end
|
20
|
+
|
21
|
+
# The map of "hints" that can be used to modify the behavior of the packet
|
22
|
+
# stream. For instance, when authentication succeeds, an "authenticated"
|
23
|
+
# hint is set, which is used to determine whether or not to compress the
|
24
|
+
# data when using the "delayed" compression algorithm.
|
25
|
+
attr_reader :hints
|
26
|
+
|
27
|
+
# The server state object, which encapsulates the algorithms used to interpret
|
28
|
+
# packets coming from the server.
|
29
|
+
attr_reader :server
|
30
|
+
|
31
|
+
# The client state object, which encapsulates the algorithms used to build
|
32
|
+
# packets to send to the server.
|
33
|
+
attr_reader :client
|
34
|
+
|
35
|
+
# The name of the client (local) end of the socket, as reported by the
|
36
|
+
# socket.
|
37
|
+
def client_name
|
38
|
+
@client_name ||= begin
|
39
|
+
sockaddr = getsockname
|
40
|
+
begin
|
41
|
+
Socket.getnameinfo(sockaddr, Socket::NI_NAMEREQD).first
|
42
|
+
rescue
|
43
|
+
begin
|
44
|
+
Socket.getnameinfo(sockaddr).first
|
45
|
+
rescue
|
46
|
+
begin
|
47
|
+
Socket.gethostbyname(Socket.gethostname).first
|
48
|
+
rescue
|
49
|
+
lwarn { "the client ipaddr/name could not be determined" }
|
50
|
+
"unknown"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# The IP address of the peer (remote) end of the socket, as reported by
|
58
|
+
# the socket.
|
59
|
+
def peer_ip
|
60
|
+
@peer_ip ||= begin
|
61
|
+
addr = getpeername
|
62
|
+
Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns true if the IO is available for reading, and false otherwise.
|
67
|
+
def available_for_read?
|
68
|
+
result = IO.select([self], nil, nil, 0)
|
69
|
+
result && result.first.any?
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the next full packet. If the mode parameter is :nonblock (the
|
73
|
+
# default), then this will return immediately, whether a packet is
|
74
|
+
# available or not, and will return nil if there is no packet ready to be
|
75
|
+
# returned. If the mode parameter is :block, then this method will block
|
76
|
+
# until a packet is available.
|
77
|
+
def next_packet(mode=:nonblock)
|
78
|
+
case mode
|
79
|
+
when :nonblock then
|
80
|
+
fill if available_for_read?
|
81
|
+
poll_next_packet
|
82
|
+
|
83
|
+
when :block then
|
84
|
+
loop do
|
85
|
+
packet = poll_next_packet
|
86
|
+
return packet if packet
|
87
|
+
|
88
|
+
loop do
|
89
|
+
result = IO.select([self]) or next
|
90
|
+
break if result.first.any?
|
91
|
+
end
|
92
|
+
|
93
|
+
if fill <= 0
|
94
|
+
raise Net::SSH::Disconnect, "connection closed by remote host"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
else
|
99
|
+
raise ArgumentError, "expected :block or :nonblock, got #{mode.inspect}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Enqueues a packet to be sent, and blocks until the entire packet is
|
104
|
+
# sent.
|
105
|
+
def send_packet(payload)
|
106
|
+
enqueue_packet(payload)
|
107
|
+
wait_for_pending_sends
|
108
|
+
end
|
109
|
+
|
110
|
+
# Enqueues a packet to be sent, but does not immediately send the packet.
|
111
|
+
# The given payload is pre-processed according to the algorithms specified
|
112
|
+
# in the client state (compression, cipher, and hmac).
|
113
|
+
def enqueue_packet(payload)
|
114
|
+
# try to compress the packet
|
115
|
+
payload = client.compress(payload)
|
116
|
+
|
117
|
+
# the length of the packet, minus the padding
|
118
|
+
actual_length = 4 + payload.length + 1
|
119
|
+
|
120
|
+
# compute the padding length
|
121
|
+
padding_length = client.cipher.block_size - (actual_length % client.cipher.block_size)
|
122
|
+
padding_length += client.cipher.block_size if padding_length < 4
|
123
|
+
|
124
|
+
# compute the packet length (sans the length field itself)
|
125
|
+
packet_length = payload.length + padding_length + 1
|
126
|
+
|
127
|
+
if packet_length < 16
|
128
|
+
padding_length += client.cipher.block_size
|
129
|
+
packet_length = payload.length + padding_length + 1
|
130
|
+
end
|
131
|
+
|
132
|
+
padding = Array.new(padding_length) { rand(256) }.pack("C*")
|
133
|
+
|
134
|
+
unencrypted_data = [packet_length, padding_length, payload, padding].pack("NCA*A*")
|
135
|
+
mac = client.hmac.digest([client.sequence_number, unencrypted_data].pack("NA*"))
|
136
|
+
|
137
|
+
encrypted_data = client.cipher.update(unencrypted_data) << client.cipher.final
|
138
|
+
message = encrypted_data + mac
|
139
|
+
|
140
|
+
debug { "queueing packet nr #{client.sequence_number} type #{payload[0]} len #{packet_length}" }
|
141
|
+
enqueue(message)
|
142
|
+
|
143
|
+
client.increment(packet_length)
|
144
|
+
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
# Performs any pending cleanup necessary on the IO and its associated
|
149
|
+
# state objects. (See State#cleanup).
|
150
|
+
def cleanup
|
151
|
+
client.cleanup
|
152
|
+
server.cleanup
|
153
|
+
end
|
154
|
+
|
155
|
+
# If the IO object requires a rekey operation (as indicated by either its
|
156
|
+
# client or server state objects, see State#needs_rekey?), this will
|
157
|
+
# yield. Otherwise, this does nothing.
|
158
|
+
def if_needs_rekey?
|
159
|
+
if client.needs_rekey? || server.needs_rekey?
|
160
|
+
yield
|
161
|
+
client.reset! if client.needs_rekey?
|
162
|
+
server.reset! if server.needs_rekey?
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
protected
|
167
|
+
|
168
|
+
# Called when this module is used to extend an object. It initializes
|
169
|
+
# the states and generally prepares the object for use as a packet stream.
|
170
|
+
def initialize_ssh
|
171
|
+
@hints = {}
|
172
|
+
@server = State.new(self)
|
173
|
+
@client = State.new(self)
|
174
|
+
@packet = nil
|
175
|
+
initialize_buffered_io
|
176
|
+
end
|
177
|
+
|
178
|
+
# Tries to read the next packet. If there is insufficient data to read
|
179
|
+
# an entire packet, this returns immediately, otherwise the packet is
|
180
|
+
# read, post-processed according to the cipher, hmac, and compression
|
181
|
+
# algorithms specified in the server state object, and returned as a
|
182
|
+
# new Packet object.
|
183
|
+
def poll_next_packet
|
184
|
+
if @packet.nil?
|
185
|
+
minimum = server.cipher.block_size < 4 ? 4 : server.cipher.block_size
|
186
|
+
return nil if available < minimum
|
187
|
+
data = read_available(minimum)
|
188
|
+
|
189
|
+
# decipher it
|
190
|
+
@packet = Net::SSH::Buffer.new(server.cipher.update(data))
|
191
|
+
@packet_length = @packet.read_long
|
192
|
+
end
|
193
|
+
|
194
|
+
need = @packet_length + 4 - server.cipher.block_size
|
195
|
+
raise Net::SSH::Exception, "padding error, need #{need} block #{server.cipher.block_size}" if need % server.cipher.block_size != 0
|
196
|
+
|
197
|
+
return nil if available < need + server.hmac.mac_length
|
198
|
+
|
199
|
+
if need > 0
|
200
|
+
# read the remainder of the packet and decrypt it.
|
201
|
+
data = read_available(need)
|
202
|
+
@packet.append(server.cipher.update(data))
|
203
|
+
end
|
204
|
+
|
205
|
+
# get the hmac from the tail of the packet (if one exists), and
|
206
|
+
# then validate it.
|
207
|
+
real_hmac = read_available(server.hmac.mac_length) || ""
|
208
|
+
|
209
|
+
@packet.append(server.cipher.final)
|
210
|
+
padding_length = @packet.read_byte
|
211
|
+
|
212
|
+
payload = @packet.read(@packet_length - padding_length - 1)
|
213
|
+
padding = @packet.read(padding_length) if padding_length > 0
|
214
|
+
|
215
|
+
my_computed_hmac = server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
|
216
|
+
raise Net::SSH::Exception, "corrupted mac detected" if real_hmac != my_computed_hmac
|
217
|
+
|
218
|
+
# try to decompress the payload, in case compression is active
|
219
|
+
payload = server.decompress(payload)
|
220
|
+
|
221
|
+
debug { "received packet nr #{server.sequence_number} type #{payload[0]} len #{@packet_length}" }
|
222
|
+
|
223
|
+
server.increment(@packet_length)
|
224
|
+
@packet = nil
|
225
|
+
|
226
|
+
return Packet.new(payload)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end; end; end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'net/ssh/errors'
|
2
|
+
require 'net/ssh/loggable'
|
3
|
+
require 'net/ssh/version'
|
4
|
+
|
5
|
+
module Net; module SSH; module Transport
|
6
|
+
|
7
|
+
# Negotiates the SSH protocol version and trades information about server
|
8
|
+
# and client. This is never used directly--it is always called by the
|
9
|
+
# transport layer as part of the initialization process of the transport
|
10
|
+
# layer.
|
11
|
+
#
|
12
|
+
# Note that this class also encapsulates the negotiated version, and acts as
|
13
|
+
# the authoritative reference for any queries regarding the version in effect.
|
14
|
+
class ServerVersion
|
15
|
+
include Loggable
|
16
|
+
|
17
|
+
# The SSH version string as reported by Net::SSH
|
18
|
+
PROTO_VERSION = "SSH-2.0-Ruby/Net::SSH_#{Net::SSH::Version::CURRENT} #{RUBY_PLATFORM}"
|
19
|
+
|
20
|
+
# Any header text sent by the server prior to sending the version.
|
21
|
+
attr_reader :header
|
22
|
+
|
23
|
+
# The version string reported by the server.
|
24
|
+
attr_reader :version
|
25
|
+
|
26
|
+
# Instantiates a new ServerVersion and immediately (and synchronously)
|
27
|
+
# negotiates the SSH protocol in effect, using the given socket.
|
28
|
+
def initialize(socket, logger)
|
29
|
+
@header = ""
|
30
|
+
@version = nil
|
31
|
+
@logger = logger
|
32
|
+
negotiate!(socket)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Negotiates the SSH protocol to use, via the given socket. If the server
|
38
|
+
# reports an incompatible SSH version (e.g., SSH1), this will raise an
|
39
|
+
# exception.
|
40
|
+
def negotiate!(socket)
|
41
|
+
info { "negotiating protocol version" }
|
42
|
+
|
43
|
+
loop do
|
44
|
+
@version = socket.readline
|
45
|
+
break if @version.nil? || @version.match(/^SSH-/)
|
46
|
+
@header << @version
|
47
|
+
end
|
48
|
+
|
49
|
+
debug { "remote is #{@version.strip}" }
|
50
|
+
|
51
|
+
unless @version.match(/^SSH-(1\.99|2\.0)-/)
|
52
|
+
raise Net::SSH::Exception, "incompatible SSH version `#{@version}'"
|
53
|
+
end
|
54
|
+
|
55
|
+
@version.strip!
|
56
|
+
|
57
|
+
debug { "local is #{PROTO_VERSION}" }
|
58
|
+
socket.write "#{PROTO_VERSION}\r\n"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end; end; end
|