tem_ruby 0.11.3 → 0.11.4
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 +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
|