tem_ruby 0.11.3 → 0.11.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/Manifest +1 -10
- data/Rakefile +1 -1
- data/bin/tem_proxy +4 -4
- data/lib/tem/apdus/buffers.rb +15 -8
- data/lib/tem/apdus/keys.rb +11 -5
- data/lib/tem/apdus/lifecycle.rb +10 -3
- data/lib/tem/apdus/tag.rb +10 -3
- data/lib/tem/auto_conf.rb +8 -5
- data/lib/tem/benchmarks/benchmarks.rb +7 -0
- data/lib/tem/benchmarks/blank_bound_secpack.rb +10 -0
- data/lib/tem/benchmarks/blank_sec.rb +14 -0
- data/lib/tem/benchmarks/devchip_decrypt.rb +12 -0
- data/lib/tem/benchmarks/post_buffer.rb +8 -0
- data/lib/tem/benchmarks/simple_apdu.rb +11 -0
- data/lib/tem/benchmarks/vm_perf.rb +11 -0
- data/lib/tem/benchmarks/vm_perf_bound.rb +12 -0
- data/lib/tem/builders/abi.rb +19 -13
- data/lib/tem/builders/assembler.rb +23 -16
- data/lib/tem/builders/crypto.rb +9 -3
- data/lib/tem/builders/isa.rb +10 -4
- data/lib/tem/definitions/abi.rb +9 -0
- data/lib/tem/definitions/assembler.rb +10 -0
- data/lib/tem/definitions/isa.rb +10 -0
- data/lib/tem/seclosures.rb +5 -5
- data/lib/tem/tem.rb +2 -1
- data/lib/tem_ruby.rb +0 -12
- data/tem_ruby.gemspec +9 -9
- data/test/builders/test_abi_builder.rb +4 -2
- data/test/tem_test_case.rb +3 -2
- data/test/tem_unit/test_tem_alu.rb +1 -1
- data/test/tem_unit/test_tem_bound_secpack.rb +1 -1
- data/test/tem_unit/test_tem_branching.rb +1 -1
- data/test/tem_unit/test_tem_crypto_asymmetric.rb +1 -1
- data/test/tem_unit/test_tem_crypto_hash.rb +1 -1
- data/test/tem_unit/test_tem_crypto_pstore.rb +1 -1
- data/test/tem_unit/test_tem_crypto_random.rb +1 -1
- data/test/tem_unit/test_tem_emit.rb +1 -1
- data/test/tem_unit/test_tem_memory.rb +1 -1
- data/test/tem_unit/test_tem_memory_compare.rb +1 -1
- data/test/tem_unit/test_tem_output.rb +1 -1
- data/test/tem_unit/test_tem_yaml_secpack.rb +4 -3
- data/test/test_auto_conf.rb +2 -0
- data/test/test_driver.rb +2 -1
- data/test/test_exceptions.rb +12 -6
- metadata +5 -24
- data/lib/tem/transport/auto_configurator.rb +0 -87
- data/lib/tem/transport/java_card_mixin.rb +0 -99
- data/lib/tem/transport/jcop_remote_protocol.rb +0 -59
- data/lib/tem/transport/jcop_remote_server.rb +0 -171
- data/lib/tem/transport/jcop_remote_transport.rb +0 -65
- data/lib/tem/transport/pcsc_transport.rb +0 -87
- data/lib/tem/transport/transport.rb +0 -10
- data/test/transport/test_auto_configurator.rb +0 -114
- data/test/transport/test_java_card_mixin.rb +0 -90
- data/test/transport/test_jcop_remote.rb +0 -82
@@ -1,59 +0,0 @@
|
|
1
|
-
# :nodoc: namespace
|
2
|
-
module Tem::Transport
|
3
|
-
|
4
|
-
# Mixin implementing the JCOP simulator protocol.
|
5
|
-
#
|
6
|
-
# The (pretty informal) protocol specification is contained in the JavaDocs for
|
7
|
-
# the class com.ibm.jc.terminal.RemoteJCTerminal and should be easy to find by
|
8
|
-
# http://www.google.com/search?q=%22com.ibm.jc.terminal.RemoteJCTerminal%22
|
9
|
-
module JcopRemoteProtocol
|
10
|
-
# Encodes and sends a JCOP simulator message to a TCP socket.
|
11
|
-
#
|
12
|
-
# The message must contain the following keys:
|
13
|
-
# type:: Integer expressing the message type (e.g. 1 = APDU exchange)
|
14
|
-
# node:: Integer expressing the node address (e.g. 0 for most purposes)
|
15
|
-
# data:: message payload, as an array of Integers ranging from 0 to 255
|
16
|
-
def send_message(socket, message)
|
17
|
-
raw_message = [message[:type], message[:node], message[:data].length].
|
18
|
-
pack('CCn') + message[:data].pack('C*')
|
19
|
-
socket.send raw_message, 0
|
20
|
-
end
|
21
|
-
|
22
|
-
# Reads and decodes a JCOP simulator message from a TCP socket.
|
23
|
-
#
|
24
|
-
# :call_seq:
|
25
|
-
# client.read_message(socket) -> Hash or nil
|
26
|
-
#
|
27
|
-
# If the other side of the TCP socket closes the connection, this method
|
28
|
-
# returns nil. Otherwise, a Hash is returned, with the format required by the
|
29
|
-
# JcopRemoteProtocol#send_message.
|
30
|
-
def recv_message(socket)
|
31
|
-
header = ''
|
32
|
-
while header.length < 4
|
33
|
-
begin
|
34
|
-
partial = socket.recv 4 - header.length
|
35
|
-
rescue # Abrupt hangups result in exceptions that we catch here.
|
36
|
-
return nil
|
37
|
-
end
|
38
|
-
return false if partial.length == 0
|
39
|
-
header += partial
|
40
|
-
end
|
41
|
-
message_type, node_address, data_length = *header.unpack('CCn')
|
42
|
-
raw_data = ''
|
43
|
-
while raw_data.length < data_length
|
44
|
-
begin
|
45
|
-
partial = socket.recv data_length - raw_data.length
|
46
|
-
rescue # Abrupt hangups result in exceptions that we catch here.
|
47
|
-
return nil
|
48
|
-
end
|
49
|
-
return false if partial.length == 0
|
50
|
-
raw_data += partial
|
51
|
-
end
|
52
|
-
|
53
|
-
return false unless raw_data.length == data_length
|
54
|
-
data = raw_data.unpack('C*')
|
55
|
-
return { :type => message_type, :node => node_address, :data => data }
|
56
|
-
end
|
57
|
-
end # module JcopRemoteProtocol
|
58
|
-
|
59
|
-
end # namespace Tem::Transport
|
@@ -1,171 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
# :nodoc: namespace
|
4
|
-
module Tem::Transport
|
5
|
-
|
6
|
-
# Stubs out the methods that can be implemented by the serving logic in a
|
7
|
-
# JCOP remote server. Serving logic classes should mix in this module, to
|
8
|
-
# avoid having unimplemented methods.
|
9
|
-
module JcopRemoteServingStubs
|
10
|
-
# Called when a client connection accepted.
|
11
|
-
#
|
12
|
-
# This method serves as a notification to the serving logic implementation.
|
13
|
-
# Its return value is discarded.
|
14
|
-
def connection_start
|
15
|
-
nil
|
16
|
-
end
|
17
|
-
|
18
|
-
# Called when a client connection is closed.
|
19
|
-
#
|
20
|
-
# This method serves as a notification to the serving logic implementation.
|
21
|
-
# Its return value is discarded.
|
22
|
-
def connection_end
|
23
|
-
nil
|
24
|
-
end
|
25
|
-
|
26
|
-
# Serving logic handling an APDU exchange.
|
27
|
-
#
|
28
|
-
# :call-seq:
|
29
|
-
# logic.exchange_apdu(apdu) -> array
|
30
|
-
#
|
31
|
-
# The |apdu| parameter is the request APDU, formatted as an array of
|
32
|
-
# integers between 0 and 255. The method should return the response APDU,
|
33
|
-
# formatted in a similar manner.
|
34
|
-
def exchange_apdu(apdu)
|
35
|
-
# Dumb implementation that always returns OK.
|
36
|
-
[0x90, 0x00]
|
37
|
-
end
|
38
|
-
end # module JcopRemoteServingStubs
|
39
|
-
|
40
|
-
|
41
|
-
# A server for the JCOP simulator protocol.
|
42
|
-
#
|
43
|
-
# The JCOP simulator protocol is generally useful when talking to a real JCOP
|
44
|
-
# simulator. This server is only handy for testing, and for forwarding
|
45
|
-
# connections (JCOP's Eclipse plug-in makes the simulator listen to 127.0.0.1,
|
46
|
-
# and sometimes you want to use it from another box).
|
47
|
-
class JcopRemoteServer
|
48
|
-
include JcopRemoteProtocol
|
49
|
-
|
50
|
-
# Creates a new JCOP server.
|
51
|
-
#
|
52
|
-
# The options hash supports the following keys:
|
53
|
-
# port:: the port to serve on
|
54
|
-
# ip:: the IP of the interface to serve on (defaults to all interfaces)
|
55
|
-
# reusable:: if set, the serving port can be shared with another
|
56
|
-
# application (REUSEADDR flag will be set on the socket)
|
57
|
-
#
|
58
|
-
# If the |serving_logic| parameter is nil, a serving logic implementation
|
59
|
-
# must be provided when calling JcopRemoteServer#run. The server will crash
|
60
|
-
# otherwise.
|
61
|
-
def initialize(options, serving_logic = nil)
|
62
|
-
@logic = serving_logic
|
63
|
-
@running = false
|
64
|
-
@options = options
|
65
|
-
@mutex = Mutex.new
|
66
|
-
end
|
67
|
-
|
68
|
-
# Runs the serving loop indefinitely.
|
69
|
-
#
|
70
|
-
# This method serves incoming conenctions until #stop is called.
|
71
|
-
#
|
72
|
-
# If |serving_logic| contains a non-nil value, it overrides any previously
|
73
|
-
# specified serving logic implementation. If no implementation is specified
|
74
|
-
# when the server is instantiated via JcopRemoteServer#new, one must be
|
75
|
-
# passed into |serving_logic|.
|
76
|
-
def run(serving_logic = nil)
|
77
|
-
@mutex.synchronize do
|
78
|
-
@logic ||= serving_logic
|
79
|
-
@serving_socket = serving_socket @options
|
80
|
-
@running = true
|
81
|
-
end
|
82
|
-
loop do
|
83
|
-
break unless @mutex.synchronize { @running }
|
84
|
-
begin
|
85
|
-
client_socket, client_address = @serving_socket.accept
|
86
|
-
rescue
|
87
|
-
# An exception will occur if the socket is closed
|
88
|
-
break
|
89
|
-
end
|
90
|
-
@logic.connection_start
|
91
|
-
loop do
|
92
|
-
break unless @mutex.synchronize { @running }
|
93
|
-
break unless process_request client_socket
|
94
|
-
end
|
95
|
-
client_socket.close rescue nil
|
96
|
-
@logic.connection_end # implemented by subclass
|
97
|
-
end
|
98
|
-
@mutex.synchronize do
|
99
|
-
@serving_socket.close if @serving_socket
|
100
|
-
@serving_socket = nil
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# Stops the serving loop.
|
105
|
-
def stop
|
106
|
-
@mutex.synchronize do
|
107
|
-
if @running
|
108
|
-
@serving_socket.close rescue nil
|
109
|
-
@serving_socket = nil
|
110
|
-
@running = false
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# TODO(costan): figure out a way to let serving logic reach this directly.
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
# Creates a socket listening to incoming connections to this server.
|
119
|
-
#
|
120
|
-
# :call-seq:
|
121
|
-
# server.establish_socket(options) -> Socket
|
122
|
-
#
|
123
|
-
# The |options| parameter supports the same keys as the options parameter
|
124
|
-
# of JcopRemoteServer#new.
|
125
|
-
#
|
126
|
-
# Returns a Socket configured to accept incoming connections.
|
127
|
-
def serving_socket(options)
|
128
|
-
port = options[:port] || 0
|
129
|
-
interface_ip = options[:ip] || '0.0.0.0'
|
130
|
-
serving_address = Socket.pack_sockaddr_in port, interface_ip
|
131
|
-
|
132
|
-
socket = Socket.new Socket::AF_INET, Socket::SOCK_STREAM,
|
133
|
-
Socket::PF_UNSPEC
|
134
|
-
|
135
|
-
if options[:reusable]
|
136
|
-
socket.setsockopt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true
|
137
|
-
end
|
138
|
-
socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true
|
139
|
-
socket.bind serving_address
|
140
|
-
socket.listen 5
|
141
|
-
socket
|
142
|
-
end
|
143
|
-
private :serving_socket
|
144
|
-
|
145
|
-
# Performs a request/response cycle.
|
146
|
-
#
|
147
|
-
# :call-seq:
|
148
|
-
# server.process_request(socket) -> Boolean
|
149
|
-
#
|
150
|
-
# Returns true if the server should do another request/response cycle, or
|
151
|
-
# false if this client indicated it's done talking to the server.
|
152
|
-
def process_request(socket)
|
153
|
-
return false unless request = recv_message(socket)
|
154
|
-
|
155
|
-
case request[:type]
|
156
|
-
when 0
|
157
|
-
# Wait for card; no-op, because that should have happen when the client
|
158
|
-
# connected.
|
159
|
-
send_message socket, :type => 0, :node => 0, :data => [3, 1, 4, 1, 5, 9]
|
160
|
-
when 1
|
161
|
-
# ATR exchange; the class' bread and butter
|
162
|
-
response = @logic.exchange_apdu request[:data]
|
163
|
-
send_message socket, :type => 1, :node => 0, :data => response
|
164
|
-
else
|
165
|
-
send_message socket, :type => request[:type], :node => 0, :data => []
|
166
|
-
end
|
167
|
-
end
|
168
|
-
private :process_request
|
169
|
-
end # module JcopRemoteServer
|
170
|
-
|
171
|
-
end # namespace Tem::Transport
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
# :nodoc: namespace
|
4
|
-
module Tem::Transport
|
5
|
-
|
6
|
-
# Implements the transport layer for a JCOP simulator instance.
|
7
|
-
class JcopRemoteTransport
|
8
|
-
include JavaCardMixin
|
9
|
-
include JcopRemoteProtocol
|
10
|
-
|
11
|
-
# Creates a new unconnected transport for a JCOP simulator serving TCP/IP.
|
12
|
-
#
|
13
|
-
# The options parameter must have the following keys:
|
14
|
-
# host:: the DNS name or IP of the host running the JCOP simulator
|
15
|
-
# port:: the TCP/IP port of the JCOP simulator server
|
16
|
-
def initialize(options)
|
17
|
-
@host, @port = options[:host], options[:port]
|
18
|
-
@socket = nil
|
19
|
-
end
|
20
|
-
|
21
|
-
#
|
22
|
-
def exchange_apdu(apdu)
|
23
|
-
send_message @socket, :type => 1, :node => 0, :data => apdu
|
24
|
-
recv_message(@socket)[:data]
|
25
|
-
end
|
26
|
-
|
27
|
-
# Makes a transport-level connection to the TEM.
|
28
|
-
def connect
|
29
|
-
begin
|
30
|
-
Socket.getaddrinfo(@host, @port, Socket::AF_INET,
|
31
|
-
Socket::SOCK_STREAM).each do |addr_info|
|
32
|
-
begin
|
33
|
-
@socket = Socket.new(addr_info[4], addr_info[5], addr_info[6])
|
34
|
-
@socket.connect Socket.pack_sockaddr_in(addr_info[1], addr_info[3])
|
35
|
-
break
|
36
|
-
rescue
|
37
|
-
@socket = nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
raise 'Connection refused' unless @socket
|
41
|
-
|
42
|
-
# Wait for the card to be inserted.
|
43
|
-
send_message @socket, :type => 0, :node => 0, :data => [0, 1, 0, 0]
|
44
|
-
recv_message @socket # ATR should come here, but who cares
|
45
|
-
rescue Exception
|
46
|
-
@socket = nil
|
47
|
-
raise
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Breaks down the transport-level connection to the TEM.
|
52
|
-
def disconnect
|
53
|
-
if @socket
|
54
|
-
@socket.close
|
55
|
-
@socket = nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def to_s
|
60
|
-
"#<JCOP Remote Terminal: disconnected>" if @socket.nil?
|
61
|
-
"#<JCOP Remote Terminal: #{@host}:#{@port}>"
|
62
|
-
end
|
63
|
-
end # class JcopRemoteTransport
|
64
|
-
|
65
|
-
end # module Tem::Transport
|
@@ -1,87 +0,0 @@
|
|
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 = @options[: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
|
@@ -1,10 +0,0 @@
|
|
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
|
@@ -1,114 +0,0 @@
|
|
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
|
@@ -1,90 +0,0 @@
|
|
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
|
@@ -1,82 +0,0 @@
|
|
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
|