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.
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