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,65 @@
1
+ require 'test/tem_test_case'
2
+
3
+ module TemMemoryCompareTestCase
4
+ # This is also called from TemYamlSecpackTest.
5
+ def _test_memory_copy_compare(yaml_roundtrip = false)
6
+ sec = @tem.assemble { |s|
7
+ s.ldwc :const => 16
8
+ s.outnew
9
+ s.ldwc :const => 6
10
+ s.ldwc :cmp_med
11
+ s.ldwc :cmp_lo
12
+ s.mcmpvb
13
+ s.outw
14
+ s.mcmpfxb :size => 6, :op1 => :cmp_med, :op2 => :cmp_hi
15
+ s.outw
16
+ s.ldwc :const => 4
17
+ s.ldwc :cmp_lo
18
+ s.ldwc :cmp_med
19
+ s.mcmpvb
20
+ s.outw
21
+
22
+ s.mcfxb :size => 6, :from => :cmp_hi, :to => :copy_buf
23
+ s.pop
24
+ s.outfxb :size => 6, :from => :copy_buf
25
+ s.ldwc :const => 4
26
+ s.ldwc :cmp_hi
27
+ s.ldwc :copy_buf2
28
+ s.mcvb
29
+ s.pop
30
+ s.outfxb :size => 4, :from => :copy_buf2
31
+
32
+ s.halt
33
+ s.label :cmp_lo
34
+ s.data :tem_ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2C, 0x12]
35
+ s.label :cmp_med
36
+ s.data :tem_ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2D, 0x11]
37
+ s.label :cmp_hi
38
+ s.data :tem_ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2E, 0x10]
39
+ s.label :cmp_hi2
40
+ s.data :tem_ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2E, 0x10]
41
+ s.label :copy_buf
42
+ s.zeros :tem_ubyte, 6
43
+ s.label :copy_buf2
44
+ s.zeros :tem_ubyte, 4
45
+ s.stack 5
46
+ }
47
+
48
+ if yaml_roundtrip
49
+ # same test, except the SECpack is serialized/deserialized
50
+ yaml_sec = sec.to_yaml_str
51
+ sec = Tem::SecPack.new_from_yaml_str(yaml_sec)
52
+ end
53
+ result = @tem.execute sec
54
+ assert_equal [0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0xA3, 0x2C, 0x51, 0x63,
55
+ 0x2E, 0x10, 0xA3, 0x2C, 0x51, 0x63],
56
+ result, 'memory copy/compare isn\'t working well'
57
+ end
58
+ end
59
+
60
+ class TemMemoryCompareTest < TemTestCase
61
+ include TemMemoryCompareTestCase
62
+ def test_memory_copy_compare
63
+ _test_memory_copy_compare false
64
+ end
65
+ end
@@ -0,0 +1,32 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class TemOutputTest < TemTestCase
4
+ def test_output
5
+ sec = @tem.assemble { |s|
6
+ s.ldbc 32
7
+ s.outnew
8
+ s.outfxb :size => 3, :from => :area1
9
+ s.ldbc 5
10
+ s.outvlb :from => :area2
11
+ s.ldbc 4
12
+ s.ldwc :area3
13
+ s.outvb
14
+ s.ldwc 0x99AA - (1 << 16)
15
+ s.ldwc 0xFA55 - (1 << 16)
16
+ s.outb
17
+ s.outw
18
+ s.halt
19
+ s.label :area1
20
+ s.data :tem_ubyte, [0xFE, 0xCD, 0x9A]
21
+ s.label :area2
22
+ s.data :tem_ubyte, [0xAB, 0x95, 0xCE, 0xFD, 0x81]
23
+ s.label :area3
24
+ s.data :tem_ubyte, [0xEC, 0xDE, 0xAD, 0xCF]
25
+ s.stack 5
26
+ }
27
+ result = @tem.execute sec
28
+ assert_equal [0xFE, 0xCD, 0x9A, 0xAB, 0x95, 0xCE, 0xFD, 0x81, 0xEC, 0xDE,
29
+ 0xAD, 0xCF, 0x55, 0x99, 0xAA],
30
+ result, 'the output unit isn\'t working well'
31
+ end
32
+ end
@@ -0,0 +1,47 @@
1
+ require 'test/tem_test_case'
2
+
3
+ require 'test/tem_unit/test_tem_bound_secpack'
4
+ require 'test/tem_unit/test_tem_memory_compare'
5
+
6
+ class TemOutputTest < TemTestCase
7
+ include TemBoundSecpackTestCase
8
+ include TemMemoryCompareTestCase
9
+
10
+
11
+ def test_yaml_secpack
12
+ # simple test to ensure that the body is preserved
13
+ sec = @tem.assemble { |s|
14
+ s.ldbc 10
15
+ s.outnew
16
+ s.ldwc 0x1234
17
+ s.ldwc 0x5678
18
+ s.dupn :n => 2
19
+ s.add
20
+ s.outw
21
+ s.sub
22
+ s.outw
23
+ s.ldwc 0x0155
24
+ s.ldwc 0x02AA
25
+ s.mul
26
+ s.outw
27
+ s.ldwc 0x390C
28
+ s.ldwc 0x00AA
29
+ s.dupn :n => 2
30
+ s.div
31
+ s.outw
32
+ s.mod
33
+ s.outw
34
+ s.halt
35
+ s.stack 5
36
+ }
37
+ yaml_sec = sec.to_yaml_str
38
+ sec2 = Tem::SecPack.new_from_yaml_str(yaml_sec)
39
+ assert_equal sec.body, sec2.body,
40
+ 'SECpack body corrupted during serialization'
41
+
42
+ # re-run the memory test (reasonably large SECpack) to ensure that de-serialized SECpacks are equivalent to the originals
43
+ _test_memory_copy_compare true
44
+ # re-run the memory test (reasonably large SECpack) to ensure that serialization works on bound SECpacks
45
+ _test_bound_secpack true
46
+ end
47
+ end
@@ -0,0 +1,108 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class DriverTest < TemTestCase
4
+ def test_buffers_io
5
+ garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
6
+
7
+ bid = @tem.post_buffer garbage
8
+ assert_equal garbage.length, @tem.get_buffer_length(bid), 'error in posted buffer length'
9
+ assert_equal garbage, @tem.read_buffer(bid), 'error in posted buffer data'
10
+
11
+ garbage.reverse!
12
+ @tem.write_buffer bid, garbage
13
+ assert_equal garbage, @tem.read_buffer(bid), 'error in (reverted) posted buffer data'
14
+ @tem.release_buffer bid
15
+
16
+ @tem.post_buffer [1]
17
+ @tem.post_buffer [2]
18
+ @tem.flush_buffers
19
+ assert_equal 0, @tem.stat_buffers[:buffers].reject { |b| b[:free] }.length, 'flush_buffers left allocated buffers'
20
+ end
21
+
22
+ def test_buffers_alloc
23
+ b_lengths = [569, 231, 455, 18, 499, 332, 47]
24
+ b_ids = b_lengths.map { |len| @tem.alloc_buffer(len) }
25
+ bstat = @tem.stat_buffers
26
+
27
+ assert bstat[:free], 'buffer stat does not contain free memory information'
28
+ assert bstat[:free][:persistent].kind_of?(Numeric), 'buffer stat does not show free persistent memory'
29
+ assert bstat[:free][:persistent] >= 0, 'buffer stat shows negative free persistent memory'
30
+ assert bstat[:free][:clear_on_reset].kind_of?(Numeric), 'buffer stat does not show free clear_on_reset memory'
31
+ assert bstat[:free][:clear_on_reset] >= 0, 'buffer stat shows negative free clear_on_reset memory'
32
+ assert bstat[:free][:clear_on_deselect].kind_of?(Numeric), 'buffer stat does not show free clear_on_deselect memory'
33
+ assert bstat[:free][:clear_on_deselect] >= 0, 'buffer stat shows negative free clear_on_deselect memory'
34
+
35
+ b_lengths.each_index do |i|
36
+ assert bstat[:buffers][b_ids[i]], "buffer stat does not show an entry for a #{b_lengths[i]}-bytes buffer"
37
+ assert bstat[:buffers][b_ids[i]][:type].kind_of?(Symbol), "buffer stat does not show the memory type for a #{b_lengths[i]}-bytes buffer"
38
+ assert_equal b_lengths[i], bstat[:buffers][b_ids[i]][:length], "bad length in buffer stat entry for a #{b_lengths[i]}-bytes buffer"
39
+ assert_equal false, bstat[:buffers][b_ids[i]][:pinned], "bad pinned flag in buffer stat entry for a #{b_lengths[i]}-bytes buffer"
40
+ end
41
+
42
+ b_ids.each { |bid| @tem.release_buffer(bid) }
43
+ end
44
+
45
+ def test_tag
46
+ garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
47
+
48
+ assert_raise(RuntimeError, 'tag returned before being set') { @tem.get_tag }
49
+
50
+ @tem.set_tag(garbage)
51
+ assert_equal garbage, @tem.get_tag[2..-1], 'error in posted tag data'
52
+
53
+ fwver = @tem.tk_firmware_ver
54
+ assert fwver[:major].kind_of?(Numeric) && fwver[:minor].kind_of?(Numeric), 'error in tag-backed firmware version'
55
+ end
56
+
57
+ def test_crypto
58
+ garbage = (1...415).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
59
+ key_pair = @tem.devchip_generate_key_pair
60
+ pubkey = @tem.devchip_save_key key_pair[:pubkey_id]
61
+
62
+ encrypted_garbage = @tem.devchip_encrypt garbage, key_pair[:privkey_id]
63
+ decrypted_garbage = pubkey.decrypt encrypted_garbage
64
+ assert_equal garbage, decrypted_garbage, 'priv-encryption+pub-decryption messed up the data'
65
+
66
+ encrypted_garbage = pubkey.encrypt garbage
67
+ decrypted_garbage = @tem.devchip_decrypt encrypted_garbage, key_pair[:privkey_id]
68
+ assert_equal garbage, decrypted_garbage, 'pub-encryption+priv-decryption messed up the data'
69
+
70
+ key_stat = @tem.stat_keys
71
+ assert key_stat[:keys], 'key stat does not contain key information'
72
+ assert_equal :public, key_stat[:keys][key_pair[:pubkey_id]][:type], 'key stat reports wrong type for public key'
73
+ assert_equal :private, key_stat[:keys][key_pair[:privkey_id]][:type], 'key stat reports wrong type for private key'
74
+ assert_in_delta 2, 2048, key_stat[:keys][key_pair[:pubkey_id]][:bits], 'key stat reports wrong size for public key'
75
+ assert_in_delta 2, 2048, key_stat[:keys][key_pair[:privkey_id]][:bits], 'key stat reports wrong size for private key'
76
+
77
+ [:pubkey_id, :privkey_id].each { |ki| @tem.devchip_release_key key_pair[ki] }
78
+ end
79
+
80
+ def test_crypto_abi
81
+ ekey = OpenSSL::PKey::RSA.generate(2048, 65537)
82
+ pubk = Tem::Key.new_from_ssl_key ekey.public_key
83
+ privk = Tem::Key.new_from_ssl_key ekey
84
+
85
+ # array and string encryption/decryption
86
+ garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
87
+ [garbage, garbage.pack('C*')].each do |g|
88
+ encrypted_garbage = pubk.encrypt g
89
+ decrypted_garbage = privk.decrypt encrypted_garbage
90
+ assert_equal g, decrypted_garbage, 'pub-encryption+priv-decryption messed up the data'
91
+ encrypted_garbage = privk.encrypt g
92
+ decrypted_garbage = pubk.decrypt encrypted_garbage
93
+ assert_equal g, decrypted_garbage, 'priv-encryption+pub-decryption messed up the data'
94
+ end
95
+
96
+ # test key serialization/deserialization through encryption/decryption
97
+ pubk_ys = pubk.to_yaml_str
98
+ pubk2 = Tem::Keys::Asymmetric.new_from_yaml_str(pubk_ys)
99
+ privk_ys = privk.to_yaml_str
100
+ privk2 = Tem::Keys::Asymmetric.new_from_yaml_str(privk_ys)
101
+ encrypted_garbage = pubk.encrypt garbage
102
+ decrypted_garbage = privk2.decrypt encrypted_garbage
103
+ assert_equal garbage, decrypted_garbage, 'pub-encryption+priv-decryption messed up the data'
104
+ encrypted_garbage = privk.encrypt garbage
105
+ decrypted_garbage = pubk2.decrypt encrypted_garbage
106
+ assert_equal garbage, decrypted_garbage, 'priv-encryption+pub-decryption messed up the data'
107
+ end
108
+ end
@@ -0,0 +1,35 @@
1
+ require 'test/tem_test_case'
2
+
3
+ class ExceptionsTest < TemTestCase
4
+ def test_trace
5
+ # test the exception handling mechanism
6
+ bad_sec = @tem.assemble { |s|
7
+ s.ldbc 2
8
+ s.outnew
9
+ s.ldbc 6
10
+ s.outw
11
+ # this exceeds the address space, so it should make the TEM die
12
+ s.ldwc 0x7fff
13
+ s.ldbv
14
+ s.label :bad_code
15
+ s.halt
16
+ s.label :stack
17
+ s.stack 5
18
+ }
19
+ assert_raise(Tem::SecExecError) { @tem.execute bad_sec }
20
+
21
+ caught = false
22
+ begin
23
+ @tem.execute bad_sec
24
+ rescue Tem::SecExecError => e
25
+ caught = true
26
+ assert_equal Hash, e.trace.class, "TEM exception does not have a TEM trace"
27
+ assert_equal 2, e.trace[:out], "Bad output buffer position in TEM trace"
28
+ assert_equal bad_sec.label_address(:bad_code), e.trace[:ip], "Bad instruction pointer in TEM trace"
29
+ assert_equal bad_sec.label_address(:stack), e.trace[:sp], "Bad instruction pointer in TEM trace"
30
+ assert_equal Hash, e.buffer_state.class, "TEM exception does not have buffer state information"
31
+ assert_equal Hash, e.key_state.class, "TEM exception does not have key state information"
32
+ end
33
+ assert caught, "Executing a bad SECpack did not raise a SecExecError"
34
+ end
35
+ end
@@ -0,0 +1,114 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+ require 'flexmock/test_unit'
5
+
6
+ require 'tem_ruby'
7
+
8
+ class AutoConfiguratorTest < Test::Unit::TestCase
9
+ AutoConfigurator = Tem::Transport::AutoConfigurator
10
+ PcscTransport = Tem::Transport::PcscTransport
11
+ JcopRemoteTransport = Tem::Transport::JcopRemoteTransport
12
+
13
+ def setup
14
+ @env_var = AutoConfigurator::ENVIRONMENT_VARIABLE_NAME
15
+ end
16
+
17
+ def test_env_configuration_blank
18
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return(nil)
19
+ assert_equal nil, AutoConfigurator.env_configuration
20
+ end
21
+ def test_env_configuration_remote_port
22
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return(':6996')
23
+ conf = AutoConfigurator.env_configuration
24
+ assert_equal JcopRemoteTransport, conf[:class]
25
+ assert_equal({:host => '127.0.0.1', :port => 6996}, conf[:opts])
26
+ end
27
+ def test_env_configuration_remote_noport
28
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return(':')
29
+ conf = AutoConfigurator.env_configuration
30
+ assert_equal JcopRemoteTransport, conf[:class]
31
+ assert_equal({:host => '127.0.0.1', :port => 8050}, conf[:opts])
32
+ end
33
+ def test_env_configuration_remote_host_port
34
+ flexmock(ENV).should_receive(:[]).with(@env_var).
35
+ and_return('@moonstone:6996')
36
+ conf = AutoConfigurator.env_configuration
37
+ assert_equal JcopRemoteTransport, conf[:class]
38
+ assert_equal({:host => 'moonstone', :port => 6996}, conf[:opts])
39
+ end
40
+ def test_env_configuration_remote_host_noport
41
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return('@moonstone')
42
+ conf = AutoConfigurator.env_configuration
43
+ assert_equal JcopRemoteTransport, conf[:class]
44
+ assert_equal({:host => 'moonstone', :port => 8050}, conf[:opts])
45
+ end
46
+ def test_env_configuration_remote_ipv6_port
47
+ flexmock(ENV).should_receive(:[]).with(@env_var).
48
+ and_return('@ff80::0080:6996')
49
+ conf = AutoConfigurator.env_configuration
50
+ assert_equal JcopRemoteTransport, conf[:class]
51
+ assert_equal({:host => 'ff80::0080', :port => 6996}, conf[:opts])
52
+ end
53
+ def test_env_configuration_remote_ipv6_noport
54
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return('@ff80::0080:')
55
+ conf = AutoConfigurator.env_configuration
56
+ assert_equal JcopRemoteTransport, conf[:class]
57
+ assert_equal({:host => 'ff80::0080', :port => 8050}, conf[:opts])
58
+ end
59
+
60
+ def test_env_configuration_pcsc_reader_index
61
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return('#1')
62
+ conf = AutoConfigurator.env_configuration
63
+ assert_equal PcscTransport, conf[:class]
64
+ assert_equal({:reader_index => 0}, conf[:opts])
65
+ end
66
+ def test_env_configuration_pcsc_reader_name
67
+ reader_name = 'Awesome Reader'
68
+ flexmock(ENV).should_receive(:[]).with(@env_var).
69
+ and_return(reader_name)
70
+ conf = AutoConfigurator.env_configuration
71
+ assert_equal PcscTransport, conf[:class]
72
+ assert_equal({:reader_name => reader_name}, conf[:opts])
73
+ end
74
+
75
+ def test_try_transport
76
+ transport = Object.new
77
+ flexmock(PcscTransport).should_receive(:new).with(:reader_index => 1).
78
+ and_return(transport)
79
+ flexmock(transport).should_receive(:connect)
80
+ flexmock(PcscTransport).should_receive(:new).with(:reader_index => 2).
81
+ and_raise('Boom headshot')
82
+ failport = Object.new
83
+ flexmock(PcscTransport).should_receive(:new).with(:reader_index => 3).
84
+ and_return(failport)
85
+ flexmock(failport).should_receive(:connect).and_raise('Lag')
86
+
87
+ config = { :class => PcscTransport, :opts => {:reader_index => 1} }
88
+ assert_equal transport, AutoConfigurator.try_transport(config)
89
+ config = { :class => PcscTransport, :opts => {:reader_index => 2} }
90
+ assert_equal nil, AutoConfigurator.try_transport(config)
91
+ config = { :class => PcscTransport, :opts => {:reader_index => 3} }
92
+ assert_equal nil, AutoConfigurator.try_transport(config)
93
+ end
94
+
95
+ def test_auto_transport_uses_env
96
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return('#1')
97
+ transport = Object.new
98
+ flexmock(PcscTransport).should_receive(:new).with(:reader_index => 0).
99
+ and_return(transport)
100
+ flexmock(transport).should_receive(:connect)
101
+
102
+ assert_equal transport, AutoConfigurator.auto_transport
103
+ end
104
+
105
+ def test_auto_transport_with_defaults
106
+ flexmock(ENV).should_receive(:[]).with(@env_var).and_return(nil)
107
+ transport = Object.new
108
+ flexmock(JcopRemoteTransport).should_receive(:new).and_return(nil)
109
+ flexmock(PcscTransport).should_receive(:new).and_return(transport)
110
+ flexmock(transport).should_receive(:connect)
111
+
112
+ assert_equal transport, AutoConfigurator.auto_transport
113
+ end
114
+ end
@@ -0,0 +1,90 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+ require 'flexmock/test_unit'
5
+
6
+ require 'tem_ruby'
7
+
8
+ class JavaCardMixinTest < Test::Unit::TestCase
9
+ JavaCardMixin = Tem::Transport::JavaCardMixin
10
+
11
+ # The sole purpose of this class is wrapping the mixin under test.
12
+ class MixinWrapper
13
+ include JavaCardMixin
14
+ end
15
+
16
+ def setup
17
+ end
18
+
19
+ def test_serialize_apdu
20
+ s = lambda { |apdu| JavaCardMixin.serialize_apdu apdu }
21
+
22
+ assert_equal [0x00, 0x05, 0x00, 0x00, 0x00], s[:ins => 0x05],
23
+ 'Specified INS'
24
+ assert_equal [0x00, 0x09, 0x00, 0x01, 0x00], s[:ins => 0x09, :p2 => 0x01],
25
+ 'Specified INS and P2'
26
+ assert_equal [0x00, 0xF9, 0xAC, 0xEF, 0x00],
27
+ s[:ins => 0xF9, :p1 => 0xAC, :p2 => 0xEF],
28
+ 'Specified INS, P1, P2'
29
+ assert_equal [0x00, 0xFA, 0xAD, 0xEC, 0x00],
30
+ s[:ins => 0xFA, :p12 => [0xAD, 0xEC]],
31
+ 'Specified INS, P1+P2'
32
+ assert_equal [0x00, 0x0E, 0x00, 0x00, 0x04, 0x33, 0x95, 0x81, 0x63],
33
+ s[:ins => 0x0E, :data => [0x33, 0x95, 0x81, 0x63]],
34
+ 'Specified INS and DATA'
35
+ assert_equal [0x80, 0x0F, 0xBA, 0xBE, 0x03, 0x31, 0x41, 0x59],
36
+ s[:cla => 0x80, :ins => 0x0F, :p1 => 0xBA, :p2 => 0xBE,
37
+ :data => [0x31, 0x41, 0x59]],
38
+ 'Specified everything'
39
+ assert_raise(RuntimeError, 'Did not specify INS') do
40
+ s[:cla => 0x80, :p1 => 0xBA, :p2 => 0xBE, :data => [0x31, 0x41, 0x59]]
41
+ end
42
+ end
43
+
44
+ def test_deserialize_response
45
+ d = lambda { |response| JavaCardMixin.deserialize_response response }
46
+
47
+ assert_equal({ :status => 0x9000, :data => [] }, d[[0x90, 0x00]])
48
+ assert_equal({ :status => 0x8631, :data => [] }, d[[0x86, 0x31]])
49
+ assert_equal({ :status => 0x9000, :data => [0x31, 0x41, 0x59, 0x26] },
50
+ d[[0x31, 0x41, 0x59, 0x26, 0x90, 0x00]])
51
+ assert_equal({ :status => 0x7395, :data => [0x31, 0x41, 0x59, 0x26] },
52
+ d[[0x31, 0x41, 0x59, 0x26, 0x73, 0x95]])
53
+ end
54
+
55
+ def win_mock
56
+ mock = MixinWrapper.new
57
+ flexmock(mock).should_receive(:exchange_apdu).
58
+ with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41]).
59
+ and_return([0x67, 0x31, 0x90, 0x00])
60
+ mock
61
+ end
62
+ def win_apdu
63
+ {:ins => 0xF9, :p1 => 0xAC, :data => [0x31, 0x41]}
64
+ end
65
+
66
+ def lose_mock
67
+ mock = MixinWrapper.new
68
+ flexmock(mock).should_receive(:exchange_apdu).
69
+ with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41]).
70
+ and_return([0x86, 0x31])
71
+ mock
72
+ end
73
+ def lose_apdu
74
+ win_apdu
75
+ end
76
+
77
+ def test_applet_apdu
78
+ assert_equal({:status => 0x9000, :data => [0x67, 0x31]},
79
+ win_mock.applet_apdu(win_apdu))
80
+ assert_equal({:status => 0x8631, :data => []},
81
+ lose_mock.applet_apdu(lose_apdu))
82
+ end
83
+
84
+ def test_applet_apdu_bang
85
+ assert_equal [0x67, 0x31], win_mock.applet_apdu!(win_apdu)
86
+ assert_raise(RuntimeError) do
87
+ lose_mock.applet_apdu!(lose_apdu)
88
+ end
89
+ end
90
+ end