tem_ruby 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/Manifest +47 -36
- data/Rakefile +23 -0
- data/bin/tem_bench +0 -0
- data/bin/tem_ca +0 -0
- data/bin/tem_irb +1 -8
- data/bin/tem_proxy +65 -0
- data/bin/tem_stat +8 -12
- data/dev_ca/config.yml +2 -0
- data/lib/tem/auto_conf.rb +25 -0
- data/lib/tem/buffers.rb +21 -34
- data/lib/tem/crypto_abi.rb +78 -30
- data/lib/tem/keys.rb +21 -22
- data/lib/tem/lifecycle.rb +2 -2
- data/lib/tem/seclosures.rb +9 -13
- data/lib/tem/tag.rb +19 -14
- data/lib/tem/tem.rb +9 -25
- 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 +51 -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 +12 -4
- data/tem_ruby.gemspec +24 -40
- data/test/_test_cert.rb +2 -13
- data/test/tem_test_case.rb +26 -0
- data/test/test_driver.rb +3 -22
- data/test/test_exceptions.rb +3 -22
- data/test/test_tem.rb +2 -21
- 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/timings.rb +2 -9
- metadata +94 -62
- data/lib/scard/java_card.rb +0 -31
- data/lib/scard/jcop_remote_terminal.rb +0 -52
- data/lib/scard/pcsc_terminal.rb +0 -83
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'smartcard'
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tem::Transport
|
6
|
+
|
7
|
+
class PcscTransport
|
8
|
+
include JavaCardMixin
|
9
|
+
PCSC = Smartcard::PCSC
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
@options = options
|
13
|
+
@context = nil
|
14
|
+
@card = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def exchange_apdu(apdu)
|
18
|
+
xmit_apdu_string = apdu.pack('C*')
|
19
|
+
result_string = @card.transmit xmit_apdu_string, @xmit_ioreq, @recv_ioreq
|
20
|
+
return result_string.unpack('C*')
|
21
|
+
end
|
22
|
+
|
23
|
+
def connect
|
24
|
+
@context = PCSC::Context.new(PCSC::SCOPE_SYSTEM) if @context.nil?
|
25
|
+
|
26
|
+
if @options[:reader_name]
|
27
|
+
@reader_name = reader_name
|
28
|
+
else
|
29
|
+
# get the first reader
|
30
|
+
readers = @context.list_readers nil
|
31
|
+
@reader_name = readers[@options[:reader_index] || 0]
|
32
|
+
end
|
33
|
+
|
34
|
+
# get the reader's status
|
35
|
+
reader_states = PCSC::ReaderStates.new(1)
|
36
|
+
reader_states.set_reader_name_of!(0, @reader_name)
|
37
|
+
reader_states.set_current_state_of!(0, PCSC::STATE_UNKNOWN)
|
38
|
+
@context.get_status_change reader_states, 100
|
39
|
+
reader_states.acknowledge_events!
|
40
|
+
|
41
|
+
# prompt for card insertion unless that already happened
|
42
|
+
if (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0
|
43
|
+
puts "Please insert TEM card in reader #{@reader_name}\n"
|
44
|
+
while (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0 do
|
45
|
+
@context.get_status_change reader_states, PCSC::INFINITE_TIMEOUT
|
46
|
+
reader_states.acknowledge_events!
|
47
|
+
end
|
48
|
+
puts "Card detected\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
# connect to card
|
52
|
+
@card = PCSC::Card.new @context, @reader_name, PCSC::SHARE_EXCLUSIVE,
|
53
|
+
PCSC::PROTOCOL_ANY
|
54
|
+
|
55
|
+
# build the transmit / receive IoRequests
|
56
|
+
status = @card.status
|
57
|
+
@xmit_ioreq = @@xmit_iorequest[status[:protocol]]
|
58
|
+
if RUBY_PLATFORM =~ /win/ and (not RUBY_PLATFORM =~ /darwin/)
|
59
|
+
@recv_ioreq = nil
|
60
|
+
else
|
61
|
+
@recv_ioreq = PCSC::IoRequest.new
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def disconnect
|
66
|
+
unless @card.nil?
|
67
|
+
@card.disconnect PCSC::DISPOSITION_LEAVE
|
68
|
+
@card = nil
|
69
|
+
end
|
70
|
+
unless @context.nil?
|
71
|
+
@context.release
|
72
|
+
@context = nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
"#<PC/SC Terminal: disconnected>" if @card.nil?
|
78
|
+
"#<PC/SC Terminal: #{@reader_name}>"
|
79
|
+
end
|
80
|
+
|
81
|
+
@@xmit_iorequest = {
|
82
|
+
Smartcard::PCSC::PROTOCOL_T0 => Smartcard::PCSC::IOREQUEST_T0,
|
83
|
+
Smartcard::PCSC::PROTOCOL_T1 => Smartcard::PCSC::IOREQUEST_T1,
|
84
|
+
}
|
85
|
+
end # class PcscTransport
|
86
|
+
|
87
|
+
end # module Tem::Transport
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# The transport module contains classes responsible for transferring low-level
|
2
|
+
# commands issed by the high-level TEM methods to actual TEMs, which can be
|
3
|
+
# connected to the system in various ways.
|
4
|
+
module Tem::Transport
|
5
|
+
|
6
|
+
# Shortcut for Tem::Transport::AutoConfigurator#auto_transport
|
7
|
+
def self.auto_transport
|
8
|
+
Tem::Transport::AutoConfigurator.auto_transport
|
9
|
+
end
|
10
|
+
end
|
data/lib/tem_ruby.rb
CHANGED
@@ -1,17 +1,25 @@
|
|
1
1
|
# gems
|
2
|
+
require 'rubygems'
|
2
3
|
require 'smartcard'
|
3
4
|
|
5
|
+
# :nodoc:
|
4
6
|
module Tem
|
5
7
|
end
|
6
8
|
|
7
|
-
|
9
|
+
# :nodoc:
|
10
|
+
module Tem::Transport
|
8
11
|
end
|
9
12
|
|
10
|
-
require '
|
11
|
-
require '
|
12
|
-
require '
|
13
|
+
require 'tem/transport/transport.rb'
|
14
|
+
require 'tem/transport/java_card_mixin.rb'
|
15
|
+
require 'tem/transport/pcsc_transport.rb'
|
16
|
+
require 'tem/transport/jcop_remote_protocol.rb'
|
17
|
+
require 'tem/transport/jcop_remote_transport.rb'
|
18
|
+
require 'tem/transport/jcop_remote_server.rb'
|
19
|
+
require 'tem/transport/auto_configurator.rb'
|
13
20
|
|
14
21
|
require 'tem/abi.rb'
|
22
|
+
require 'tem/auto_conf.rb'
|
15
23
|
require 'tem/buffers.rb'
|
16
24
|
require 'tem/ca.rb'
|
17
25
|
require 'tem/crypto_abi.rb'
|
data/tem_ruby.gemspec
CHANGED
@@ -1,55 +1,39 @@
|
|
1
|
-
|
2
|
-
# Gem::Specification for Tem_ruby-0.9.2
|
3
|
-
# Originally generated by Echoe
|
1
|
+
# -*- encoding: utf-8 -*-
|
4
2
|
|
5
3
|
Gem::Specification.new do |s|
|
6
4
|
s.name = %q{tem_ruby}
|
7
|
-
s.version = "0.
|
8
|
-
|
9
|
-
s.specification_version = 2 if s.respond_to? :specification_version=
|
5
|
+
s.version = "0.10.0"
|
10
6
|
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new(">=
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
12
8
|
s.authors = ["Victor Costan"]
|
13
|
-
s.date = %q{
|
9
|
+
s.date = %q{2009-04-08}
|
14
10
|
s.description = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
15
11
|
s.email = %q{victor@costan.us}
|
16
|
-
s.executables = ["
|
17
|
-
s.extra_rdoc_files = ["bin/
|
12
|
+
s.executables = ["tem_bench", "tem_ca", "tem_irb", "tem_proxy", "tem_stat"]
|
13
|
+
s.extra_rdoc_files = ["bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "CHANGELOG", "lib/tem/_cert.rb", "lib/tem/abi.rb", "lib/tem/auto_conf.rb", "lib/tem/buffers.rb", "lib/tem/ca.rb", "lib/tem/crypto_abi.rb", "lib/tem/ecert.rb", "lib/tem/hive.rb", "lib/tem/keys.rb", "lib/tem/lifecycle.rb", "lib/tem/sec_assembler.rb", "lib/tem/sec_exec_error.rb", "lib/tem/sec_opcodes.rb", "lib/tem/seclosures.rb", "lib/tem/secpack.rb", "lib/tem/tag.rb", "lib/tem/tem.rb", "lib/tem/toolkit.rb", "lib/tem/transport/auto_configurator.rb", "lib/tem/transport/java_card_mixin.rb", "lib/tem/transport/jcop_remote_protocol.rb", "lib/tem/transport/jcop_remote_server.rb", "lib/tem/transport/jcop_remote_transport.rb", "lib/tem/transport/pcsc_transport.rb", "lib/tem/transport/transport.rb", "lib/tem_ruby.rb", "LICENSE", "README"]
|
14
|
+
s.files = ["bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "CHANGELOG", "dev_ca/ca_cert.cer", "dev_ca/ca_cert.pem", "dev_ca/ca_key.pem", "dev_ca/config.yml", "lib/tem/_cert.rb", "lib/tem/abi.rb", "lib/tem/auto_conf.rb", "lib/tem/buffers.rb", "lib/tem/ca.rb", "lib/tem/crypto_abi.rb", "lib/tem/ecert.rb", "lib/tem/hive.rb", "lib/tem/keys.rb", "lib/tem/lifecycle.rb", "lib/tem/sec_assembler.rb", "lib/tem/sec_exec_error.rb", "lib/tem/sec_opcodes.rb", "lib/tem/seclosures.rb", "lib/tem/secpack.rb", "lib/tem/tag.rb", "lib/tem/tem.rb", "lib/tem/toolkit.rb", "lib/tem/transport/auto_configurator.rb", "lib/tem/transport/java_card_mixin.rb", "lib/tem/transport/jcop_remote_protocol.rb", "lib/tem/transport/jcop_remote_server.rb", "lib/tem/transport/jcop_remote_transport.rb", "lib/tem/transport/pcsc_transport.rb", "lib/tem/transport/transport.rb", "lib/tem_ruby.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/_test_cert.rb", "test/tem_test_case.rb", "test/test_driver.rb", "test/test_exceptions.rb", "test/test_tem.rb", "test/transport/test_auto_configurator.rb", "test/transport/test_java_card_mixin.rb", "test/transport/test_jcop_remote.rb", "timings/blank_bound_secpack.rb", "timings/blank_sec.rb", "timings/devchip_decrypt.rb", "timings/post_buffer.rb", "timings/simple_apdu.rb", "timings/timings.rb", "timings/vm_perf.rb", "timings/vm_perf_bound.rb", "tem_ruby.gemspec"]
|
18
15
|
s.has_rdoc = true
|
19
16
|
s.homepage = %q{http://tem.rubyforge.org}
|
20
17
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tem_ruby", "--main", "README"]
|
21
18
|
s.require_paths = ["lib"]
|
22
19
|
s.rubyforge_project = %q{tem}
|
23
|
-
s.rubygems_version = %q{1.
|
20
|
+
s.rubygems_version = %q{1.3.1}
|
24
21
|
s.summary = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
25
|
-
s.test_files = ["test/test_driver.rb", "test/test_tem.rb", "test/
|
22
|
+
s.test_files = ["test/test_driver.rb", "test/test_exceptions.rb", "test/test_tem.rb", "test/transport/test_auto_configurator.rb", "test/transport/test_java_card_mixin.rb", "test/transport/test_jcop_remote.rb"]
|
26
23
|
|
27
|
-
s.
|
28
|
-
|
24
|
+
if s.respond_to? :specification_version then
|
25
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
26
|
+
s.specification_version = 2
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
# p.email = 'victor@costan.us'
|
43
|
-
# p.summary = 'TEM (Trusted Execution Module) driver, written in and for ruby.'
|
44
|
-
# p.url = 'http://tem.rubyforge.org'
|
45
|
-
# p.dependencies = ['smartcard >=0.3.0']
|
46
|
-
#
|
47
|
-
# p.need_tar_gz = true
|
48
|
-
# p.need_zip = true
|
49
|
-
# p.rdoc_pattern = /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# if $0 == __FILE__
|
53
|
-
# Rake.application = Rake::Application.new
|
54
|
-
# Rake.application.run
|
55
|
-
# end
|
28
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
29
|
+
s.add_runtime_dependency(%q<smartcard>, [">= 0.3.0"])
|
30
|
+
s.add_development_dependency(%q<echoe>, [">= 0"])
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<smartcard>, [">= 0.3.0"])
|
33
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
34
|
+
end
|
35
|
+
else
|
36
|
+
s.add_dependency(%q<smartcard>, [">= 0.3.0"])
|
37
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
38
|
+
end
|
39
|
+
end
|
data/test/_test_cert.rb
CHANGED
@@ -26,23 +26,14 @@ require 'openssl'
|
|
26
26
|
|
27
27
|
class CertTest < Test::Unit::TestCase
|
28
28
|
def setup
|
29
|
-
@
|
30
|
-
unless @terminal.connect
|
31
|
-
@terminal.disconnect
|
32
|
-
@terminal = Tem::SCard::PCSCTerminal.new
|
33
|
-
@terminal.connect
|
34
|
-
end
|
35
|
-
@javacard = Tem::SCard::JavaCard.new(@terminal)
|
36
|
-
@tem = Tem::Session.new(@javacard)
|
29
|
+
@tem = Tem.auto_tem
|
37
30
|
|
38
31
|
@tem.kill
|
39
32
|
@tem.activate
|
40
|
-
|
41
|
-
|
42
33
|
end
|
43
34
|
|
44
35
|
def teardown
|
45
|
-
@
|
36
|
+
@tem.disconnect unless @tem.nil?
|
46
37
|
end
|
47
38
|
|
48
39
|
def test_cert
|
@@ -75,7 +66,5 @@ class CertTest < Test::Unit::TestCase
|
|
75
66
|
#The only way to set the signature is to sign the certificate, and only the issuer (manufacturer) can do this.
|
76
67
|
#This means that the manufacturer has to be contacted every time the user wants to verify the TEM's certificate,
|
77
68
|
#and this may not be practical.
|
78
|
-
|
79
|
-
|
80
69
|
end
|
81
70
|
end
|
@@ -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
|
data/test/test_driver.rb
CHANGED
@@ -1,25 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'test/unit'
|
1
|
+
require 'test/tem_test_case'
|
3
2
|
|
4
|
-
class DriverTest <
|
5
|
-
def setup
|
6
|
-
@terminal = Tem::SCard::JCOPRemoteTerminal.new
|
7
|
-
unless @terminal.connect
|
8
|
-
@terminal.disconnect
|
9
|
-
@terminal = Tem::SCard::PCSCTerminal.new
|
10
|
-
@terminal.connect
|
11
|
-
end
|
12
|
-
@javacard = Tem::SCard::JavaCard.new(@terminal)
|
13
|
-
@tem = Tem::Session.new(@javacard)
|
14
|
-
|
15
|
-
@tem.kill
|
16
|
-
@tem.activate
|
17
|
-
end
|
18
|
-
|
19
|
-
def teardown
|
20
|
-
@terminal.disconnect unless @terminal.nil?
|
21
|
-
end
|
22
|
-
|
3
|
+
class DriverTest < TemTestCase
|
23
4
|
def test_buffers_io
|
24
5
|
garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
25
6
|
|
@@ -73,7 +54,7 @@ class DriverTest < Test::Unit::TestCase
|
|
73
54
|
assert fwver[:major].kind_of?(Numeric) && fwver[:minor].kind_of?(Numeric), 'error in tag-backed firmware version'
|
74
55
|
end
|
75
56
|
|
76
|
-
def test_crypto
|
57
|
+
def test_crypto
|
77
58
|
garbage = (1...415).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
78
59
|
key_pair = @tem.devchip_generate_key_pair
|
79
60
|
pubkey = @tem.devchip_save_key key_pair[:pubkey_id]
|
data/test/test_exceptions.rb
CHANGED
@@ -1,25 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'test/unit'
|
1
|
+
require 'test/tem_test_case'
|
3
2
|
|
4
|
-
class ExceptionsTest <
|
5
|
-
def setup
|
6
|
-
@terminal = Tem::SCard::JCOPRemoteTerminal.new
|
7
|
-
unless @terminal.connect
|
8
|
-
@terminal.disconnect
|
9
|
-
@terminal = Tem::SCard::PCSCTerminal.new
|
10
|
-
@terminal.connect
|
11
|
-
end
|
12
|
-
@javacard = Tem::SCard::JavaCard.new(@terminal)
|
13
|
-
@tem = Tem::Session.new(@javacard)
|
14
|
-
|
15
|
-
@tem.kill
|
16
|
-
@tem.activate
|
17
|
-
end
|
18
|
-
|
19
|
-
def teardown
|
20
|
-
@terminal.disconnect unless @terminal.nil?
|
21
|
-
end
|
22
|
-
|
3
|
+
class ExceptionsTest < TemTestCase
|
23
4
|
def test_trace
|
24
5
|
# test the exception handling mechanism
|
25
6
|
bad_sec = @tem.assemble { |s|
|
@@ -52,4 +33,4 @@ class ExceptionsTest < Test::Unit::TestCase
|
|
52
33
|
end
|
53
34
|
assert caught, "Executing a bad SECpack did not raise a SecExecError"
|
54
35
|
end
|
55
|
-
end
|
36
|
+
end
|
data/test/test_tem.rb
CHANGED
@@ -1,25 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'test/unit'
|
1
|
+
require 'test/tem_test_case'
|
3
2
|
|
4
|
-
class TemTest <
|
5
|
-
def setup
|
6
|
-
@terminal = Tem::SCard::JCOPRemoteTerminal.new
|
7
|
-
unless @terminal.connect
|
8
|
-
@terminal.disconnect
|
9
|
-
@terminal = Tem::SCard::PCSCTerminal.new
|
10
|
-
@terminal.connect
|
11
|
-
end
|
12
|
-
@javacard = Tem::SCard::JavaCard.new(@terminal)
|
13
|
-
@tem = Tem::Session.new(@javacard)
|
14
|
-
|
15
|
-
@tem.kill
|
16
|
-
@tem.activate
|
17
|
-
end
|
18
|
-
|
19
|
-
def teardown
|
20
|
-
@terminal.disconnect unless @terminal.nil?
|
21
|
-
end
|
22
|
-
|
3
|
+
class TemTest < TemTestCase
|
23
4
|
def test_alu
|
24
5
|
sec = @tem.assemble { |s|
|
25
6
|
s.ldbc 10
|
@@ -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
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'flexmock/test_unit'
|
5
|
+
|
6
|
+
require 'tem_ruby'
|
7
|
+
|
8
|
+
# Tests JcopRemoteProtocol, JcopRemoteServer, and JcopRemoteTransport.
|
9
|
+
class JcopRemoteTest < Test::Unit::TestCase
|
10
|
+
Protocol = Tem::Transport::JcopRemoteProtocol
|
11
|
+
Server = Tem::Transport::JcopRemoteServer
|
12
|
+
Transport = Tem::Transport::JcopRemoteTransport
|
13
|
+
|
14
|
+
# Serving logic that records what it receives and replays a log.
|
15
|
+
class Logic
|
16
|
+
include Protocol
|
17
|
+
attr_reader :received
|
18
|
+
def initialize(responses)
|
19
|
+
@responses = responses
|
20
|
+
@received = []
|
21
|
+
end
|
22
|
+
def connection_start
|
23
|
+
@received << :start
|
24
|
+
end
|
25
|
+
def connection_end
|
26
|
+
@received << :end
|
27
|
+
end
|
28
|
+
def exchange_apdu(apdu)
|
29
|
+
@received << apdu
|
30
|
+
@responses.shift
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup
|
35
|
+
@server = Server.new(:ip => '127.0.0.1', :port => 51995)
|
36
|
+
@client = Transport.new :host => '127.0.0.1', :port => 51995
|
37
|
+
@old_abort_on_exception = Thread.abort_on_exception
|
38
|
+
Thread.abort_on_exception = true
|
39
|
+
end
|
40
|
+
|
41
|
+
def teardown
|
42
|
+
Thread.abort_on_exception = @old_abort_on_exception
|
43
|
+
@server.stop
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_apdu_exchange
|
47
|
+
apdu_request = [0x31, 0x41, 0x59, 0x26, 0x53]
|
48
|
+
apdu_response = [0x27, 0x90, 0x00]
|
49
|
+
|
50
|
+
logic = Logic.new([apdu_response])
|
51
|
+
Thread.new do
|
52
|
+
begin
|
53
|
+
@server.run logic
|
54
|
+
rescue Exception
|
55
|
+
print $!, "\n"
|
56
|
+
print $!.backtrace.join("\n")
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
end
|
60
|
+
Kernel.sleep 0.05 # Wait for the server to start up.
|
61
|
+
@client.connect
|
62
|
+
assert_equal apdu_response, @client.exchange_apdu(apdu_request)
|
63
|
+
@client.disconnect
|
64
|
+
Kernel.sleep 0.05 # Wait for the server to process the disconnect.
|
65
|
+
assert_equal [:start, apdu_request, :end], logic.received
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_java_card_integration
|
69
|
+
apdu_request = [0x00, 0x31, 0x41, 0x59, 0x00]
|
70
|
+
apdu_response = [0x27, 0x90, 0x00]
|
71
|
+
|
72
|
+
logic = Logic.new([apdu_response])
|
73
|
+
Thread.new { @server.run logic }
|
74
|
+
Kernel.sleep 0.05 # Wait for the server to start up.
|
75
|
+
@client.connect
|
76
|
+
assert_equal [0x27],
|
77
|
+
@client.applet_apdu!(:ins => 0x31, :p1 => 0x41, :p2 => 0x59)
|
78
|
+
@client.disconnect
|
79
|
+
Kernel.sleep 0.05 # Wait for the server to process the disconnect.
|
80
|
+
assert_equal [:start, apdu_request, :end], logic.received
|
81
|
+
end
|
82
|
+
end
|