codtls 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +12 -0
  3. data/.yardopts +4 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +21 -0
  6. data/README.md +78 -0
  7. data/Rakefile +29 -0
  8. data/lib/codtls.rb +186 -0
  9. data/lib/codtls/abstract_session.rb +179 -0
  10. data/lib/codtls/alert.rb +64 -0
  11. data/lib/codtls/decrypt.rb +72 -0
  12. data/lib/codtls/ecc.rb +26 -0
  13. data/lib/codtls/encrypt.rb +29 -0
  14. data/lib/codtls/h_changecipherspec.rb +25 -0
  15. data/lib/codtls/h_chello.rb +79 -0
  16. data/lib/codtls/h_content.rb +57 -0
  17. data/lib/codtls/h_finished.rb +30 -0
  18. data/lib/codtls/h_keyexchange.rb +131 -0
  19. data/lib/codtls/h_shello.rb +51 -0
  20. data/lib/codtls/h_shellodone.rb +22 -0
  21. data/lib/codtls/h_type.rb +22 -0
  22. data/lib/codtls/h_verify.rb +30 -0
  23. data/lib/codtls/handshake.rb +173 -0
  24. data/lib/codtls/models/codtls_connection.rb +3 -0
  25. data/lib/codtls/models/codtls_device.rb +3 -0
  26. data/lib/codtls/prf.rb +40 -0
  27. data/lib/codtls/pskdb.rb +104 -0
  28. data/lib/codtls/ram_session.rb +214 -0
  29. data/lib/codtls/rampskdb.rb +87 -0
  30. data/lib/codtls/record.rb +202 -0
  31. data/lib/codtls/session.rb +284 -0
  32. data/lib/codtls/version.rb +3 -0
  33. data/lib/generators/codtls/codtls_generator.rb +56 -0
  34. data/lib/generators/codtls/templates/create_codtls_connections.rb +15 -0
  35. data/lib/generators/codtls/templates/create_codtls_devices.rb +11 -0
  36. data/test/test_codtls.rb +75 -0
  37. data/test/test_ecc.rb +44 -0
  38. data/test/test_h_chello.rb +40 -0
  39. data/test/test_h_content.rb +59 -0
  40. data/test/test_h_keyexchange.rb +36 -0
  41. data/test/test_helper.rb +3 -0
  42. data/test/test_pskdb.rb +37 -0
  43. data/test/test_ram_session.rb +131 -0
  44. data/test/test_rampskdb.rb +26 -0
  45. data/test/test_record.rb +128 -0
  46. data/test/test_send_recv.rb +178 -0
  47. data/test/test_session.rb +164 -0
  48. metadata +303 -0
