tem_ruby 0.9.2 → 0.10.0
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 +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
|