costan-tem_ruby 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|