data/test/test_ecc.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+ require 'codtls/ecc'
3
+
4
+ # Testclass with Test Vectors from
5
+ # http://www.nsa.gov/ia/_files/nist-routines.pdf
6
+ class ECCTest < Minitest::Test
7
+ BP_X = ['6b17d1f2e12c4247f8bce6e563a440f2' \
8
+ '77037d812deb33a0f4a13945d898c296'].pack('H*')
9
+ BP_Y = ['4fe342e2fe1a7f9b8ee7eb4a7c0f9e16' \
10
+ '2bce33576b315ececbb6406837bf51f5'].pack('H*')
11
+
12
+ S_X = ['de2444bebc8d36e682edd27e0f271508' \
13
+ '617519b3221a8fa0b77cab3989da97c9'].pack('H*')
14
+ S_Y = ['c093ae7ff36e5380fc01a5aad1e66659' \
15
+ '702de80f53cec576b6350b243042a256'].pack('H*')
16
+
17
+ KEY = ['c51e4753afdec1e6b6c6a5b992f43f8d' \
18
+ 'd0c7a8933072708b6522468b2ffb06fd'].pack('H*')
19
+
20
+ R_X = '51d08d5f2d4278882946d88d83c97d11' \
21
+ 'e62becc3cfc18bedacc89ba34eeca03f'
22
+ R_Y = '75ee68eb8bf626aa5b673ab51f6e744e' \
23
+ '06f8fcf8a6c0cf3035beca956a7b41d5'
24
+
25
+ KEY2 = ['00000000000000000000000000000000' \
26
+ '00000000000000000000000000000002'].pack('H*')
27
+
28
+ R2_X = '7669e6901606ee3ba1a8eef1e0024c33' \
29
+ 'df6c22f3b17481b82a860ffcdb6127b0'
30
+ R2_Y = 'fa878162187a54f6c39f6ee0072f33de' \
31
+ '389ef3eecd03023de10ca2c1db61d0c7'
32
+
33
+ def test_ecc
34
+ r = CoDTLS::ECC.mult(KEY, "\x04" + S_X + S_Y)
35
+ assert_equal('04' + R_X + R_Y, r.unpack('H*')[0])
36
+
37
+ r = CoDTLS::ECC.mult(KEY2, "\x04" + S_X + S_Y)
38
+ assert_equal('04' + R2_X + R2_Y, r.unpack('H*')[0])
39
+
40
+ r1 = CoDTLS::ECC.mult(KEY, "\x04" + BP_X + BP_Y)
41
+ r2 = CoDTLS::ECC.mult(KEY)
42
+ assert_equal(r1.unpack('H*')[0], r2.unpack('H*')[0])
43
+ end
44
+ end
@@ -0,0 +1,40 @@
1
+ require 'test_helper'
2
+ require 'codtls'
3
+
4
+ # Testclass
5
+ class ClientHelloTest < Minitest::Test
6
+ RANDOM = 'ABCDEFGHIJKLMNOPQRSTUVWXYZAB'
7
+ COOKIE = 'ABCDEFGH'
8
+ APPENDIX = "\x00\x02\xFF\x01\x01\x00\x00\x0E\x00\x0A\x00" \
9
+ "\x04\x00\x02\x00\x23\x00\x0B\x00\x02\x01\x00"
10
+
11
+ # [fails?, time, random, cookie, wire]
12
+ V = [
13
+ [0, 42, RANDOM, COOKIE,
14
+ "\xFE\xFD\x00\x00\x00\x2A" + RANDOM + "\x08" + COOKIE + APPENDIX],
15
+ [0, 24, RANDOM, nil,
16
+ "\xFE\xFD\x00\x00\x00\x18" + RANDOM + "\x00" + APPENDIX],
17
+ [0, 0xFFFFFFFF, RANDOM, nil,
18
+ "\xFE\xFD\xFF\xFF\xFF\xFF" + RANDOM + "\x00" + APPENDIX],
19
+ [1, nil, RANDOM, COOKIE, 'T1'],
20
+ [1, 0x1FFFFFFFF, RANDOM, COOKIE, 'T2'],
21
+ [1, 42, '', COOKIE, 'T3'],
22
+ [1, 42, nil, COOKIE, 'T4'],
23
+ [1, 42, RANDOM[0..26], COOKIE, 'T5'],
24
+ [1, 42, RANDOM + 'C', COOKIE, 'T6'],
25
+ [1, 42, RANDOM, 'A' * 256, 'T7']
26
+ ]
27
+
28
+ def test_clienthello
29
+ V.each do |(f, t, r, c, w)|
30
+ if f == 1
31
+ assert_raises CoDTLS::HandshakeError, w do
32
+ CoDTLS::Handshake::ClientHello.new(t, r, c)
33
+ end
34
+ else
35
+ wire = CoDTLS::Handshake::ClientHello.new(t, r, c).to_wire
36
+ assert_equal(w.b, wire)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ require 'test_helper'
2
+ require 'codtls'
3
+
4
+ # Testclass
5
+ class ContentTest < Minitest::Test
6
+ COOKIE = 'ABCDEFGH'
7
+
8
+ def test_content_get
9
+ 3.times do |i|
10
+ c = ("\x0D\x0B\x03\x03\x08" + COOKIE) * (i + 1)
11
+ o = CoDTLS::Handshake::Content.get_content(c)
12
+ assert_equal(CoDTLS::Handshake::HelloVerifyRequest, o.class)
13
+ assert_equal(COOKIE, o.cookie)
14
+ assert_equal(("\x0D\x0B\x03\x03\x08" + COOKIE) * i, c)
15
+ end
16
+
17
+ c = "\x0D\x0B\x03\x03\x08" + COOKIE + 'A'
18
+ CoDTLS::Handshake::Content.get_content(c)
19
+ assert_equal('A', c)
20
+
21
+ assert_raises CoDTLS::HandshakeError do
22
+ c = "\x0D\x0B\x03\x03\x08" + COOKIE[0...6]
23
+ CoDTLS::Handshake::Content.get_content(c)
24
+ end
25
+
26
+ assert_raises CoDTLS::HandshakeError do
27
+ c = "\xFD\x0B\x03\x03\x08" + COOKIE
28
+ CoDTLS::Handshake::Content.get_content(c)
29
+ end
30
+ end
31
+
32
+ def test_add_content
33
+ c = ''
34
+ f = CoDTLS::Handshake::Finished.new('Hallo Welt!')
35
+ CoDTLS::Handshake::Content.add_content(c, f)
36
+ assert_equal("\x51\x0BHallo Welt!", c)
37
+
38
+ CoDTLS::Handshake::Content.add_content(c, f)
39
+ assert_equal("\x51\x0BHallo Welt!\x51\x0BHallo Welt!", c)
40
+
41
+ c = 'ABC'
42
+ f = CoDTLS::Handshake::Finished.new('Hallo Welt!')
43
+ CoDTLS::Handshake::Content.add_content(c, f)
44
+ assert_equal("ABC\x51\x0BHallo Welt!", c)
45
+
46
+ c = ''
47
+ f = CoDTLS::Handshake::Finished.new('')
48
+ CoDTLS::Handshake::Content.add_content(c, f)
49
+ assert_equal("\x50", c)
50
+
51
+ f = CoDTLS::Handshake::Finished.new('Hallo Welt!')
52
+ CoDTLS::Handshake::Content.add_content(c, f)
53
+ assert_equal("\x50\x51\x0BHallo Welt!", c)
54
+
55
+ f = CoDTLS::Handshake::Finished.new('')
56
+ CoDTLS::Handshake::Content.add_content(c, f)
57
+ assert_equal("\x50\x51\x0BHallo Welt!\x50", c)
58
+ end
59
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'codtls'
3
+
4
+ # Testclass
5
+ class KeyExchangeTest < Minitest::Test
6
+ PSK_HINT = 'ABCDEFGHIJKLMNOP'
7
+ CURVE = CoDTLS::Handshake::KeyExchange::ECCURVETYPE[:named_curve] +
8
+ CoDTLS::Handshake::KeyExchange::NAMEDCURVE[:secp256r1]
9
+ POINT = CoDTLS::Handshake::KeyExchange::POINTTYPE[:uncompressed] +
10
+ ['6b17d1f2e12c4247f8bce6e563a440f2' \
11
+ '77037d812deb33a0f4a13945d898c296'].pack('H*') +
12
+ ['4fe342e2fe1a7f9b8ee7eb4a7c0f9e16' \
13
+ '2bce33576b315ececbb6406837bf51f5'].pack('H*')
14
+
15
+ # [fails?, psk_hint, curve, point, wire]
16
+ V = [
17
+ [0, PSK_HINT, CURVE, POINT,
18
+ "\x00\x10" + PSK_HINT + CURVE + "\x41" + POINT] # ,
19
+ # [1, nil, RANDOM, COOKIE, 'T1']
20
+ ]
21
+
22
+ def test_keyexchange
23
+ V.each do |(f, psk, c, p, w)|
24
+ if f == 1
25
+ # assert_raises CoDTLS::HandshakeError, w do
26
+ # CoDTLS::Handshake::ClientHello.new(t, r, c)
27
+ # end
28
+ else
29
+ wire = CoDTLS::Handshake::ClientKeyExchange.new(psk, c, p).to_wire
30
+ assert_equal(w.b, wire)
31
+ wire = CoDTLS::Handshake::ServerKeyExchange.new(psk, c, p).to_wire
32
+ assert_equal(w.b, wire)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+ require 'minitest/autorun'
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+ require 'codtls/pskdb'
3
+
4
+ # Testclass
5
+ class CoDTLSPSKDBTest < Minitest::Test
6
+ def setup
7
+ fail CoDTLS::SessionError 'testdatabase already exists' if File.exist?(
8
+ 'testdatabase.sqlite')
9
+ SQLite3::Database.new('testdatabase.sqlite')
10
+ ActiveRecord::Base.establish_connection(
11
+ adapter: 'sqlite3',
12
+ database: 'testdatabase.sqlite')
13
+ ActiveRecord::Base.connection
14
+ ActiveRecord::Migration.verbose = false # debug messages
15
+ ActiveRecord::Migrator.migrate 'db/migrate'
16
+ @session = CoDTLS::Session.new('127.0.0.1')
17
+ end
18
+
19
+ def teardown
20
+ ActiveRecord::Base.remove_connection
21
+ FileUtils.rm('testdatabase.sqlite') if File.exist?('testdatabase.sqlite')
22
+ end
23
+
24
+ # a new uuid gets registered and its psk gets updated.
25
+ # The standard values for the epoch and handshake get checked.
26
+ def test_psk
27
+ assert_equal(nil, CoDTLS::PSKDB.get_psk('UUID'))
28
+ CoDTLS::PSKDB.set_psk('UUID', '')
29
+ assert_equal('', CoDTLS::PSKDB.get_psk('UUID'))
30
+ CoDTLS::PSKDB.set_psk('UUID', 'PSK')
31
+ assert_equal('PSK', CoDTLS::PSKDB.get_psk('UUID'))
32
+ CoDTLS::PSKDB.set_psk('UUID2', 'PSK1')
33
+ assert_equal('PSK1', CoDTLS::PSKDB.get_psk('UUID2'))
34
+ CoDTLS::PSKDB.set_psk('UUID2', 'PSK2')
35
+ assert_equal('PSK2', CoDTLS::PSKDB.get_psk('UUID2'))
36
+ end
37
+ end
@@ -0,0 +1,131 @@
1
+ require 'test_helper'
2
+ require 'codtls/abstract_session'
3
+ require 'codtls/ram_session'
4
+
5
+ # Testclass
6
+ class CoDTLSRAMSessionTest < Minitest::Test
7
+ def setup
8
+ @session = CoDTLS::RAMSession.new('127.0.0.1')
9
+ end
10
+
11
+ def teardown
12
+ CoDTLS::RAMSession.clear_all
13
+ end
14
+
15
+ # check values, set everything, check values, clear, check values,
16
+ # create new session, check values
17
+ def test_clear
18
+ assert_equal(nil, @session.id)
19
+ assert_equal(0, @session.epoch)
20
+ assert_equal(true, @session.check_seq(1))
21
+ assert_equal(1, @session.seq)
22
+ assert_equal(nil, @session.key_block)
23
+ assert_equal(false, @session.handshake?)
24
+
25
+ @session.id = 'ABCDEFGH'
26
+ @session.key_block = 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDABCD'
27
+ @session.increase_epoch
28
+ @session.seq = 5
29
+ @session.enable_handshake
30
+
31
+ assert_equal('ABCDEFGH', @session.id)
32
+ assert_equal(1, @session.epoch)
33
+ assert_equal(true, @session.check_seq(6))
34
+ assert_equal(1, @session.seq)
35
+ assert_equal('ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDABCD',
36
+ @session.key_block)
37
+ assert_equal(true, @session.handshake?)
38
+
39
+ @session.clear
40
+ assert_equal(nil, @session.id)
41
+ assert_equal(0, @session.epoch)
42
+ assert_equal(true, @session.check_seq(1))
43
+ assert_equal(1, @session.seq)
44
+ assert_equal(nil, @session.key_block)
45
+ assert_equal(false, @session.handshake?)
46
+ end
47
+
48
+ # get_epoch and increase_epoch test
49
+ def test_epoch
50
+ assert_equal(nil, @session.id)
51
+ assert_equal(0, @session.epoch)
52
+ assert_equal(true, @session.check_seq(1))
53
+ assert_equal(1, @session.seq)
54
+ assert_equal(nil, @session.key_block)
55
+ assert_equal(false, @session.handshake?)
56
+
57
+ @session.seq
58
+ @session.seq
59
+ @session.seq = 50
60
+ assert_raises(CoDTLS::SessionError) { @session.increase_epoch }
61
+
62
+ @session.key_block = 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDABCD'
63
+ assert_equal(nil, @session.key_block)
64
+
65
+ @session.increase_epoch
66
+ assert_equal(1, @session.epoch)
67
+ assert_equal(true, @session.check_seq(1))
68
+ assert_equal(1, @session.seq)
69
+ assert_equal('ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDABCD',
70
+ @session.key_block)
71
+ end
72
+
73
+ # get_key_block and add_key_block tests, testing the overwriting off
74
+ # new keyblocks and switching keyblocks when the epoch is increased
75
+ def test_key_block
76
+ assert_equal(nil, @session.key_block)
77
+ exception = assert_raises(CoDTLS::SessionError) do
78
+ @session.key_block = 'this_key_block_is_too_small'
79
+ end
80
+ assert_equal('key blocks have to be 40 byte long', exception.message)
81
+ @session.key_block = 'key_block_with_fourty_bytes_number_00001'
82
+ assert_equal(nil, @session.key_block)
83
+ @session.increase_epoch
84
+ assert_equal('key_block_with_fourt' \
85
+ 'y_bytes_number_00001', @session.key_block)
86
+ @session.key_block = 'key_block_with_fourty_bytes_number_00002'
87
+ @session.key_block = 'key_block_with_fourty_bytes_number_00003'
88
+ assert_equal('key_block_with_fourt' \
89
+ 'y_bytes_number_00001', @session.key_block)
90
+ @session.increase_epoch
91
+ assert_equal('key_block_with_fourt' \
92
+ 'y_bytes_number_00003', @session.key_block)
93
+ end
94
+
95
+ # enable_handshake and dissable_handshake tests.
96
+ def test_handshake
97
+ assert_equal(false, @session.handshake?)
98
+ @session.enable_handshake
99
+ assert_equal(true, @session.handshake?)
100
+ @session.enable_handshake
101
+ assert_equal(true, @session.handshake?)
102
+ @session.disable_handshake
103
+ assert_equal(false, @session.handshake?)
104
+ end
105
+
106
+ # get_seq and check_seq tests, testing the check_seq ranges and the
107
+ # incrementing of get_seq.
108
+ def test_seq
109
+ assert_equal(1, @session.seq)
110
+ assert_equal(2, @session.seq)
111
+ assert_equal(3, @session.seq)
112
+
113
+ # 1 is expected, so -9 ... 101 are valid values
114
+ assert_equal(false, @session.check_seq(-10))
115
+ assert_equal(false, @session.check_seq(102))
116
+ assert_equal(true, @session.check_seq(-9))
117
+ assert_equal(true, @session.check_seq(-1))
118
+ assert_equal(true, @session.check_seq(0))
119
+ assert_equal(true, @session.check_seq(1))
120
+ assert_equal(true, @session.check_seq(101))
121
+
122
+ @session.seq = 1
123
+ (2..100).each do |n|
124
+ assert_equal(true, @session.check_seq(n))
125
+ @session.seq = n
126
+ end
127
+ # 101 is expected, so max allowed value is 201
128
+ assert_equal(true, @session.check_seq(201))
129
+ assert_equal(false, @session.check_seq(202))
130
+ end
131
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+ require 'codtls/rampskdb'
3
+
4
+ # Testclass
5
+ class CoDTLSRAMPSKDBTest < Minitest::Test
6
+ def setup
7
+ end
8
+
9
+ def teardown
10
+ CoDTLS::RAMPSKDB.clear_all
11
+ end
12
+
13
+ # a new uuid gets registered and its psk gets updated.
14
+ # The standard values for the epoch and handshake get checked.
15
+ def test_psk
16
+ assert_equal(nil, CoDTLS::RAMPSKDB.get_psk('UUID'))
17
+ CoDTLS::RAMPSKDB.set_psk('UUID', '')
18
+ assert_equal('', CoDTLS::RAMPSKDB.get_psk('UUID'))
19
+ CoDTLS::RAMPSKDB.set_psk('UUID', 'PSK')
20
+ assert_equal('PSK', CoDTLS::RAMPSKDB.get_psk('UUID'))
21
+ CoDTLS::RAMPSKDB.set_psk('UUID2', 'PSK1')
22
+ assert_equal('PSK1', CoDTLS::RAMPSKDB.get_psk('UUID2'))
23
+ CoDTLS::RAMPSKDB.set_psk('UUID2', 'PSK2')
24
+ assert_equal('PSK2', CoDTLS::RAMPSKDB.get_psk('UUID2'))
25
+ end
26
+ end
@@ -0,0 +1,128 @@
1
+ require 'test_helper'
2
+ require 'codtls'
3
+
4
+ # Testclass
5
+ class RecordTest < Minitest::Test
6
+ # [fails?, input, header, headeradd]
7
+ V = [[
8
+ # Type
9
+ [0, :alert, 0x2000, ''],
10
+ [0, :handshake, 0x4000, ''],
11
+ [0, :appdata, 0x6000, ''],
12
+ [0, 0, 0x0000, '00'],
13
+ [0, 128, 0x0000, '80'],
14
+ [0, 255, 0x0000, 'ff'],
15
+ [1, 'string', 0x0000, ''],
16
+ [1, :unknown, 0x0000, ''],
17
+ [1, -1, 0x0000, ''],
18
+ [1, 256, 0x0000, '']
19
+ ], [
20
+ # Version
21
+ [0, :v10, 0x0000, ''],
22
+ [0, :v12, 0x1000, ''],
23
+ [0, 0, 0x0800, '0000'],
24
+ [0, 255, 0x0800, '00ff'],
25
+ [0, 256, 0x0800, '0100'],
26
+ [0, 2**16 - 1, 0x0800, 'ffff'],
27
+ [1, 'string', 0x0800, ''],
28
+ [1, :reserved, 0x0800, ''],
29
+ [1, -1, 0x0800, ''],
30
+ [1, 2**16, 0x0800, '']
31
+ ], [
32
+ # Epoch
33
+ [0, :implizit, 0x0700, ''],
34
+ [0, 0, 0x0000, ''],
35
+ [0, 4, 0x0400, ''],
36
+ [0, 5, 0x0500, '05'],
37
+ [0, 255, 0x0500, 'ff'],
38
+ [0, 256, 0x0600, '0100'],
39
+ [0, 2**16 - 1, 0x0600, 'ffff'],
40
+ [1, 'string', 0x0500, ''],
41
+ [1, :unknown, 0x0500, ''],
42
+ [1, -1, 0x0600, ''],
43
+ [1, 2**16, 0x0600, '']
44
+ ], [
45
+ # Seq_Num
46
+ [0, :none, 0x0000, ''],
47
+ [0, :implizit, 0x001C, ''],
48
+ [0, 0, 0x0004, '00'],
49
+ [0, 255, 0x0004, 'ff'],
50
+ [0, 256, 0x0008, '0100'],
51
+ [0, 2**16 - 1, 0x0008, 'ffff'],
52
+ [0, 2**16, 0x000C, '010000'],
53
+ [0, 2**48 - 1, 0x0018, 'ffffffffffff'],
54
+ [1, 'string', 0x0004, ''],
55
+ [1, :unknown, 0x0008, ''],
56
+ [1, -1, 0x000C, ''],
57
+ [1, 2**48, 0x0018, '']
58
+ ], [
59
+ # Length
60
+ [0, :implizit, 0x0003, ''],
61
+ [0, 0, 0x0000, ''],
62
+ [0, 5, 0x0001, '05'],
63
+ [0, 128, 0x0001, '80'],
64
+ [0, 255, 0x0001, 'ff'],
65
+ [0, 256, 0x0002, '0100'],
66
+ [0, 2**16 - 1, 0x0002, 'ffff'],
67
+ [1, 'string', 0x0001, ''],
68
+ [1, :unknown, 0x0001, ''],
69
+ [1, -1, 0x0002, ''],
70
+ [1, 2**16, 0x0002, '']
71
+ ]]
72
+
73
+ def test_record
74
+ assert_raises(CoDTLS::RecordError) { CoDTLS::Record.parse('') }
75
+ assert_raises(CoDTLS::RecordError) { CoDTLS::Record.parse(' ') }
76
+
77
+ V[0].each do |t|
78
+ V[1].each do |v|
79
+ V[2].each do |e|
80
+ V[3].each do |s|
81
+ V[4].each do |l|
82
+ header = 0x00C0 | t[2] | v[2] | e[2] | s[2] | l[2]
83
+ to_add = t[3] + v[3] + e[3] + s[3] + l[3]
84
+ complete = [header].pack('n').unpack('H*')[0] + to_add
85
+
86
+ fail = t[0] | v[0] | e[0] | s[0] | l[0]
87
+ if fail == 1
88
+ assert_raises CoDTLS::RecordError, complete do
89
+ r = CoDTLS::Record.new(t[1], e[1], s[1])
90
+ r.version = v[1]
91
+ r.length = l[1]
92
+ end
93
+ assert_raises CoDTLS::RecordError, complete do
94
+ CoDTLS::Record.parse([complete].pack('H*'))
95
+ end
96
+ else
97
+ nonce = 'abcd'
98
+ nonce += [e[1].class == Symbol ? 0 : e[1]].pack('n')
99
+ seq = [s[1].class == Symbol ? 0 : s[1]].pack('Q')
100
+ nonce += seq[0...6].reverse
101
+ # to_wire
102
+ r = CoDTLS::Record.new(t[1], e[1], s[1])
103
+ r.version = v[1]
104
+ r.length = l[1]
105
+ assert_equal(complete, r.to_wire.unpack('H*')[0], r.inspect)
106
+ assert_equal(nonce, r.nonce('abcd'))
107
+ # parse
108
+ data = 'Hello World!'
109
+ fail_info = complete + data
110
+ complete = [complete].pack('H*') + data
111
+ r, d = CoDTLS::Record.parse(complete)
112
+ assert_equal(t[1], r.type, fail_info + ' Type')
113
+ assert_equal(v[1], r.version, fail_info + ' Version')
114
+ assert_equal(e[1], r.epoch, fail_info + ' Epoch')
115
+ assert_equal(s[1], r.seq_num, fail_info + ' Seq_num')
116
+ assert_equal(l[1], r.length, fail_info + ' Length')
117
+ range = (r.length == :implizit ? 0..-1 : 0...r.length)
118
+ assert_equal(data.slice!(range), d, fail_info + ' Payload')
119
+ assert_equal(data, complete, fail_info + ' Rest')
120
+ assert_equal(nonce, r.nonce('abcd'))
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end