costan-tem_ruby 0.10.2

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 (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