sonixlabs-net-ssh 2.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.
- data/CHANGELOG.rdoc +262 -0
- data/Manifest +121 -0
- data/README.rdoc +184 -0
- data/Rakefile +86 -0
- data/Rudyfile +96 -0
- data/THANKS.rdoc +19 -0
- data/lib/net/ssh.rb +223 -0
- data/lib/net/ssh/authentication/agent.rb +179 -0
- data/lib/net/ssh/authentication/constants.rb +18 -0
- data/lib/net/ssh/authentication/key_manager.rb +253 -0
- data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
- data/lib/net/ssh/authentication/methods/hostbased.rb +75 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +70 -0
- data/lib/net/ssh/authentication/methods/password.rb +43 -0
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -0
- data/lib/net/ssh/authentication/pageant.rb +264 -0
- data/lib/net/ssh/authentication/session.rb +146 -0
- data/lib/net/ssh/buffer.rb +340 -0
- data/lib/net/ssh/buffered_io.rb +198 -0
- data/lib/net/ssh/config.rb +207 -0
- data/lib/net/ssh/connection/channel.rb +630 -0
- data/lib/net/ssh/connection/constants.rb +33 -0
- data/lib/net/ssh/connection/session.rb +597 -0
- data/lib/net/ssh/connection/term.rb +178 -0
- data/lib/net/ssh/errors.rb +88 -0
- data/lib/net/ssh/key_factory.rb +102 -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/command.rb +75 -0
- data/lib/net/ssh/proxy/errors.rb +14 -0
- data/lib/net/ssh/proxy/http.rb +94 -0
- data/lib/net/ssh/proxy/socks4.rb +70 -0
- data/lib/net/ssh/proxy/socks5.rb +142 -0
- data/lib/net/ssh/ruby_compat.rb +43 -0
- data/lib/net/ssh/service/forward.rb +298 -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 +64 -0
- data/lib/net/ssh/transport/algorithms.rb +386 -0
- data/lib/net/ssh/transport/cipher_factory.rb +79 -0
- data/lib/net/ssh/transport/constants.rb +30 -0
- data/lib/net/ssh/transport/hmac.rb +42 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +79 -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/hmac/sha2_256.rb +15 -0
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +13 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +14 -0
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +13 -0
- data/lib/net/ssh/transport/identity_cipher.rb +55 -0
- data/lib/net/ssh/transport/kex.rb +17 -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 +80 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +15 -0
- data/lib/net/ssh/transport/key_expander.rb +26 -0
- data/lib/net/ssh/transport/openssl.rb +127 -0
- data/lib/net/ssh/transport/packet_stream.rb +235 -0
- data/lib/net/ssh/transport/server_version.rb +71 -0
- data/lib/net/ssh/transport/session.rb +278 -0
- data/lib/net/ssh/transport/state.rb +206 -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 +62 -0
- data/lib/sonixlabs-net-ssh.rb +1 -0
- data/net-ssh.gemspec +145 -0
- data/setup.rb +1585 -0
- data/support/arcfour_check.rb +20 -0
- data/support/ssh_tunnel_bug.rb +65 -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 +114 -0
- data/test/authentication/methods/test_keyboard_interactive.rb +100 -0
- data/test/authentication/methods/test_password.rb +52 -0
- data/test/authentication/methods/test_publickey.rb +148 -0
- data/test/authentication/test_agent.rb +205 -0
- data/test/authentication/test_key_manager.rb +171 -0
- data/test/authentication/test_session.rb +106 -0
- data/test/common.rb +107 -0
- data/test/configs/eqsign +3 -0
- data/test/configs/exact_match +8 -0
- data/test/configs/host_plus +10 -0
- data/test/configs/multihost +4 -0
- data/test/configs/wild_cards +14 -0
- data/test/connection/test_channel.rb +467 -0
- data/test/connection/test_session.rb +488 -0
- data/test/test_all.rb +9 -0
- data/test/test_buffer.rb +336 -0
- data/test/test_buffered_io.rb +63 -0
- data/test/test_config.rb +120 -0
- data/test/test_key_factory.rb +79 -0
- data/test/transport/hmac/test_md5.rb +39 -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/hmac/test_sha2_256.rb +35 -0
- data/test/transport/hmac/test_sha2_256_96.rb +25 -0
- data/test/transport/hmac/test_sha2_512.rb +35 -0
- data/test/transport/hmac/test_sha2_512_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/kex/test_diffie_hellman_group_exchange_sha256.rb +33 -0
- data/test/transport/test_algorithms.rb +308 -0
- data/test/transport/test_cipher_factory.rb +213 -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 +736 -0
- data/test/transport/test_server_version.rb +78 -0
- data/test/transport/test_session.rb +315 -0
- data/test/transport/test_state.rb +179 -0
- metadata +178 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
require 'net/ssh/buffer'
|
|
2
|
+
require 'net/ssh/errors'
|
|
3
|
+
require 'net/ssh/loggable'
|
|
4
|
+
require 'net/ssh/transport/openssl'
|
|
5
|
+
require 'net/ssh/transport/constants'
|
|
6
|
+
|
|
7
|
+
module Net; module SSH; module Transport; module Kex
|
|
8
|
+
|
|
9
|
+
# A key-exchange service implementing the "diffie-hellman-group1-sha1"
|
|
10
|
+
# key-exchange algorithm.
|
|
11
|
+
class DiffieHellmanGroup1SHA1
|
|
12
|
+
include Constants, Loggable
|
|
13
|
+
|
|
14
|
+
# The value of 'P', as a string, in hexadecimal
|
|
15
|
+
P_s = "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" +
|
|
16
|
+
"C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" +
|
|
17
|
+
"020BBEA6" "3B139B22" "514A0879" "8E3404DD" +
|
|
18
|
+
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" +
|
|
19
|
+
"4FE1356D" "6D51C245" "E485B576" "625E7EC6" +
|
|
20
|
+
"F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" +
|
|
21
|
+
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" +
|
|
22
|
+
"49286651" "ECE65381" "FFFFFFFF" "FFFFFFFF"
|
|
23
|
+
|
|
24
|
+
# The radix in which P_s represents the value of P
|
|
25
|
+
P_r = 16
|
|
26
|
+
|
|
27
|
+
# The group constant
|
|
28
|
+
G = 2
|
|
29
|
+
|
|
30
|
+
attr_reader :p
|
|
31
|
+
attr_reader :g
|
|
32
|
+
attr_reader :digester
|
|
33
|
+
attr_reader :algorithms
|
|
34
|
+
attr_reader :connection
|
|
35
|
+
attr_reader :data
|
|
36
|
+
attr_reader :dh
|
|
37
|
+
|
|
38
|
+
# Create a new instance of the DiffieHellmanGroup1SHA1 algorithm.
|
|
39
|
+
# The data is a Hash of symbols representing information
|
|
40
|
+
# required by this algorithm, which was acquired during earlier
|
|
41
|
+
# processing.
|
|
42
|
+
def initialize(algorithms, connection, data)
|
|
43
|
+
@p = OpenSSL::BN.new(P_s, P_r)
|
|
44
|
+
@g = G
|
|
45
|
+
|
|
46
|
+
@digester = OpenSSL::Digest::SHA1
|
|
47
|
+
@algorithms = algorithms
|
|
48
|
+
@connection = connection
|
|
49
|
+
|
|
50
|
+
@data = data.dup
|
|
51
|
+
@dh = generate_key
|
|
52
|
+
@logger = @data.delete(:logger)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Perform the key-exchange for the given session, with the given
|
|
56
|
+
# data. This method will return a hash consisting of the
|
|
57
|
+
# following keys:
|
|
58
|
+
#
|
|
59
|
+
# * :session_id
|
|
60
|
+
# * :server_key
|
|
61
|
+
# * :shared_secret
|
|
62
|
+
# * :hashing_algorithm
|
|
63
|
+
#
|
|
64
|
+
# The caller is expected to be able to understand how to use these
|
|
65
|
+
# deliverables.
|
|
66
|
+
def exchange_keys
|
|
67
|
+
result = send_kexinit
|
|
68
|
+
verify_server_key(result[:server_key])
|
|
69
|
+
session_id = verify_signature(result)
|
|
70
|
+
confirm_newkeys
|
|
71
|
+
|
|
72
|
+
return { :session_id => session_id,
|
|
73
|
+
:server_key => result[:server_key],
|
|
74
|
+
:shared_secret => result[:shared_secret],
|
|
75
|
+
:hashing_algorithm => digester }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
# Returns the DH key parameters for the current connection.
|
|
81
|
+
def get_parameters
|
|
82
|
+
[p, g]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Returns the INIT/REPLY constants used by this algorithm.
|
|
86
|
+
def get_message_types
|
|
87
|
+
[KEXDH_INIT, KEXDH_REPLY]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Build the signature buffer to use when verifying a signature from
|
|
91
|
+
# the server.
|
|
92
|
+
def build_signature_buffer(result)
|
|
93
|
+
response = Net::SSH::Buffer.new
|
|
94
|
+
response.write_string data[:client_version_string],
|
|
95
|
+
data[:server_version_string],
|
|
96
|
+
data[:client_algorithm_packet],
|
|
97
|
+
data[:server_algorithm_packet],
|
|
98
|
+
result[:key_blob]
|
|
99
|
+
response.write_bignum dh.pub_key,
|
|
100
|
+
result[:server_dh_pubkey],
|
|
101
|
+
result[:shared_secret]
|
|
102
|
+
response
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Generate a DH key with a private key consisting of the given
|
|
106
|
+
# number of bytes.
|
|
107
|
+
def generate_key #:nodoc:
|
|
108
|
+
dh = OpenSSL::PKey::DH.new
|
|
109
|
+
|
|
110
|
+
dh.p, dh.g = get_parameters
|
|
111
|
+
dh.priv_key = OpenSSL::BN.rand(data[:need_bytes] * 8)
|
|
112
|
+
|
|
113
|
+
dh.generate_key! until dh.valid?
|
|
114
|
+
|
|
115
|
+
dh
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Send the KEXDH_INIT message, and expect the KEXDH_REPLY. Return the
|
|
119
|
+
# resulting buffer.
|
|
120
|
+
#
|
|
121
|
+
# Parse the buffer from a KEXDH_REPLY message, returning a hash of
|
|
122
|
+
# the extracted values.
|
|
123
|
+
def send_kexinit #:nodoc:
|
|
124
|
+
init, reply = get_message_types
|
|
125
|
+
|
|
126
|
+
# send the KEXDH_INIT message
|
|
127
|
+
buffer = Net::SSH::Buffer.from(:byte, init, :bignum, dh.pub_key)
|
|
128
|
+
connection.send_message(buffer)
|
|
129
|
+
|
|
130
|
+
# expect the KEXDH_REPLY message
|
|
131
|
+
buffer = connection.next_message
|
|
132
|
+
raise Net::SSH::Exception, "expected REPLY" unless buffer.type == reply
|
|
133
|
+
|
|
134
|
+
result = Hash.new
|
|
135
|
+
|
|
136
|
+
result[:key_blob] = buffer.read_string
|
|
137
|
+
result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
|
|
138
|
+
result[:server_dh_pubkey] = buffer.read_bignum
|
|
139
|
+
result[:shared_secret] = OpenSSL::BN.new(dh.compute_key(result[:server_dh_pubkey]), 2)
|
|
140
|
+
|
|
141
|
+
sig_buffer = Net::SSH::Buffer.new(buffer.read_string)
|
|
142
|
+
sig_type = sig_buffer.read_string
|
|
143
|
+
if sig_type != algorithms.host_key
|
|
144
|
+
raise Net::SSH::Exception,
|
|
145
|
+
"host key algorithm mismatch for signature " +
|
|
146
|
+
"'#{sig_type}' != '#{algorithms.host_key}'"
|
|
147
|
+
end
|
|
148
|
+
result[:server_sig] = sig_buffer.read_string
|
|
149
|
+
|
|
150
|
+
return result
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Verify that the given key is of the expected type, and that it
|
|
154
|
+
# really is the key for the session's host. Raise Net::SSH::Exception
|
|
155
|
+
# if it is not.
|
|
156
|
+
def verify_server_key(key) #:nodoc:
|
|
157
|
+
if key.ssh_type != algorithms.host_key
|
|
158
|
+
raise Net::SSH::Exception,
|
|
159
|
+
"host key algorithm mismatch " +
|
|
160
|
+
"'#{key.ssh_type}' != '#{algorithms.host_key}'"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
blob, fingerprint = generate_key_fingerprint(key)
|
|
164
|
+
|
|
165
|
+
unless connection.host_key_verifier.verify(:key => key, :key_blob => blob, :fingerprint => fingerprint, :session => connection)
|
|
166
|
+
raise Net::SSH::Exception, "host key verification failed"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def generate_key_fingerprint(key)
|
|
171
|
+
blob = Net::SSH::Buffer.from(:key, key).to_s
|
|
172
|
+
fingerprint = OpenSSL::Digest::MD5.hexdigest(blob).scan(/../).join(":")
|
|
173
|
+
|
|
174
|
+
[blob, fingerprint]
|
|
175
|
+
rescue ::Exception => e
|
|
176
|
+
[nil, "(could not generate fingerprint: #{e.message})"]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Verify the signature that was received. Raise Net::SSH::Exception
|
|
180
|
+
# if the signature could not be verified. Otherwise, return the new
|
|
181
|
+
# session-id.
|
|
182
|
+
def verify_signature(result) #:nodoc:
|
|
183
|
+
response = build_signature_buffer(result)
|
|
184
|
+
|
|
185
|
+
hash = @digester.digest(response.to_s)
|
|
186
|
+
|
|
187
|
+
unless result[:server_key].ssh_do_verify(result[:server_sig], hash)
|
|
188
|
+
raise Net::SSH::Exception, "could not verify server signature"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
return hash
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Send the NEWKEYS message, and expect the NEWKEYS message in
|
|
195
|
+
# reply.
|
|
196
|
+
def confirm_newkeys #:nodoc:
|
|
197
|
+
# send own NEWKEYS message first (the wodSSHServer won't send first)
|
|
198
|
+
response = Net::SSH::Buffer.new
|
|
199
|
+
response.write_byte(NEWKEYS)
|
|
200
|
+
connection.send_message(response)
|
|
201
|
+
|
|
202
|
+
# wait for the server's NEWKEYS message
|
|
203
|
+
buffer = connection.next_message
|
|
204
|
+
raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
end; end; end; end
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
|
|
23
|
+
# for Compatibility: OpenSSH requires (need_bits * 2 + 1) length of parameter
|
|
24
|
+
need_bits = data[:need_bytes] * 8 * 2 + 1
|
|
25
|
+
|
|
26
|
+
if need_bits < MINIMUM_BITS
|
|
27
|
+
need_bits = MINIMUM_BITS
|
|
28
|
+
elsif need_bits > MAXIMUM_BITS
|
|
29
|
+
need_bits = MAXIMUM_BITS
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
data[:need_bits ] = need_bits
|
|
33
|
+
data[:need_bytes] = need_bits / 8
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns the DH key parameters for the given session.
|
|
37
|
+
def get_parameters
|
|
38
|
+
compute_need_bits
|
|
39
|
+
|
|
40
|
+
# request the DH key parameters for the given number of bits.
|
|
41
|
+
buffer = Net::SSH::Buffer.from(:byte, KEXDH_GEX_REQUEST, :long, MINIMUM_BITS,
|
|
42
|
+
:long, data[:need_bits], :long, MAXIMUM_BITS)
|
|
43
|
+
connection.send_message(buffer)
|
|
44
|
+
|
|
45
|
+
buffer = connection.next_message
|
|
46
|
+
unless buffer.type == KEXDH_GEX_GROUP
|
|
47
|
+
raise Net::SSH::Exception, "expected KEXDH_GEX_GROUP, got #{buffer.type}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
p = buffer.read_bignum
|
|
51
|
+
g = buffer.read_bignum
|
|
52
|
+
|
|
53
|
+
[p, g]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Returns the INIT/REPLY constants used by this algorithm.
|
|
57
|
+
def get_message_types
|
|
58
|
+
[KEXDH_GEX_INIT, KEXDH_GEX_REPLY]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Build the signature buffer to use when verifying a signature from
|
|
62
|
+
# the server.
|
|
63
|
+
def build_signature_buffer(result)
|
|
64
|
+
response = Net::SSH::Buffer.new
|
|
65
|
+
response.write_string data[:client_version_string],
|
|
66
|
+
data[:server_version_string],
|
|
67
|
+
data[:client_algorithm_packet],
|
|
68
|
+
data[:server_algorithm_packet],
|
|
69
|
+
result[:key_blob]
|
|
70
|
+
response.write_long MINIMUM_BITS,
|
|
71
|
+
data[:need_bits],
|
|
72
|
+
MAXIMUM_BITS
|
|
73
|
+
response.write_bignum dh.p, dh.g, dh.pub_key,
|
|
74
|
+
result[:server_dh_pubkey],
|
|
75
|
+
result[:shared_secret]
|
|
76
|
+
response
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
|
|
2
|
+
|
|
3
|
+
module Net::SSH::Transport::Kex
|
|
4
|
+
if defined?(OpenSSL::Digest::SHA256)
|
|
5
|
+
# A key-exchange service implementing the
|
|
6
|
+
# "diffie-hellman-group-exchange-sha256" key-exchange algorithm.
|
|
7
|
+
class DiffieHellmanGroupExchangeSHA256 < DiffieHellmanGroupExchangeSHA1
|
|
8
|
+
def initialize(*args)
|
|
9
|
+
super(*args)
|
|
10
|
+
|
|
11
|
+
@digester = OpenSSL::Digest::SHA256
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Net; module SSH; module Transport
|
|
2
|
+
module KeyExpander
|
|
3
|
+
|
|
4
|
+
# Generate a key value in accordance with the SSH2 specification.
|
|
5
|
+
# (RFC4253 7.2. "Output from Key Exchange")
|
|
6
|
+
def self.expand_key(bytes, start, options={})
|
|
7
|
+
if bytes == 0
|
|
8
|
+
return ""
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
k = start[0, bytes]
|
|
12
|
+
|
|
13
|
+
digester = options[:digester] or raise 'No digester supplied'
|
|
14
|
+
shared = options[:shared] or raise 'No shared secret supplied'
|
|
15
|
+
hash = options[:hash] or raise 'No hash supplied'
|
|
16
|
+
|
|
17
|
+
while k.length < bytes
|
|
18
|
+
step = digester.digest(shared + hash + k)
|
|
19
|
+
bytes_needed = bytes - k.length
|
|
20
|
+
k << step[0, bytes_needed]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
return k
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end; end; end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
|
|
3
|
+
module OpenSSL
|
|
4
|
+
|
|
5
|
+
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
6
|
+
# have been added to it by the Net::SSH module for convenience in dealing with
|
|
7
|
+
# SSH functionality.
|
|
8
|
+
class BN
|
|
9
|
+
|
|
10
|
+
# Converts a BN object to a string. The format used is that which is
|
|
11
|
+
# required by the SSH2 protocol.
|
|
12
|
+
def to_ssh
|
|
13
|
+
if zero?
|
|
14
|
+
return [0].pack("N")
|
|
15
|
+
else
|
|
16
|
+
buf = to_s(2)
|
|
17
|
+
if buf.getbyte(0)[7] == 1
|
|
18
|
+
return [buf.length+1, 0, buf].pack("NCA*")
|
|
19
|
+
else
|
|
20
|
+
return [buf.length, buf].pack("NA*")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module PKey
|
|
28
|
+
|
|
29
|
+
class PKey
|
|
30
|
+
def fingerprint
|
|
31
|
+
@fingerprint ||= OpenSSL::Digest::MD5.hexdigest(to_blob).scan(/../).join(":")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
36
|
+
# have been added to it by the Net::SSH module for convenience in dealing
|
|
37
|
+
# with SSH functionality.
|
|
38
|
+
class DH
|
|
39
|
+
|
|
40
|
+
# Determines whether the pub_key for this key is valid. (This algorithm
|
|
41
|
+
# lifted more-or-less directly from OpenSSH, dh.c, dh_pub_is_valid.)
|
|
42
|
+
def valid?
|
|
43
|
+
return false if pub_key.nil? || pub_key < 0
|
|
44
|
+
bits_set = 0
|
|
45
|
+
pub_key.num_bits.times { |i| bits_set += 1 if pub_key.bit_set?(i) }
|
|
46
|
+
return ( bits_set > 1 && pub_key < p )
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
52
|
+
# have been added to it by the Net::SSH module for convenience in dealing
|
|
53
|
+
# with SSH functionality.
|
|
54
|
+
class RSA
|
|
55
|
+
|
|
56
|
+
# Returns "ssh-rsa", which is the description of this key type used by the
|
|
57
|
+
# SSH2 protocol.
|
|
58
|
+
def ssh_type
|
|
59
|
+
"ssh-rsa"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Converts the key to a blob, according to the SSH2 protocol.
|
|
63
|
+
def to_blob
|
|
64
|
+
@blob ||= Net::SSH::Buffer.from(:string, ssh_type, :bignum, e, :bignum, n).to_s
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Verifies the given signature matches the given data.
|
|
68
|
+
def ssh_do_verify(sig, data)
|
|
69
|
+
verify(OpenSSL::Digest::SHA1.new, sig, data)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns the signature for the given data.
|
|
73
|
+
def ssh_do_sign(data)
|
|
74
|
+
sign(OpenSSL::Digest::SHA1.new, data)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# This class is originally defined in the OpenSSL module. As needed, methods
|
|
79
|
+
# have been added to it by the Net::SSH module for convenience in dealing
|
|
80
|
+
# with SSH functionality.
|
|
81
|
+
class DSA
|
|
82
|
+
|
|
83
|
+
# Returns "ssh-dss", which is the description of this key type used by the
|
|
84
|
+
# SSH2 protocol.
|
|
85
|
+
def ssh_type
|
|
86
|
+
"ssh-dss"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Converts the key to a blob, according to the SSH2 protocol.
|
|
90
|
+
def to_blob
|
|
91
|
+
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
|
92
|
+
:bignum, p, :bignum, q, :bignum, g, :bignum, pub_key).to_s
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Verifies the given signature matches the given data.
|
|
96
|
+
def ssh_do_verify(sig, data)
|
|
97
|
+
sig_r = sig[0,20].unpack("H*")[0].to_i(16)
|
|
98
|
+
sig_s = sig[20,20].unpack("H*")[0].to_i(16)
|
|
99
|
+
a1sig = OpenSSL::ASN1::Sequence([
|
|
100
|
+
OpenSSL::ASN1::Integer(sig_r),
|
|
101
|
+
OpenSSL::ASN1::Integer(sig_s)
|
|
102
|
+
])
|
|
103
|
+
return verify(OpenSSL::Digest::DSS1.new, a1sig.to_der, data)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Signs the given data.
|
|
107
|
+
def ssh_do_sign(data)
|
|
108
|
+
sig = sign( OpenSSL::Digest::DSS1.new, data)
|
|
109
|
+
a1sig = OpenSSL::ASN1.decode( sig )
|
|
110
|
+
|
|
111
|
+
sig_r = a1sig.value[0].value.to_s(2)
|
|
112
|
+
sig_s = a1sig.value[1].value.to_s(2)
|
|
113
|
+
|
|
114
|
+
if sig_r.length > 20 || sig_s.length > 20
|
|
115
|
+
raise OpenSSL::PKey::DSAError, "bad sig size"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
sig_r = "\0" * ( 20 - sig_r.length ) + sig_r if sig_r.length < 20
|
|
119
|
+
sig_s = "\0" * ( 20 - sig_s.length ) + sig_s if sig_s.length < 20
|
|
120
|
+
|
|
121
|
+
return sig_r + sig_s
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|