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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +3 -0
  3. data.tar.gz.sig +1 -0
  4. data/.yardopts +7 -0
  5. data/CHANGES.md +4 -0
  6. data/Gemfile +14 -0
  7. data/LICENSE +19 -0
  8. data/README.md +137 -0
  9. data/Rakefile +110 -0
  10. data/lib/putty/key.rb +25 -0
  11. data/lib/putty/key/error.rb +26 -0
  12. data/lib/putty/key/openssl.rb +182 -0
  13. data/lib/putty/key/ppk.rb +374 -0
  14. data/lib/putty/key/util.rb +128 -0
  15. data/lib/putty/key/version.rb +6 -0
  16. data/putty-key.gemspec +29 -0
  17. data/test/fixtures/dss-1024-encrypted.ppk +17 -0
  18. data/test/fixtures/dss-1024.pem +12 -0
  19. data/test/fixtures/dss-1024.ppk +17 -0
  20. data/test/fixtures/ecdsa-secp256k1.pem +5 -0
  21. data/test/fixtures/ecdsa-sha2-nistp256-encrypted.ppk +10 -0
  22. data/test/fixtures/ecdsa-sha2-nistp256.pem +5 -0
  23. data/test/fixtures/ecdsa-sha2-nistp256.ppk +10 -0
  24. data/test/fixtures/ecdsa-sha2-nistp384-encrypted.ppk +11 -0
  25. data/test/fixtures/ecdsa-sha2-nistp384.pem +6 -0
  26. data/test/fixtures/ecdsa-sha2-nistp384.ppk +11 -0
  27. data/test/fixtures/ecdsa-sha2-nistp521-encrypted.ppk +12 -0
  28. data/test/fixtures/ecdsa-sha2-nistp521.pem +7 -0
  29. data/test/fixtures/ecdsa-sha2-nistp521.ppk +12 -0
  30. data/test/fixtures/rsa-2048-encrypted.ppk +26 -0
  31. data/test/fixtures/rsa-2048.pem +27 -0
  32. data/test/fixtures/rsa-2048.ppk +26 -0
  33. data/test/fixtures/test-blank-comment.ppk +11 -0
  34. data/test/fixtures/test-encrypted.ppk +11 -0
  35. data/test/fixtures/test-invalid-blob-lines.ppk +11 -0
  36. data/test/fixtures/test-invalid-encryption-type.ppk +11 -0
  37. data/test/fixtures/test-invalid-format-1.ppk +11 -0
  38. data/test/fixtures/test-invalid-format-3.ppk +11 -0
  39. data/test/fixtures/test-invalid-private-mac.ppk +11 -0
  40. data/test/fixtures/test-truncated.ppk +10 -0
  41. data/test/fixtures/test-unix-line-endings.ppk +11 -0
  42. data/test/fixtures/test.ppk +11 -0
  43. data/test/openssl_test.rb +252 -0
  44. data/test/ppk_test.rb +247 -0
  45. data/test/test_helper.rb +81 -0
  46. data/test/util_test.rb +180 -0
  47. data/test/version_test.rb +7 -0
  48. metadata +124 -0
  49. 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
@@ -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