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.
- data/CHANGELOG +45 -0
- data/LICENSE +21 -0
- data/Manifest +75 -0
- data/README +8 -0
- data/Rakefile +23 -0
- data/bin/tem_bench +9 -0
- data/bin/tem_ca +13 -0
- data/bin/tem_irb +11 -0
- data/bin/tem_proxy +65 -0
- data/bin/tem_stat +35 -0
- data/dev_ca/ca_cert.cer +0 -0
- data/dev_ca/ca_cert.pem +32 -0
- data/dev_ca/ca_key.pem +27 -0
- data/dev_ca/config.yml +14 -0
- data/lib/tem/_cert.rb +158 -0
- data/lib/tem/apdus/buffers.rb +89 -0
- data/lib/tem/apdus/keys.rb +64 -0
- data/lib/tem/apdus/lifecycle.rb +13 -0
- data/lib/tem/apdus/tag.rb +38 -0
- data/lib/tem/auto_conf.rb +25 -0
- data/lib/tem/builders/abi.rb +482 -0
- data/lib/tem/builders/assembler.rb +314 -0
- data/lib/tem/builders/crypto.rb +124 -0
- data/lib/tem/builders/isa.rb +120 -0
- data/lib/tem/ca.rb +114 -0
- data/lib/tem/definitions/abi.rb +65 -0
- data/lib/tem/definitions/assembler.rb +23 -0
- data/lib/tem/definitions/isa.rb +188 -0
- data/lib/tem/ecert.rb +77 -0
- data/lib/tem/hive.rb +18 -0
- data/lib/tem/keys/asymmetric.rb +116 -0
- data/lib/tem/keys/key.rb +48 -0
- data/lib/tem/keys/symmetric.rb +47 -0
- data/lib/tem/sec_exec_error.rb +63 -0
- data/lib/tem/seclosures.rb +81 -0
- data/lib/tem/secpack.rb +107 -0
- data/lib/tem/tem.rb +31 -0
- data/lib/tem/toolkit.rb +101 -0
- data/lib/tem/transport/auto_configurator.rb +87 -0
- data/lib/tem/transport/java_card_mixin.rb +99 -0
- data/lib/tem/transport/jcop_remote_protocol.rb +59 -0
- data/lib/tem/transport/jcop_remote_server.rb +171 -0
- data/lib/tem/transport/jcop_remote_transport.rb +65 -0
- data/lib/tem/transport/pcsc_transport.rb +87 -0
- data/lib/tem/transport/transport.rb +10 -0
- data/lib/tem_ruby.rb +47 -0
- data/tem_ruby.gemspec +35 -0
- data/test/_test_cert.rb +70 -0
- data/test/builders/test_abi_builder.rb +298 -0
- data/test/tem_test_case.rb +26 -0
- data/test/tem_unit/test_tem_alu.rb +33 -0
- data/test/tem_unit/test_tem_bound_secpack.rb +51 -0
- data/test/tem_unit/test_tem_branching.rb +56 -0
- data/test/tem_unit/test_tem_crypto_asymmetric.rb +123 -0
- data/test/tem_unit/test_tem_crypto_hash.rb +35 -0
- data/test/tem_unit/test_tem_crypto_pstore.rb +53 -0
- data/test/tem_unit/test_tem_crypto_random.rb +25 -0
- data/test/tem_unit/test_tem_emit.rb +23 -0
- data/test/tem_unit/test_tem_memory.rb +48 -0
- data/test/tem_unit/test_tem_memory_compare.rb +65 -0
- data/test/tem_unit/test_tem_output.rb +32 -0
- data/test/tem_unit/test_tem_yaml_secpack.rb +47 -0
- data/test/test_driver.rb +108 -0
- data/test/test_exceptions.rb +35 -0
- data/test/transport/test_auto_configurator.rb +114 -0
- data/test/transport/test_java_card_mixin.rb +90 -0
- data/test/transport/test_jcop_remote.rb +82 -0
- data/timings/blank_bound_secpack.rb +18 -0
- data/timings/blank_sec.rb +14 -0
- data/timings/devchip_decrypt.rb +9 -0
- data/timings/post_buffer.rb +10 -0
- data/timings/simple_apdu.rb +5 -0
- data/timings/timings.rb +64 -0
- data/timings/vm_perf.rb +140 -0
- data/timings/vm_perf_bound.rb +141 -0
- 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
|
data/test/test_driver.rb
ADDED
@@ -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
|