costan-tem_ruby 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/CHANGELOG +45 -0
  2. data/LICENSE +21 -0
  3. data/Manifest +75 -0
  4. data/README +8 -0
  5. data/Rakefile +23 -0
  6. data/bin/tem_bench +9 -0
  7. data/bin/tem_ca +13 -0
  8. data/bin/tem_irb +11 -0
  9. data/bin/tem_proxy +65 -0
  10. data/bin/tem_stat +35 -0
  11. data/dev_ca/ca_cert.cer +0 -0
  12. data/dev_ca/ca_cert.pem +32 -0
  13. data/dev_ca/ca_key.pem +27 -0
  14. data/dev_ca/config.yml +14 -0
  15. data/lib/tem/_cert.rb +158 -0
  16. data/lib/tem/apdus/buffers.rb +89 -0
  17. data/lib/tem/apdus/keys.rb +64 -0
  18. data/lib/tem/apdus/lifecycle.rb +13 -0
  19. data/lib/tem/apdus/tag.rb +38 -0
  20. data/lib/tem/auto_conf.rb +25 -0
  21. data/lib/tem/builders/abi.rb +482 -0
  22. data/lib/tem/builders/assembler.rb +314 -0
  23. data/lib/tem/builders/crypto.rb +124 -0
  24. data/lib/tem/builders/isa.rb +120 -0
  25. data/lib/tem/ca.rb +114 -0
  26. data/lib/tem/definitions/abi.rb +65 -0
  27. data/lib/tem/definitions/assembler.rb +23 -0
  28. data/lib/tem/definitions/isa.rb +188 -0
  29. data/lib/tem/ecert.rb +77 -0
  30. data/lib/tem/hive.rb +18 -0
  31. data/lib/tem/keys/asymmetric.rb +116 -0
  32. data/lib/tem/keys/key.rb +48 -0
  33. data/lib/tem/keys/symmetric.rb +47 -0
  34. data/lib/tem/sec_exec_error.rb +63 -0
  35. data/lib/tem/seclosures.rb +81 -0
  36. data/lib/tem/secpack.rb +107 -0
  37. data/lib/tem/tem.rb +31 -0
  38. data/lib/tem/toolkit.rb +101 -0
  39. data/lib/tem/transport/auto_configurator.rb +87 -0
  40. data/lib/tem/transport/java_card_mixin.rb +99 -0
  41. data/lib/tem/transport/jcop_remote_protocol.rb +59 -0
  42. data/lib/tem/transport/jcop_remote_server.rb +171 -0
  43. data/lib/tem/transport/jcop_remote_transport.rb +65 -0
  44. data/lib/tem/transport/pcsc_transport.rb +87 -0
  45. data/lib/tem/transport/transport.rb +10 -0
  46. data/lib/tem_ruby.rb +47 -0
  47. data/tem_ruby.gemspec +35 -0
  48. data/test/_test_cert.rb +70 -0
  49. data/test/builders/test_abi_builder.rb +298 -0
  50. data/test/tem_test_case.rb +26 -0
  51. data/test/tem_unit/test_tem_alu.rb +33 -0
  52. data/test/tem_unit/test_tem_bound_secpack.rb +51 -0
  53. data/test/tem_unit/test_tem_branching.rb +56 -0
  54. data/test/tem_unit/test_tem_crypto_asymmetric.rb +123 -0
  55. data/test/tem_unit/test_tem_crypto_hash.rb +35 -0
  56. data/test/tem_unit/test_tem_crypto_pstore.rb +53 -0
  57. data/test/tem_unit/test_tem_crypto_random.rb +25 -0
  58. data/test/tem_unit/test_tem_emit.rb +23 -0
  59. data/test/tem_unit/test_tem_memory.rb +48 -0
  60. data/test/tem_unit/test_tem_memory_compare.rb +65 -0
  61. data/test/tem_unit/test_tem_output.rb +32 -0
  62. data/test/tem_unit/test_tem_yaml_secpack.rb +47 -0
  63. data/test/test_driver.rb +108 -0
  64. data/test/test_exceptions.rb +35 -0
  65. data/test/transport/test_auto_configurator.rb +114 -0
  66. data/test/transport/test_java_card_mixin.rb +90 -0
  67. data/test/transport/test_jcop_remote.rb +82 -0
  68. data/timings/blank_bound_secpack.rb +18 -0
  69. data/timings/blank_sec.rb +14 -0
  70. data/timings/devchip_decrypt.rb +9 -0
  71. data/timings/post_buffer.rb +10 -0
  72. data/timings/simple_apdu.rb +5 -0
  73. data/timings/timings.rb +64 -0
  74. data/timings/vm_perf.rb +140 -0
  75. data/timings/vm_perf_bound.rb +141 -0
  76. metadata +201 -0
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+
3
+ require 'tem_ruby'
4
+
5
+ # Helper methods for TEM tests.
6
+ #
7
+ # This module implements setup and teardown methods that provide an initialized
8
+ # @tem instance variable holding a Tem::Session. Just the right thing for
9
+ # testing :)
10
+ class TemTestCase < Test::Unit::TestCase
11
+ def setup
12
+ @tem = Tem.auto_tem
13
+
14
+ @tem.kill
15
+ @tem.activate
16
+ end
17
+
18
+ def teardown
19
+ @tem.disconnect unless @tem.nil?
20
+ end
21
+
22
+ def test_smoke
23
+ # All the required files have been parsed successfully.
24
+ assert true
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemAluTest < TemTestCase
4
+ def test_alu
5
+ sec = @tem.assemble { |s|
6
+ s.ldbc 10
7
+ s.outnew
8
+ s.ldwc 0x1234
9
+ s.ldwc 0x5678
10
+ s.dupn :n => 2
11
+ s.add
12
+ s.outw
13
+ s.sub
14
+ s.outw
15
+ s.ldwc 0x0155
16
+ s.ldwc 0x02AA
17
+ s.mul
18
+ s.outw
19
+ s.ldwc 0x390C
20
+ s.ldwc 0x00AA
21
+ s.dupn :n => 2
22
+ s.div
23
+ s.outw
24
+ s.mod
25
+ s.outw
26
+ s.halt
27
+ s.stack 5
28
+ }
29
+ result = @tem.execute sec
30
+ assert_equal [0x68, 0xAC, 0xBB, 0xBC, 0x8C, 0x72, 0x00, 0x55, 0x00, 0x9A],
31
+ result, 'the ALU isn\'t working well'
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ require 'test/tem_test_case'
2
+
3
+ module TemBoundSecpackTestCase
4
+ # This is also called from TemYamlSecpackTest.
5
+ def _test_bound_secpack(yaml_roundtrip = false)
6
+ keyd = @tem.tk_gen_key
7
+ pubk = @tem.tk_read_key keyd[:pubk_id], keyd[:authz]
8
+
9
+ secret = (0...16).map { |i| (99 * i * i + 51 * i + 33) % 256 }
10
+ bound_sec = @tem.assemble { |s|
11
+ s.ldbc secret.length
12
+ s.outnew
13
+ s.label :mess_place
14
+ s.outfxb :size => secret.length, :from => :secret
15
+ s.halt
16
+ s.label :secret
17
+ s.data :tem_ubyte, secret
18
+ # Make sure the zero_bytes optimization doesn't screw things up.
19
+ s.zeros :tem_ubyte, 60
20
+ s.label :plain
21
+ s.stack 4
22
+ }
23
+
24
+ sb = bound_sec.body
25
+ secret_found = false
26
+ 0.upto(sb.length - 1) { |i| if secret == sb[i, secret.length] then secret_found = true; break; end }
27
+ assert secret_found, 'test_bound_secpack needs rethinking: the unbound secpack does not contain the secret'
28
+
29
+ bound_sec.bind pubk, :secret, :plain
30
+ if yaml_roundtrip
31
+ # same test, except the SECpack is serialized/deserialized
32
+ yaml_bound_sec = bound_sec.to_yaml_str
33
+ bound_sec = Tem::SecPack.new_from_yaml_str(yaml_bound_sec)
34
+ end
35
+ result = @tem.execute bound_sec, keyd[:privk_id]
36
+ assert_equal secret, result, 'TEM failed to decrypt secpack'
37
+
38
+ sb = bound_sec.body
39
+ 0.upto(sb.length - 1) { |i| assert_not_equal secret, sb[i, secret.length], 'secret found unencrypted in bound secpack' }
40
+
41
+ bound_sec.body[bound_sec.label_address(:mess_place)] += 1
42
+ assert_raise(RuntimeError, 'secpack validation isn\'t working') { @tem.execute bound_sec }
43
+ end
44
+ end
45
+
46
+ class TemBoundSecpackTest < TemTestCase
47
+ include TemBoundSecpackTestCase
48
+ def test_bound_secpack
49
+ _test_bound_secpack false
50
+ end
51
+ end
@@ -0,0 +1,56 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemBranchingTest < TemTestCase
4
+ def test_branching
5
+ secpack = @tem.assemble { |s|
6
+ s.ldbc 24
7
+ s.outnew
8
+
9
+ s.jmp :to => :over_halt
10
+ s.halt # this gets jumped over
11
+ s.label :over_halt
12
+ s.ldbc 4
13
+ s.label :test_loop
14
+ s.dupn :n => 1
15
+ s.outb
16
+ s.ldbc 1
17
+ s.sub
18
+ s.dupn :n=> 1
19
+ s.jae :to => :test_loop
20
+
21
+ failed = 0xFA - (1 << 8)
22
+ [
23
+ [:ja, [1, 1, failed], [0, failed, 2], [-1, failed, 3]],
24
+ [:jae, [1, 4, failed], [0, 5, failed], [-1, failed, 6]],
25
+ [:jb, [1, failed, 7], [0, failed, 8], [-1, 9, failed]],
26
+ [:jbe, [1, failed, 10], [0, 11, failed], [-1, 12, failed]],
27
+ [:jz, [1, failed, 13], [0, 14, failed], [-1, failed, 15]],
28
+ [:jne, [1, 16, failed], [0, failed, 17], [-1, 18, failed]],
29
+ ].each do |op_line|
30
+ op = op_line.shift
31
+ op_line.each_index do |i|
32
+ then_label = "#{op}_l#{i}_t".to_sym
33
+ out_label = "#{op}_l#{i}_o".to_sym
34
+
35
+ s.ldbc op_line[i][0]
36
+ s.send op, :to => then_label
37
+ s.ldbc op_line[i][2]
38
+ s.jmp :to => out_label
39
+ s.label then_label
40
+ s.ldbc op_line[i][1]
41
+ s.label out_label
42
+ s.outb
43
+ end
44
+ end
45
+
46
+ s.halt
47
+ # Test automated stack placement.
48
+ s.zeros :tem_ubyte, 10
49
+ }
50
+ result = @tem.execute secpack
51
+ assert_equal [0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
52
+ 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
53
+ 0x10, 0x11, 0x12],
54
+ result, 'the branching unit isn\'t working well'
55
+ end
56
+ end
@@ -0,0 +1,123 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemCryptoAsymmetricTest < TemTestCase
4
+ def i_crypt(data, key_id, authz, mode = :encrypt, direct_io = true, max_output = nil)
5
+ if max_output.nil?
6
+ max_output = case mode
7
+ when :encrypt
8
+ ((data.length + 239) / 240) * 256
9
+ when :decrypt
10
+ data.length
11
+ when :sign
12
+ 256
13
+ end
14
+ end
15
+
16
+ crypt_opcode = {:encrypt => :kefxb, :decrypt => :kdfxb, :sign => :ksfxb}[mode]
17
+ ex_sec = @tem.assemble { |s|
18
+ # buffer
19
+ s.ldwc :const => max_output
20
+ s.outnew
21
+ s.ldbc :const => key_id
22
+ s.authk :auth => :key_auth
23
+ s.send crypt_opcode, :from => :data, :size => data.length, :to => (direct_io ? 0xFFFF : :outdata)
24
+ s.outvlb :from => :outdata unless direct_io
25
+ s.halt
26
+
27
+ s.label :key_auth
28
+ s.data :tem_ubyte, authz
29
+ s.label :data
30
+ s.data :tem_ubyte, data
31
+ unless direct_io
32
+ s.label :outdata
33
+ s.zeros :tem_ubyte, max_output
34
+ end
35
+ s.stack 5
36
+ }
37
+ return @tem.execute(ex_sec)
38
+ end
39
+
40
+ def i_verify(data, signature, key_id, authz)
41
+ sign_sec = @tem.assemble { |s|
42
+ # buffer
43
+ s.ldbc :const => 1
44
+ s.outnew
45
+ s.ldbc :const => key_id
46
+ s.authk :auth => :key_auth
47
+ s.kvsfxb :from => :data, :size => data.length, :signature => :signature
48
+ s.outb
49
+ s.halt
50
+
51
+ s.label :key_auth
52
+ s.data :tem_ubyte, authz
53
+ s.label :data
54
+ s.data :tem_ubyte, data
55
+ s.label :signature
56
+ s.data :tem_ubyte, signature
57
+ s.stack 5
58
+ }
59
+ return @tem.execute(sign_sec)[0] == 1
60
+ end
61
+
62
+ def i_test_crypto_pki_ops(pubk_id, privk_id, pubk, privk, authz)
63
+ garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
64
+
65
+ # SEC/priv-sign + CPU/pub-verify, direct IO
66
+ signed_garbage = i_crypt garbage, privk_id, authz, :sign, true
67
+ assert privk.verify(garbage, signed_garbage),
68
+ 'SEC priv-signing + CPU pub-verify failed on good data'
69
+
70
+ # SEC/priv-sign + CPU/pub-verify, indirect IO
71
+ signed_garbage = i_crypt garbage, privk_id, authz, :sign, false
72
+ assert privk.verify(garbage, signed_garbage),
73
+ 'SEC priv-signing + CPU pub-verify failed on good data'
74
+
75
+ # CPU/priv-sign + SEC/pub-verify
76
+ signed_garbage = privk.sign garbage
77
+ assert i_verify(garbage, signed_garbage, pubk_id, authz),
78
+ 'CPU priv-signing + SEC pub-verify failed on good data'
79
+
80
+ # CPU/priv-encrypt + SEC/pub-decrypt, indirect IO
81
+ encrypted_garbage = privk.encrypt garbage
82
+ decrypted_garbage = i_crypt encrypted_garbage, pubk_id, authz, :decrypt,
83
+ false
84
+ assert_equal garbage, decrypted_garbage,
85
+ 'SEC priv-encryption + CPU pub-decryption messed up the data'
86
+
87
+ # SEC/pub-encrypt + CPU/priv-decrypt, indirect IO
88
+ encrypted_garbage = i_crypt garbage, pubk_id, authz, :encrypt, false
89
+ decrypted_garbage = privk.decrypt encrypted_garbage
90
+ assert_equal garbage, decrypted_garbage,
91
+ 'SEC priv-encryption + CPU pub-decryption messed up the data'
92
+
93
+ # CPU/pub-encrypt + SEC/priv-decrypt, direct-IO
94
+ encrypted_garbage = pubk.encrypt garbage
95
+ decrypted_garbage = i_crypt encrypted_garbage, privk_id, authz, :decrypt,
96
+ true
97
+ assert_equal garbage, decrypted_garbage,
98
+ 'CPU pub-encryption + SEC priv-decryption messed up the data'
99
+
100
+ # SEC/priv-encrypt + CPU/pub-decrypt, direct-IO
101
+ encrypted_garbage = i_crypt garbage, privk_id, authz, :encrypt, true
102
+ decrypted_garbage = pubk.decrypt encrypted_garbage
103
+ assert_equal garbage, decrypted_garbage,
104
+ 'SEC priv-encryption + CPU pub-decryption messed up the data'
105
+ end
106
+
107
+ def test_crypto_asymmetric
108
+ # crypto run with an internally generated key
109
+ keyd = @tem.tk_gen_key :asymmetric
110
+ pubk = @tem.tk_read_key keyd[:pubk_id], keyd[:authz]
111
+ privk = @tem.tk_read_key keyd[:privk_id], keyd[:authz]
112
+ i_test_crypto_pki_ops keyd[:pubk_id], keyd[:privk_id], pubk, privk,
113
+ keyd[:authz]
114
+
115
+ # crypto run with an externally generated key
116
+ ekey = OpenSSL::PKey::RSA.generate(2048, 65537)
117
+ pubk = Tem::Key.new_from_ssl_key ekey.public_key
118
+ privk = Tem::Key.new_from_ssl_key ekey
119
+ pubk_id = @tem.tk_post_key pubk, keyd[:authz]
120
+ privk_id = @tem.tk_post_key privk, keyd[:authz]
121
+ i_test_crypto_pki_ops pubk_id, privk_id, pubk, privk, keyd[:authz]
122
+ end
123
+ end
@@ -0,0 +1,35 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemCryptoHashTest < TemTestCase
4
+ def test_crypto_hash
5
+ garbage1 = (0...8).map { |x| (31 * x * x + 5 * x + 3) % 256 }
6
+ garbage2 = (0...11).map { |x| (69 * x * x + 62 * x + 10) % 256 }
7
+ hash_size = 20
8
+
9
+ sec = @tem.assemble { |s|
10
+ s.ldwc hash_size * 3
11
+ s.outnew
12
+ s.mdfxb :size => garbage1.length, :from => :garbage1, :to => :hash_area
13
+ s.outfxb :size => hash_size, :from => :hash_area
14
+ s.mdfxb :size => garbage2.length, :from => :garbage2, :to => 0xFFFF
15
+ s.ldwc garbage2.length
16
+ s.ldwc :garbage2
17
+ s.ldwc :hash_area
18
+ s.mdvb
19
+ s.outfxb :size => hash_size, :from => :hash_area
20
+ s.halt
21
+ s.label :garbage1
22
+ s.data :tem_ubyte, garbage1
23
+ s.label :garbage2
24
+ s.data :tem_ubyte, garbage2
25
+ s.label :hash_area
26
+ s.zeros :tem_ubyte, hash_size
27
+ s.stack 5
28
+ }
29
+
30
+ result = @tem.execute sec
31
+ assert_equal [garbage1, garbage2, garbage2].map { |d| @tem.tem_hash d}.
32
+ flatten,
33
+ result, 'cryptographic hashing isn\'t working well'
34
+ end
35
+ end
@@ -0,0 +1,53 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemCryptoPstoreTest < TemTestCase
4
+ def test_crypto_pstore
5
+ addr1 = (0...(@tem.tem_ps_addr_length)).map { |x| (61 * x * x + 62 * x + 10) % 256 }
6
+ addr2 = addr1.dup; addr2[addr2.length - 1] += 1
7
+ random_value = (0...(@tem.tem_ps_value_length)).map { |x| (69 * x * x + 62 * x + 10) % 256 }
8
+
9
+ sec = @tem.assemble { |s|
10
+ s.ldwc 3 * @tem.tem_ushort_length + @tem.tem_ps_value_length * 2
11
+ s.outnew
12
+
13
+ # check that the location is blank
14
+ s.ldwc :pstore_addr
15
+ s.pshkvb
16
+ s.outw
17
+
18
+ # write to create the location
19
+ s.pswrfxb :addr => :pstore_addr, :from => :s_value
20
+ # check that the location isn't blank anymore
21
+ s.pshkfxb :addr => :pstore_addr
22
+ s.outw
23
+ # re-read (should get what was written)
24
+ s.ldwc :pstore_addr
25
+ s.ldwc :s_value2
26
+ s.psrdvb
27
+ s.ldwc :s_value2
28
+ s.outvb
29
+
30
+ # drop the location
31
+ s.ldwc :pstore_addr
32
+ s.dupn :n => 1
33
+ s.psrm
34
+ # check that the location is blank again
35
+ s.pshkvb
36
+ s.outw
37
+
38
+ s.halt
39
+
40
+ s.label :pstore_addr
41
+ s.data :tem_ubyte, addr1
42
+ s.label :s_value
43
+ s.data :tem_ubyte, random_value
44
+ s.label :s_value2
45
+ s.zeros :tem_ps_value
46
+ s.stack 8
47
+ }
48
+ expected = @tem.to_tem_ushort(0) + @tem.to_tem_ushort(1) + random_value +
49
+ @tem.to_tem_ushort(0)
50
+ result = @tem.execute sec
51
+ assert_equal expected, result, 'persistent store locations aren\'t working well'
52
+ end
53
+ end
@@ -0,0 +1,25 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemCryptoRandomTest < TemTestCase
4
+ def test_crypto_random
5
+ sec = @tem.assemble { |s|
6
+ s.ldbc 16
7
+ s.outnew
8
+ s.ldbc 8
9
+ s.dupn :n => 1
10
+ s.ldwc :rnd_area
11
+ s.dupn :n => 2
12
+ s.rnd
13
+ s.outvb
14
+ s.ldbc(-1)
15
+ s.rnd
16
+ s.halt
17
+ s.label :rnd_area
18
+ s.zeros :tem_ubyte, 8
19
+ s.stack 5
20
+ }
21
+
22
+ result = @tem.execute sec
23
+ assert_equal 16, result.length, 'monotonic counters aren\'t working well'
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemEmitTest < TemTestCase
4
+ def test_emit
5
+ # try to emit
6
+ er = @tem.emit
7
+ assert er != nil, 'TEM emitting failed'
8
+
9
+ # now verify that the private key is good and the authorization matches
10
+ privek = @tem.tk_read_key 0, er[:privek_auth]
11
+ assert((not privek.is_public?), 'TEM emission failed to produce a proper PrivEK')
12
+
13
+ # verify that the public key can be read from the ECert
14
+ pubek = @tem.pubek
15
+ assert pubek.is_public?, 'TEM emission failed to produce a proper PubEK'
16
+
17
+ # verify the PrivEK against the ECert
18
+ ecert = @tem.endorsement_cert
19
+ ecert.verify privek.ssl_key
20
+
21
+ @tem.tk_delete_key 0, er[:privek_auth]
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemMemoryTest < TemTestCase
4
+ def test_memory
5
+ sec = @tem.assemble { |s|
6
+ s.label :clobber
7
+ s.ldbc 32
8
+ s.label :clobber2
9
+ s.outnew
10
+ s.ldwc 0x55AA
11
+ s.stw :clobber
12
+ s.ldb :clobber
13
+ s.outw
14
+ s.ldw :clobber
15
+ s.outw
16
+ s.ldbc 0xA5 - (1 << 8)
17
+ s.stb :clobber
18
+ s.ldw :clobber
19
+ s.outw
20
+ s.ldwc :clobber2
21
+ s.dupn :n => 1
22
+ s.dupn :n => 2
23
+ s.ldwc 0x9966 - (1 << 16)
24
+ s.stwv
25
+ s.ldbv
26
+ s.outw
27
+ s.ldbc 0x98 - (1 << 8)
28
+ s.stbv
29
+ s.ldwv
30
+ s.outw
31
+ s.ldwc 0x1122
32
+ s.ldwc 0x3344
33
+ s.ldwc 0x5566
34
+ s.flipn :n => 3
35
+ s.outw
36
+ s.outw
37
+ s.outw
38
+ s.halt
39
+ # Test stack without arguments.
40
+ s.stack
41
+ s.zeros :tem_short, 5
42
+ }
43
+ result = @tem.execute sec
44
+ assert_equal [0x00, 0x55, 0x55, 0xAA, 0xA5, 0xAA, 0xFF, 0x99, 0x98, 0x66,
45
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66],
46
+ result, 'the memory unit isn\'t working well'
47
+ end
48
+ end