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.
Files changed (56) hide show
  1. data/CHANGELOG +2 -0
  2. data/Manifest +1 -10
  3. data/Rakefile +1 -1
  4. data/bin/tem_proxy +4 -4
  5. data/lib/tem/apdus/buffers.rb +15 -8
  6. data/lib/tem/apdus/keys.rb +11 -5
  7. data/lib/tem/apdus/lifecycle.rb +10 -3
  8. data/lib/tem/apdus/tag.rb +10 -3
  9. data/lib/tem/auto_conf.rb +8 -5
  10. data/lib/tem/benchmarks/benchmarks.rb +7 -0
  11. data/lib/tem/benchmarks/blank_bound_secpack.rb +10 -0
  12. data/lib/tem/benchmarks/blank_sec.rb +14 -0
  13. data/lib/tem/benchmarks/devchip_decrypt.rb +12 -0
  14. data/lib/tem/benchmarks/post_buffer.rb +8 -0
  15. data/lib/tem/benchmarks/simple_apdu.rb +11 -0
  16. data/lib/tem/benchmarks/vm_perf.rb +11 -0
  17. data/lib/tem/benchmarks/vm_perf_bound.rb +12 -0
  18. data/lib/tem/builders/abi.rb +19 -13
  19. data/lib/tem/builders/assembler.rb +23 -16
  20. data/lib/tem/builders/crypto.rb +9 -3
  21. data/lib/tem/builders/isa.rb +10 -4
  22. data/lib/tem/definitions/abi.rb +9 -0
  23. data/lib/tem/definitions/assembler.rb +10 -0
  24. data/lib/tem/definitions/isa.rb +10 -0
  25. data/lib/tem/seclosures.rb +5 -5
  26. data/lib/tem/tem.rb +2 -1
  27. data/lib/tem_ruby.rb +0 -12
  28. data/tem_ruby.gemspec +9 -9
  29. data/test/builders/test_abi_builder.rb +4 -2
  30. data/test/tem_test_case.rb +3 -2
  31. data/test/tem_unit/test_tem_alu.rb +1 -1
  32. data/test/tem_unit/test_tem_bound_secpack.rb +1 -1
  33. data/test/tem_unit/test_tem_branching.rb +1 -1
  34. data/test/tem_unit/test_tem_crypto_asymmetric.rb +1 -1
  35. data/test/tem_unit/test_tem_crypto_hash.rb +1 -1
  36. data/test/tem_unit/test_tem_crypto_pstore.rb +1 -1
  37. data/test/tem_unit/test_tem_crypto_random.rb +1 -1
  38. data/test/tem_unit/test_tem_emit.rb +1 -1
  39. data/test/tem_unit/test_tem_memory.rb +1 -1
  40. data/test/tem_unit/test_tem_memory_compare.rb +1 -1
  41. data/test/tem_unit/test_tem_output.rb +1 -1
  42. data/test/tem_unit/test_tem_yaml_secpack.rb +4 -3
  43. data/test/test_auto_conf.rb +2 -0
  44. data/test/test_driver.rb +2 -1
  45. data/test/test_exceptions.rb +12 -6
  46. metadata +5 -24
  47. data/lib/tem/transport/auto_configurator.rb +0 -87
  48. data/lib/tem/transport/java_card_mixin.rb +0 -99
  49. data/lib/tem/transport/jcop_remote_protocol.rb +0 -59
  50. data/lib/tem/transport/jcop_remote_server.rb +0 -171
  51. data/lib/tem/transport/jcop_remote_transport.rb +0 -65
  52. data/lib/tem/transport/pcsc_transport.rb +0 -87
  53. data/lib/tem/transport/transport.rb +0 -10
  54. data/test/transport/test_auto_configurator.rb +0 -114
  55. data/test/transport/test_java_card_mixin.rb +0 -90
  56. 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