putty-key 1.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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +1 -0
- data/.yardopts +7 -0
- data/CHANGES.md +4 -0
- data/Gemfile +14 -0
- data/LICENSE +19 -0
- data/README.md +137 -0
- data/Rakefile +110 -0
- data/lib/putty/key.rb +25 -0
- data/lib/putty/key/error.rb +26 -0
- data/lib/putty/key/openssl.rb +182 -0
- data/lib/putty/key/ppk.rb +374 -0
- data/lib/putty/key/util.rb +128 -0
- data/lib/putty/key/version.rb +6 -0
- data/putty-key.gemspec +29 -0
- data/test/fixtures/dss-1024-encrypted.ppk +17 -0
- data/test/fixtures/dss-1024.pem +12 -0
- data/test/fixtures/dss-1024.ppk +17 -0
- data/test/fixtures/ecdsa-secp256k1.pem +5 -0
- data/test/fixtures/ecdsa-sha2-nistp256-encrypted.ppk +10 -0
- data/test/fixtures/ecdsa-sha2-nistp256.pem +5 -0
- data/test/fixtures/ecdsa-sha2-nistp256.ppk +10 -0
- data/test/fixtures/ecdsa-sha2-nistp384-encrypted.ppk +11 -0
- data/test/fixtures/ecdsa-sha2-nistp384.pem +6 -0
- data/test/fixtures/ecdsa-sha2-nistp384.ppk +11 -0
- data/test/fixtures/ecdsa-sha2-nistp521-encrypted.ppk +12 -0
- data/test/fixtures/ecdsa-sha2-nistp521.pem +7 -0
- data/test/fixtures/ecdsa-sha2-nistp521.ppk +12 -0
- data/test/fixtures/rsa-2048-encrypted.ppk +26 -0
- data/test/fixtures/rsa-2048.pem +27 -0
- data/test/fixtures/rsa-2048.ppk +26 -0
- data/test/fixtures/test-blank-comment.ppk +11 -0
- data/test/fixtures/test-encrypted.ppk +11 -0
- data/test/fixtures/test-invalid-blob-lines.ppk +11 -0
- data/test/fixtures/test-invalid-encryption-type.ppk +11 -0
- data/test/fixtures/test-invalid-format-1.ppk +11 -0
- data/test/fixtures/test-invalid-format-3.ppk +11 -0
- data/test/fixtures/test-invalid-private-mac.ppk +11 -0
- data/test/fixtures/test-truncated.ppk +10 -0
- data/test/fixtures/test-unix-line-endings.ppk +11 -0
- data/test/fixtures/test.ppk +11 -0
- data/test/openssl_test.rb +252 -0
- data/test/ppk_test.rb +247 -0
- data/test/test_helper.rb +81 -0
- data/test/util_test.rb +180 -0
- data/test/version_test.rb +7 -0
- metadata +124 -0
- metadata.gz.sig +0 -0
data/test/ppk_test.rb
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
class PPKTest < Minitest::Test
|
5
|
+
TEST_COMMENT = 'This is a test ppk file'.b
|
6
|
+
TEST_PUBLIC_BLOB = "\x00\x00\x00\x04test\x00\x00\x00\x4AThis is the public blob from a ppk file created for testing purposes only.".b
|
7
|
+
TEST_PRIVATE_BLOB = "\x00\x00\x00\x77This is the private blob from a ppk file created for testing purposes only. It is slightly longer than the public blob.".b
|
8
|
+
|
9
|
+
def test_initialize
|
10
|
+
ppk = PuTTY::Key::PPK.new
|
11
|
+
assert_nil(ppk.algorithm)
|
12
|
+
assert_nil(ppk.comment)
|
13
|
+
assert_nil(ppk.public_blob)
|
14
|
+
assert_nil(ppk.private_blob)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_initialize_invalid_format
|
18
|
+
[1,3].each do |format|
|
19
|
+
assert_raises(PuTTY::Key::FormatError) { PuTTY::Key::PPK.new(fixture_path("test-invalid-format-#{format}.ppk")) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_initialize_invalid_encryption_type
|
24
|
+
assert_raises(PuTTY::Key::FormatError) { PuTTY::Key::PPK.new(fixture_path('test-invalid-encryption-type.ppk')) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_initialize_invalid_private_mac
|
28
|
+
assert_raises(PuTTY::Key::FormatError) { PuTTY::Key::PPK.new(fixture_path('test-invalid-private-mac.ppk')) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_initialize_file_not_exists
|
32
|
+
temp_dir do |dir|
|
33
|
+
assert_raises(Errno::ENOENT) { PuTTY::Key::PPK.new(File.join(dir, 'missing')) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_initialize_non_ppk
|
38
|
+
assert_raises(PuTTY::Key::FormatError) { PuTTY::Key::PPK.new(fixture_path('rsa-2048.pem')) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_initialize_truncated
|
42
|
+
assert_raises(PuTTY::Key::FormatError) { PuTTY::Key::PPK.new(fixture_path('test-truncated.ppk')) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_initialize_invalid_blob_lines
|
46
|
+
assert_raises(PuTTY::Key::FormatError) { PuTTY::Key::PPK.new(fixture_path('test-invalid-blob-lines.ppk')) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def assert_test_ppk_properties(ppk, comment: TEST_COMMENT, encrypted: false)
|
50
|
+
assert_equal(Encoding::ASCII_8BIT, ppk.algorithm.encoding)
|
51
|
+
assert_equal(Encoding::ASCII_8BIT, ppk.comment.encoding)
|
52
|
+
assert_equal(Encoding::ASCII_8BIT, ppk.public_blob.encoding)
|
53
|
+
assert_equal(Encoding::ASCII_8BIT, ppk.private_blob.encoding)
|
54
|
+
assert_equal('test'.b, ppk.algorithm)
|
55
|
+
assert_equal(comment, ppk.comment)
|
56
|
+
assert_equal(TEST_PUBLIC_BLOB, ppk.public_blob)
|
57
|
+
|
58
|
+
if encrypted
|
59
|
+
# When loading an encrypted ppk file, the padding added to the private blob cannot be removed.
|
60
|
+
assert(ppk.private_blob.start_with?(TEST_PRIVATE_BLOB), "Private blob does not start with #{TEST_PRIVATE_BLOB}")
|
61
|
+
else
|
62
|
+
assert_equal(TEST_PRIVATE_BLOB, ppk.private_blob)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_initialize_unencrypted
|
67
|
+
ppk = PuTTY::Key::PPK.new(fixture_path('test.ppk'))
|
68
|
+
assert_test_ppk_properties(ppk)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_initialize_blank_comment
|
72
|
+
ppk = PuTTY::Key::PPK.new(fixture_path('test-blank-comment.ppk'))
|
73
|
+
assert_test_ppk_properties(ppk, comment: ''.b)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_initialize_encrypted
|
77
|
+
ppk = PuTTY::Key::PPK.new(fixture_path('test-encrypted.ppk'), 'Test Passphrase')
|
78
|
+
assert_test_ppk_properties(ppk, encrypted: true)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_initialize_encrypted_no_passphrase
|
82
|
+
assert_raises(ArgumentError) { PuTTY::Key::PPK.new(fixture_path('test-encrypted.ppk')) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_initialize_encrypted_incorrect_passphrase
|
86
|
+
assert_raises(ArgumentError) { PuTTY::Key::PPK.new(fixture_path('test-encrypted.ppk'), 'Not Test Passphrase') }
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_initialize_pathname
|
90
|
+
ppk = PuTTY::Key::PPK.new(Pathname.new(fixture_path('test.ppk')))
|
91
|
+
assert_test_ppk_properties(ppk)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_initialize_unix_line_endings
|
95
|
+
ppk = PuTTY::Key::PPK.new(fixture_path('test-unix-line-endings.ppk'))
|
96
|
+
assert_test_ppk_properties(ppk)
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_test_ppk
|
100
|
+
PuTTY::Key::PPK.new.tap do |ppk|
|
101
|
+
ppk.algorithm = 'test'
|
102
|
+
ppk.comment = TEST_COMMENT
|
103
|
+
ppk.public_blob = TEST_PUBLIC_BLOB
|
104
|
+
ppk.private_blob = TEST_PRIVATE_BLOB
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_save_path_nil
|
109
|
+
ppk = create_test_ppk
|
110
|
+
assert_raises(ArgumentError) { ppk.save(nil) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_save_passphrase_encryption_type_nil
|
114
|
+
ppk = create_test_ppk
|
115
|
+
temp_file_name do |file|
|
116
|
+
assert_raises(ArgumentError) { ppk.save(file, 'Test Passphrase', encryption_type: nil) }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_save_passphrase_encryption_type_none
|
121
|
+
ppk = create_test_ppk
|
122
|
+
temp_file_name do |file|
|
123
|
+
assert_raises(ArgumentError) { ppk.save(file, 'Test Passphrase', encryption_type: 'none') }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_save_passphrase_unsupported_encryption_type
|
128
|
+
ppk = create_test_ppk
|
129
|
+
temp_file_name do |file|
|
130
|
+
assert_raises(ArgumentError) { ppk.save(file, 'Test Passphrase', encryption_type: 'camellia256-cbc') }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_save_format_nil
|
135
|
+
ppk = create_test_ppk
|
136
|
+
temp_file_name do |file|
|
137
|
+
assert_raises(ArgumentError) { ppk.save(file, 'Test Passphrase', format: nil) }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_save_format_not_supported
|
142
|
+
ppk = create_test_ppk
|
143
|
+
temp_file_name do |file|
|
144
|
+
[1,3].each do |format|
|
145
|
+
assert_raises(ArgumentError) { ppk.save(file, 'Test Passphrase', format: format) }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_save_dir_not_exists
|
151
|
+
ppk = create_test_ppk
|
152
|
+
temp_dir do |dir|
|
153
|
+
assert_raises(Errno::ENOENT) { ppk.save(File.join(dir, 'missing', 'file')) }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_save_algorithm_nil
|
158
|
+
ppk = create_test_ppk
|
159
|
+
ppk.algorithm = nil
|
160
|
+
temp_file_name do |file|
|
161
|
+
assert_raises(PuTTY::Key::InvalidStateError) { ppk.save(file) }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_save_public_blob_nil
|
166
|
+
ppk = create_test_ppk
|
167
|
+
ppk.public_blob = nil
|
168
|
+
temp_file_name do |file|
|
169
|
+
assert_raises(PuTTY::Key::InvalidStateError) { ppk.save(file) }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_save_private_blob_nil
|
174
|
+
ppk = create_test_ppk
|
175
|
+
ppk.private_blob = nil
|
176
|
+
temp_file_name do |file|
|
177
|
+
assert_raises(PuTTY::Key::InvalidStateError) { ppk.save(file) }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_save_unencrypted
|
182
|
+
ppk = create_test_ppk
|
183
|
+
temp_file_name do |file|
|
184
|
+
ppk.save(file)
|
185
|
+
assert_identical_to_fixture('test.ppk', file)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_save_passphrase_empty
|
190
|
+
ppk = create_test_ppk
|
191
|
+
temp_file_name do |file|
|
192
|
+
ppk.save(file, '')
|
193
|
+
assert_identical_to_fixture('test.ppk', file)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_save_encrypted
|
198
|
+
ppk = create_test_ppk
|
199
|
+
temp_file_name do |file|
|
200
|
+
ppk.save(file, 'Test Passphrase')
|
201
|
+
assert_identical_to_fixture('test-encrypted.ppk', file)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_save_comment_empty
|
206
|
+
ppk = create_test_ppk
|
207
|
+
ppk.comment = ''
|
208
|
+
temp_file_name do |file|
|
209
|
+
ppk.save(file)
|
210
|
+
assert_identical_to_fixture('test-blank-comment.ppk', file)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_save_comment_nil
|
215
|
+
ppk = create_test_ppk
|
216
|
+
ppk.comment = nil
|
217
|
+
temp_file_name do |file|
|
218
|
+
ppk.save(file)
|
219
|
+
assert_identical_to_fixture('test-blank-comment.ppk', file)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_save_pathname
|
224
|
+
ppk = create_test_ppk
|
225
|
+
temp_file_name do |file|
|
226
|
+
ppk.save(Pathname.new(file))
|
227
|
+
assert_identical_to_fixture('test.ppk', file)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_save_overwrite
|
232
|
+
ppk = create_test_ppk
|
233
|
+
temp_file_name do |file|
|
234
|
+
File.open(file, 'w') { |f| f.write('not test.ppk') }
|
235
|
+
ppk.save(file)
|
236
|
+
assert_identical_to_fixture('test.ppk', file)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_save_result
|
241
|
+
ppk = create_test_ppk
|
242
|
+
temp_file_name do |file|
|
243
|
+
result = ppk.save(file)
|
244
|
+
assert_equal(File.size(file), result)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
TEST_TYPE = (ENV['TEST_TYPE'] || 'refinement').to_sym
|
2
|
+
raise "Unrecognized TEST_TYPE: #{TEST_TYPE}" unless [:refinement, :global].include?(TEST_TYPE)
|
3
|
+
|
4
|
+
TEST_COVERAGE = ENV['TEST_COVERAGE'] != '0'
|
5
|
+
|
6
|
+
if TEST_COVERAGE
|
7
|
+
require 'simplecov'
|
8
|
+
require 'coveralls'
|
9
|
+
|
10
|
+
SimpleCov.command_name TEST_TYPE.to_s
|
11
|
+
|
12
|
+
SimpleCov.formatters = [
|
13
|
+
SimpleCov::Formatter::HTMLFormatter
|
14
|
+
]
|
15
|
+
|
16
|
+
SimpleCov.start do
|
17
|
+
add_filter 'test'
|
18
|
+
project_name 'PuTTY::Key'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'putty/key'
|
23
|
+
|
24
|
+
require 'fileutils'
|
25
|
+
require 'minitest/autorun'
|
26
|
+
require 'tmpdir'
|
27
|
+
|
28
|
+
PuTTY::Key.global_install if TEST_TYPE == :global
|
29
|
+
|
30
|
+
module TestHelper
|
31
|
+
BASE_DIR = File.expand_path(File.dirname(__FILE__))
|
32
|
+
|
33
|
+
module Assertions
|
34
|
+
def assert_files_identical(exp, act, msg = nil)
|
35
|
+
msg = message(msg) { "Expected file #{act} to be identical to #{exp}\n\n#{act}:\n#{File.read(act)}\n\n#{exp}:\n#{File.read(exp)}\n" }
|
36
|
+
assert(FileUtils.identical?(exp, act), msg)
|
37
|
+
end
|
38
|
+
|
39
|
+
def assert_identical_to_fixture(exp_fixture, act_file, msg = nil)
|
40
|
+
assert_files_identical(fixture_path(exp_fixture), act_file, msg)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Fixtures
|
45
|
+
FIXTURES_DIR = File.join(BASE_DIR, 'fixtures')
|
46
|
+
|
47
|
+
def fixture_path(fixture)
|
48
|
+
File.join(FIXTURES_DIR, fixture)
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_fixture(fixture)
|
52
|
+
File.read(fixture_path(fixture), mode: 'rb')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Utils
|
57
|
+
def temp_dir(&block)
|
58
|
+
Dir.mktmpdir('putty-key', &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def temp_file_name(name = nil)
|
62
|
+
temp_dir do |dir|
|
63
|
+
file = File.join(dir, name || 'test')
|
64
|
+
yield file
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class ::OpenSSL::BN
|
70
|
+
# Override to_s so the represented value is visible.
|
71
|
+
def inspect
|
72
|
+
"#<OpenSSL::BN:#{to_s(16)}>"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Minitest::Test
|
78
|
+
include TestHelper::Assertions
|
79
|
+
include TestHelper::Fixtures
|
80
|
+
include TestHelper::Utils
|
81
|
+
end
|
data/test/util_test.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
# PuTTY::Key::NilValueError and PuTTY::Key::Util are private constants.
|
7
|
+
NilValueError = PuTTY::Key.const_get(:NilValueError)
|
8
|
+
Util = PuTTY::Key.const_get(:Util)
|
9
|
+
|
10
|
+
class PPKTest < Minitest::Test
|
11
|
+
def test_ssh_pack_empty
|
12
|
+
s = Util.ssh_pack
|
13
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
14
|
+
assert_equal("".b, s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_ssh_pack_nil_element
|
18
|
+
assert_raises(NilValueError) { Util.ssh_pack('test', nil, 'test2') }
|
19
|
+
end
|
20
|
+
|
21
|
+
def ssh_pack_string_empty
|
22
|
+
s = Util.ssh_pack('')
|
23
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
24
|
+
assert_equal("\x00\x00\x00\x00".b, s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_ssh_pack_string_utf8
|
28
|
+
s = Util.ssh_pack('This is UTF-8: ✓')
|
29
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
30
|
+
assert_equal("\x00\x00\x00\x12This is UTF-8: \xe2\x9c\x93".b, s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_ssh_pack_string_binary
|
34
|
+
s = Util.ssh_pack("\x00\x01\x02\x03\x04".b)
|
35
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
36
|
+
assert_equal("\x00\x00\x00\x05\x00\x01\x02\x03\x04".b, s)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_ssh_pack_bn
|
40
|
+
s = Util.ssh_pack(OpenSSL::BN.new(12345678901234567890))
|
41
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
42
|
+
assert_equal("\x00\x00\x00\x09\x00\xab\x54\xa9\x8c\xeb\x1f\x0a\xd2".b, s)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_ssh_pack_bn_postive_msb_unset
|
46
|
+
s = Util.ssh_pack(OpenSSL::BN.new(0x7f), OpenSSL::BN.new(0x7fff))
|
47
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
48
|
+
assert_equal("\x00\x00\x00\x01\x7f\x00\x00\x00\x02\x7f\xff".b, s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_ssh_pack_bn_postive_msb_set
|
52
|
+
s = Util.ssh_pack(OpenSSL::BN.new(0x80), OpenSSL::BN.new(0xff), OpenSSL::BN.new(0x8000), OpenSSL::BN.new(0xff00))
|
53
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
54
|
+
assert_equal("\x00\x00\x00\x02\x00\x80\x00\x00\x00\x02\x00\xff\x00\x00\x00\x03\x00\x80\x00\x00\x00\x00\x03\x00\xff\x00".b, s)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_ssh_pack_bn_negative
|
58
|
+
s = Util.ssh_pack(OpenSSL::BN.new(-0x01), OpenSSL::BN.new(-0x80), OpenSSL::BN.new(-0x81), OpenSSL::BN.new(-0x0100))
|
59
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
60
|
+
assert_equal("\x00\x00\x00\x01\xff\x00\x00\x00\x01\x80\x00\x00\x00\x02\xff\x7f\x00\x00\x00\x02\xff\x00".b, s)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_ssh_pack_bn_zero
|
64
|
+
s = Util.ssh_pack(OpenSSL::BN.new(0))
|
65
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
66
|
+
assert_equal("\x00\x00\x00\x00".b, s)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_ssh_pack_bn_rfc_4251_mpint_examples
|
70
|
+
s = Util.ssh_pack(OpenSSL::BN.new(0x0), OpenSSL::BN.new(0x9a378f9b2e332a7), OpenSSL::BN.new(0x80), OpenSSL::BN.new(-0x1234), OpenSSL::BN.new(-0xdeadbeef))
|
71
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
72
|
+
assert_equal("\x00\x00\x00\x00\x00\x00\x00\x08\x09\xa3\x78\xf9\xb2\xe3\x32\xa7\x00\x00\x00\x02\x00\x80\x00\x00\x00\x02\xed\xcc\x00\x00\x00\x05\xff\x21\x52\x41\x11".b, s)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_ssh_pack_mixed
|
76
|
+
s = Util.ssh_pack('string1', OpenSSL::BN.new(42), 'string2', OpenSSL::BN.new(1764))
|
77
|
+
assert_equal(Encoding::ASCII_8BIT, s.encoding)
|
78
|
+
assert_equal("\x00\x00\x00\x07string1\x00\x00\x00\x01\x2a\x00\x00\x00\x07string2\x00\x00\x00\x02\x06\xe4".b, s)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_ssh_unpack_encoded_nil
|
82
|
+
assert_raises(ArgumentError) { Util.ssh_unpack(nil) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_ssh_unpack_encoded_not_binary
|
86
|
+
assert_raises(ArgumentError) { Util.ssh_unpack('\x00\x00\x00\x12This is UTF-8: ✓', :string) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_ssh_unpack_spec_empty
|
90
|
+
assert_equal([], Util.ssh_unpack("\x00\x00\x00\x06string".b))
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_ssh_unpack_spec_invalid
|
94
|
+
assert_raises(ArgumentError) { Util.ssh_unpack("\x00\x00\x00\x07string1\x00\x00\x00\x07string2\x00\x00\x00\x07string3".b, :string, :unknown, :string) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_ssh_unpack_spec_longer_than_encoded
|
98
|
+
assert_raises(PuTTY::Key::FormatError) { Util.ssh_unpack("\x00\x00\x00\x06string".b, :string, :string) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_ssh_unpack_encoded_truncated_value
|
102
|
+
assert_raises(PuTTY::Key::FormatError) { Util.ssh_unpack("\x00\x00\x00\x06str".b, :string) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_ssh_unpack_encoded_truncated_length
|
106
|
+
assert_raises(PuTTY::Key::FormatError) { Util.ssh_unpack("\x00\x00".b, :string) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_ssh_unpack_encoded_missing_value
|
110
|
+
assert_raises(PuTTY::Key::FormatError) { Util.ssh_unpack("\x00\x00\x00\x06".b, :string) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_ssh_unpack_string_empty
|
114
|
+
a = Util.ssh_unpack("\x00\x00\x00\x00".b, :string)
|
115
|
+
assert_equal([''.b], a)
|
116
|
+
assert_kind_of(String, a[0])
|
117
|
+
assert_equal(Encoding::ASCII_8BIT, a[0].encoding)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_ssh_unpack_string_utf8
|
121
|
+
a = Util.ssh_unpack("\x00\x00\x00\x12This is UTF-8: \xe2\x9c\x93".b, :string)
|
122
|
+
assert_equal(["This is UTF-8: \xe2\x9c\x93".b], a)
|
123
|
+
assert_kind_of(String, a[0])
|
124
|
+
assert_equal(Encoding::ASCII_8BIT, a[0].encoding)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_ssh_unpack_string_binary
|
128
|
+
a = Util.ssh_unpack("\x00\x00\x00\x05\x00\x01\x02\x03\x04".b, :string)
|
129
|
+
assert_equal(["\x00\x01\x02\x03\x04".b], a)
|
130
|
+
assert_kind_of(String, a[0])
|
131
|
+
assert_equal(Encoding::ASCII_8BIT, a[0].encoding)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_ssh_unpack_bn
|
135
|
+
a = Util.ssh_unpack("\x00\x00\x00\x09\x00\xab\x54\xa9\x8c\xeb\x1f\x0a\xd2".b, :mpint)
|
136
|
+
assert_equal([OpenSSL::BN.new(12345678901234567890)], a)
|
137
|
+
assert_kind_of(OpenSSL::BN, a[0])
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_ssh_unpack_bn_positive_msb_unset
|
141
|
+
a = Util.ssh_unpack("\x00\x00\x00\x01\x7f\x00\x00\x00\x02\x7f\xff".b, :mpint, :mpint)
|
142
|
+
assert_equal([OpenSSL::BN.new(0x7f), OpenSSL::BN.new(0x7fff)], a)
|
143
|
+
a.each {|o| assert_kind_of(OpenSSL::BN, o) }
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_ssh_unpack_bn_positive_msb_set
|
147
|
+
a = Util.ssh_unpack("\x00\x00\x00\x02\x00\x80\x00\x00\x00\x02\x00\xff\x00\x00\x00\x03\x00\x80\x00\x00\x00\x00\x03\x00\xff\x00".b, :mpint, :mpint, :mpint, :mpint)
|
148
|
+
assert_equal([OpenSSL::BN.new(0x80), OpenSSL::BN.new(0xff), OpenSSL::BN.new(0x8000), OpenSSL::BN.new(0xff00)], a)
|
149
|
+
a.each {|o| assert_kind_of(OpenSSL::BN, o) }
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_ssh_unpack_bn_negative
|
153
|
+
a = Util.ssh_unpack("\x00\x00\x00\x01\xff\x00\x00\x00\x01\x80\x00\x00\x00\x02\xff\x7f\x00\x00\x00\x02\xff\x00".b, :mpint, :mpint, :mpint, :mpint)
|
154
|
+
assert_equal([OpenSSL::BN.new(-0x01), OpenSSL::BN.new(-0x80), OpenSSL::BN.new(-0x81), OpenSSL::BN.new(-0x0100)], a)
|
155
|
+
a.each {|o| assert_kind_of(OpenSSL::BN, o) }
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_ssh_unpack_bn_zero
|
159
|
+
a = Util.ssh_unpack("\x00\x00\x00\x00".b, :mpint)
|
160
|
+
assert_equal([OpenSSL::BN.new(0)], a)
|
161
|
+
assert_kind_of(OpenSSL::BN, a[0])
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_ssh_unpack_bn_rfc_4251_mpint_examples
|
165
|
+
a = Util.ssh_unpack("\x00\x00\x00\x00\x00\x00\x00\x08\x09\xa3\x78\xf9\xb2\xe3\x32\xa7\x00\x00\x00\x02\x00\x80\x00\x00\x00\x02\xed\xcc\x00\x00\x00\x05\xff\x21\x52\x41\x11".b, :mpint, :mpint, :mpint, :mpint, :mpint)
|
166
|
+
assert_equal([OpenSSL::BN.new(0x0), OpenSSL::BN.new(0x9a378f9b2e332a7), OpenSSL::BN.new(0x80), OpenSSL::BN.new(-0x1234), OpenSSL::BN.new(-0xdeadbeef)], a)
|
167
|
+
a.each {|o| assert_kind_of(OpenSSL::BN, o) }
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_ssh_unpack_mixed
|
171
|
+
a = Util.ssh_unpack("\x00\x00\x00\x07string1\x00\x00\x00\x01\x2a\x00\x00\x00\x07string2\x00\x00\x00\x02\x06\xe4".b, :string, :mpint, :string, :mpint)
|
172
|
+
assert_equal(['string1', OpenSSL::BN.new(42), 'string2', OpenSSL::BN.new(1764)], a)
|
173
|
+
assert_kind_of(String, a[0])
|
174
|
+
assert_kind_of(OpenSSL::BN, a[1])
|
175
|
+
assert_kind_of(String, a[2])
|
176
|
+
assert_kind_of(OpenSSL::BN, a[3])
|
177
|
+
assert_equal(Encoding::ASCII_8BIT, a[0].encoding)
|
178
|
+
assert_equal(Encoding::ASCII_8BIT, a[2].encoding)
|
179
|
+
end
|
180
|
+
end
|