putty-key 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|