smartcard 0.3.2-x86-mswin32-60 → 0.4.0-x86-mswin32-60
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 +17 -3
 - data/ext/smartcard_pcsc/pcsc_constants.c +1 -1
 - data/ext/smartcard_pcsc/pcsc_context.c +1 -1
 - data/lib/smartcard/gp/gp_card_mixin.rb +28 -0
 - data/lib/smartcard/iso/auto_configurator.rb +93 -0
 - data/lib/smartcard/iso/iso_card_mixin.rb +92 -0
 - data/lib/smartcard/iso/jcop_remote_protocol.rb +66 -0
 - data/lib/smartcard/iso/jcop_remote_server.rb +178 -0
 - data/lib/smartcard/iso/jcop_remote_transport.rb +72 -0
 - data/lib/smartcard/iso/pcsc_transport.rb +94 -0
 - data/lib/smartcard/iso/transport.rb +15 -0
 - data/lib/smartcard/{pcsc_exception.rb → pcsc/pcsc_exception.rb} +0 -0
 - data/lib/smartcard/pcsc.so +0 -0
 - data/lib/smartcard.rb +14 -0
 - data/smartcard.gemspec +6 -6
 - data/test/gp/gp_card_mixin_test.rb +33 -0
 - data/test/iso/auto_configurator_test.rb +119 -0
 - data/test/iso/iso_card_mixin_test.rb +95 -0
 - data/test/iso/jcop_remote_test.rb +87 -0
 - data/test/{test_containers.rb → pcsc/containers_test.rb} +7 -1
 - data/test/{test_smoke.rb → pcsc/smoke_test.rb} +7 -1
 - data/tests/ts_pcsc_ext.rb +4 -0
 - metadata +35 -11
 
    
        data/CHANGELOG
    CHANGED
    
    
    
        data/Manifest
    CHANGED
    
    | 
         @@ -13,11 +13,25 @@ ext/smartcard_pcsc/pcsc_namespace.c 
     | 
|
| 
       13 
13 
     | 
    
         
             
            ext/smartcard_pcsc/pcsc_reader_states.c
         
     | 
| 
       14 
14 
     | 
    
         
             
            ext/smartcard_pcsc/pcsc_surrogate_reader.h
         
     | 
| 
       15 
15 
     | 
    
         
             
            ext/smartcard_pcsc/pcsc_surrogate_wintypes.h
         
     | 
| 
       16 
     | 
    
         
            -
            lib/smartcard/ 
     | 
| 
      
 16 
     | 
    
         
            +
            lib/smartcard/gp/gp_card_mixin.rb
         
     | 
| 
      
 17 
     | 
    
         
            +
            lib/smartcard/iso/auto_configurator.rb
         
     | 
| 
      
 18 
     | 
    
         
            +
            lib/smartcard/iso/iso_card_mixin.rb
         
     | 
| 
      
 19 
     | 
    
         
            +
            lib/smartcard/iso/jcop_remote_protocol.rb
         
     | 
| 
      
 20 
     | 
    
         
            +
            lib/smartcard/iso/jcop_remote_server.rb
         
     | 
| 
      
 21 
     | 
    
         
            +
            lib/smartcard/iso/jcop_remote_transport.rb
         
     | 
| 
      
 22 
     | 
    
         
            +
            lib/smartcard/iso/pcsc_transport.rb
         
     | 
| 
      
 23 
     | 
    
         
            +
            lib/smartcard/iso/transport.rb
         
     | 
| 
      
 24 
     | 
    
         
            +
            lib/smartcard/pcsc/pcsc_exception.rb
         
     | 
| 
       17 
25 
     | 
    
         
             
            lib/smartcard.rb
         
     | 
| 
       18 
26 
     | 
    
         
             
            LICENSE
         
     | 
| 
       19 
27 
     | 
    
         
             
            Manifest
         
     | 
| 
      
 28 
     | 
    
         
            +
            Rakefile
         
     | 
| 
       20 
29 
     | 
    
         
             
            README
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
            test/ 
     | 
| 
      
 30 
     | 
    
         
            +
            smartcard.gemspec
         
     | 
| 
      
 31 
     | 
    
         
            +
            test/gp/gp_card_mixin_test.rb
         
     | 
| 
      
 32 
     | 
    
         
            +
            test/iso/auto_configurator_test.rb
         
     | 
| 
      
 33 
     | 
    
         
            +
            test/iso/iso_card_mixin_test.rb
         
     | 
| 
      
 34 
     | 
    
         
            +
            test/iso/jcop_remote_test.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            test/pcsc/containers_test.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            test/pcsc/smoke_test.rb
         
     | 
| 
       23 
37 
     | 
    
         
             
            tests/ts_pcsc_ext.rb
         
     | 
| 
         @@ -119,7 +119,7 @@ void Init_PCSC_Consts() { 
     | 
|
| 
       119 
119 
     | 
    
         
             
            #endif /* SCARD_STATE_UNPOWERED */
         
     | 
| 
       120 
120 
     | 
    
         | 
| 
       121 
121 
     | 
    
         
             
            	/* INFINITE : Infinite timeout. */
         
     | 
| 
       122 
     | 
    
         
            -
            	rb_define_const(mPcsc, "INFINITE_TIMEOUT",  
     | 
| 
      
 122 
     | 
    
         
            +
            	rb_define_const(mPcsc, "INFINITE_TIMEOUT", UINT2NUM(INFINITE));
         
     | 
| 
       123 
123 
     | 
    
         | 
| 
       124 
124 
     | 
    
         | 
| 
       125 
125 
     | 
    
         
             
            	/* SCARD_UNKNOWNU : Card is absent. */
         
     | 
| 
         @@ -225,7 +225,7 @@ static VALUE PCSC_Context_get_status_change(VALUE self, VALUE rbReaderStates, VA 
     | 
|
| 
       225 
225 
     | 
    
         
             
            	if(TYPE(rbTimeout) == T_NIL || TYPE(rbTimeout) == T_FALSE)
         
     | 
| 
       226 
226 
     | 
    
         
             
            		timeout = INFINITE;
         
     | 
| 
       227 
227 
     | 
    
         
             
            	else
         
     | 
| 
       228 
     | 
    
         
            -
            		timeout =  
     | 
| 
      
 228 
     | 
    
         
            +
            		timeout = NUM2UINT(rbTimeout);
         
     | 
| 
       229 
229 
     | 
    
         | 
| 
       230 
230 
     | 
    
         
             
            	if(_PCSC_ReaderStates_lowlevel_get(rbReaderStates, &reader_states, &reader_states_count) == 0)
         
     | 
| 
       231 
231 
     | 
    
         
             
            		rb_raise(rb_eArgError, "first parameter is not a ReaderStates instance or nil");
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # GlobalPlatform (formerly OpenPlatform) interface.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            # :nodoc: namespace
         
     | 
| 
      
 8 
     | 
    
         
            +
            module Smartcard::Gp
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module GpCardMixin
         
     | 
| 
      
 12 
     | 
    
         
            +
              include Smartcard::Iso::IsoCardMixin
         
     | 
| 
      
 13 
     | 
    
         
            +
              
         
     | 
| 
      
 14 
     | 
    
         
            +
              # Selects a GlobalPlatform application.
         
     | 
| 
      
 15 
     | 
    
         
            +
              def select_application(app_id)
         
     | 
| 
      
 16 
     | 
    
         
            +
                iso_apdu! :ins => 0xA4, :p1 => 0x04, :p2 => 0x00, :data => app_id
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              # Installs a JavaCard applet on the JavaCard.
         
     | 
| 
      
 20 
     | 
    
         
            +
              #
         
     | 
| 
      
 21 
     | 
    
         
            +
              # This would be really, really nice to have. Sadly, it's a far away TBD right
         
     | 
| 
      
 22 
     | 
    
         
            +
              # now.
         
     | 
| 
      
 23 
     | 
    
         
            +
              def install_applet(cap_contents)
         
     | 
| 
      
 24 
     | 
    
         
            +
                raise "Not implemeted; it'd be nice though, right?"
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end  # module GpCardMixin
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            end  # namespace Smartcard::Gp
         
     | 
| 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Automatic smart-card transport selection and configuration.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            # :nodoc: namespace
         
     | 
| 
      
 8 
     | 
    
         
            +
            module Smartcard::Iso
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            # Automatic configuration code.
         
     | 
| 
      
 11 
     | 
    
         
            +
            module AutoConfigurator  
         
     | 
| 
      
 12 
     | 
    
         
            +
              # The name of the environment variable that might supply the transport
         
     | 
| 
      
 13 
     | 
    
         
            +
              # configuration.
         
     | 
| 
      
 14 
     | 
    
         
            +
              ENVIRONMENT_VARIABLE_NAME = 'SCARD_PORT'
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
              # The default configurations to be tried if no configuration is specified.
         
     | 
| 
      
 17 
     | 
    
         
            +
              DEFAULT_CONFIGURATIONS = [
         
     | 
| 
      
 18 
     | 
    
         
            +
                { :class => JcopRemoteTransport,
         
     | 
| 
      
 19 
     | 
    
         
            +
                  :opts => { :host => '127.0.0.1', :port => 8050} },
         
     | 
| 
      
 20 
     | 
    
         
            +
                { :class => PcscTransport, :opts => { :reader_index => 0 }}
         
     | 
| 
      
 21 
     | 
    
         
            +
              ]
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              # Creates a transport based on available configuration information.
         
     | 
| 
      
 24 
     | 
    
         
            +
              def self.auto_transport
         
     | 
| 
      
 25 
     | 
    
         
            +
                configuration = env_configuration
         
     | 
| 
      
 26 
     | 
    
         
            +
                return try_transport(configuration) if configuration
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                DEFAULT_CONFIGURATIONS.each do |config|
         
     | 
| 
      
 29 
     | 
    
         
            +
                  transport = try_transport(config)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  return transport if transport
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
                return nil
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              # Retrieves transport configuration information from an environment variable.
         
     | 
| 
      
 36 
     | 
    
         
            +
              #
         
     | 
| 
      
 37 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 38 
     | 
    
         
            +
              #   AutoConfigurator.env_configuration -> hash
         
     | 
| 
      
 39 
     | 
    
         
            +
              #
         
     | 
| 
      
 40 
     | 
    
         
            +
              # The returned configuration has the keys required by
         
     | 
| 
      
 41 
     | 
    
         
            +
              # AutoConfigurator#try_transport
         
     | 
| 
      
 42 
     | 
    
         
            +
              def self.env_configuration
         
     | 
| 
      
 43 
     | 
    
         
            +
                return nil unless conf = ENV[ENVIRONMENT_VARIABLE_NAME]
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                case conf[0]
         
     | 
| 
      
 46 
     | 
    
         
            +
                when ?:
         
     | 
| 
      
 47 
     | 
    
         
            +
                  # :8050 -- JCOP emulator at port 8050
         
     | 
| 
      
 48 
     | 
    
         
            +
                  transport_class = JcopRemoteTransport
         
     | 
| 
      
 49 
     | 
    
         
            +
                  transport_opts = { :host => '127.0.0.1' }
         
     | 
| 
      
 50 
     | 
    
         
            +
                  transport_opts[:port] = conf[1..-1].to_i
         
     | 
| 
      
 51 
     | 
    
         
            +
                when ?@
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # @127.0.0.1:8050 -- JCOP emulator at host 127.0.0.1 port 8050
         
     | 
| 
      
 53 
     | 
    
         
            +
                  transport_class = JcopRemoteTransport
         
     | 
| 
      
 54 
     | 
    
         
            +
                  port_index = conf.rindex(?:) || conf.length
         
     | 
| 
      
 55 
     | 
    
         
            +
                  transport_opts = { :host => conf[1...port_index] }
         
     | 
| 
      
 56 
     | 
    
         
            +
                  transport_opts[:port] = conf[(port_index + 1)..-1].to_i
         
     | 
| 
      
 57 
     | 
    
         
            +
                when ?#
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # #2 -- 2nd PC/SC reader in the system
         
     | 
| 
      
 59 
     | 
    
         
            +
                  transport_class = PcscTransport
         
     | 
| 
      
 60 
     | 
    
         
            +
                  transport_opts = { :reader_index => conf[1..-1].to_i - 1 }
         
     | 
| 
      
 61 
     | 
    
         
            +
                else
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # Reader Name -- the PC/SC reader with the given name
         
     | 
| 
      
 63 
     | 
    
         
            +
                  transport_class = PcscTransport
         
     | 
| 
      
 64 
     | 
    
         
            +
                  transport_opts = { :reader_name => conf }
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
                
         
     | 
| 
      
 67 
     | 
    
         
            +
                transport_opts[:port] = 8050 if transport_opts[:port] == 0
         
     | 
| 
      
 68 
     | 
    
         
            +
                if transport_opts[:reader_index] and transport_opts[:reader_index] < 0
         
     | 
| 
      
 69 
     | 
    
         
            +
                  transport_opts[:reader_index] = 0
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
                { :class => transport_class, :opts => transport_opts }
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
              
         
     | 
| 
      
 74 
     | 
    
         
            +
              # Attempts to create a new ISO7816 transport with the given configuration.
         
     | 
| 
      
 75 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 76 
     | 
    
         
            +
              #   AutoConfigurator.try_transport(configuration) -> Transport or nil
         
     | 
| 
      
 77 
     | 
    
         
            +
              #
         
     | 
| 
      
 78 
     | 
    
         
            +
              # The configuration should have the following keys:
         
     | 
| 
      
 79 
     | 
    
         
            +
              #   class:: the Ruby class implementing the transport
         
     | 
| 
      
 80 
     | 
    
         
            +
              #   opts:: the options to be passed to the implementation's constructor
         
     | 
| 
      
 81 
     | 
    
         
            +
              def self.try_transport(configuration)
         
     | 
| 
      
 82 
     | 
    
         
            +
                raise 'No transport class specified' unless configuration[:class]
         
     | 
| 
      
 83 
     | 
    
         
            +
                begin
         
     | 
| 
      
 84 
     | 
    
         
            +
                  transport = configuration[:class].new(configuration[:opts] || {})
         
     | 
| 
      
 85 
     | 
    
         
            +
                  transport.connect
         
     | 
| 
      
 86 
     | 
    
         
            +
                  return transport
         
     | 
| 
      
 87 
     | 
    
         
            +
                rescue Exception
         
     | 
| 
      
 88 
     | 
    
         
            +
                  return nil
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
            end  # module AutoConfigurator
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            end  # module Smartcard::Iso
         
     | 
| 
         @@ -0,0 +1,92 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Common code for talking to ISO7816 smart-cards on all transports.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            # :nodoc: namespace
         
     | 
| 
      
 8 
     | 
    
         
            +
            module Smartcard::Iso
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # Module intended to be mixed into transport implementations to mediate between
         
     | 
| 
      
 12 
     | 
    
         
            +
            # a high level format for ISO7816-specific APDUs and the wire-level APDU 
         
     | 
| 
      
 13 
     | 
    
         
            +
            # request and response formats.
         
     | 
| 
      
 14 
     | 
    
         
            +
            #
         
     | 
| 
      
 15 
     | 
    
         
            +
            # The mix-in calls exchange_apdu in the transport implementation. It supplies
         
     | 
| 
      
 16 
     | 
    
         
            +
            # the APDU data as an array of integers between 0 and 255, and expects a
         
     | 
| 
      
 17 
     | 
    
         
            +
            # response in the same format.
         
     | 
| 
      
 18 
     | 
    
         
            +
            module IsoCardMixin  
         
     | 
| 
      
 19 
     | 
    
         
            +
              # APDU exchange with the ISO7816 card, raising an exception if the return
         
     | 
| 
      
 20 
     | 
    
         
            +
              # code is not success (0x9000).
         
     | 
| 
      
 21 
     | 
    
         
            +
              #
         
     | 
| 
      
 22 
     | 
    
         
            +
              # :call_seq:
         
     | 
| 
      
 23 
     | 
    
         
            +
              #   transport.iso_apdu!(apdu_data) -> array
         
     | 
| 
      
 24 
     | 
    
         
            +
              #
         
     | 
| 
      
 25 
     | 
    
         
            +
              # The apdu_data should be in the format expected by
         
     | 
| 
      
 26 
     | 
    
         
            +
              # IsoCardMixin#serialize_apdu. Returns the response data, if the response
         
     | 
| 
      
 27 
     | 
    
         
            +
              # status indicates success (0x9000). Otherwise, raises an exeception.
         
     | 
| 
      
 28 
     | 
    
         
            +
              def iso_apdu!(apdu_data)
         
     | 
| 
      
 29 
     | 
    
         
            +
                response = self.iso_apdu apdu_data
         
     | 
| 
      
 30 
     | 
    
         
            +
                return response[:data] if response[:status] == 0x9000
         
     | 
| 
      
 31 
     | 
    
         
            +
                raise "JavaCard response has error status 0x#{'%04x' % response[:status]}"
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              # Performs an APDU exchange with the ISO7816 card.
         
     | 
| 
      
 35 
     | 
    
         
            +
              #
         
     | 
| 
      
 36 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 37 
     | 
    
         
            +
              #   transport.iso_apdu(apdu_data) -> hash
         
     | 
| 
      
 38 
     | 
    
         
            +
              #
         
     | 
| 
      
 39 
     | 
    
         
            +
              # The apdu_data should be in the format expected by
         
     | 
| 
      
 40 
     | 
    
         
            +
              # IsoCardMixin#serialize_apdu. The response will be as specified in
         
     | 
| 
      
 41 
     | 
    
         
            +
              # IsoCardMixin#deserialize_response.
         
     | 
| 
      
 42 
     | 
    
         
            +
              def iso_apdu(apdu_data)
         
     | 
| 
      
 43 
     | 
    
         
            +
                response = self.exchange_apdu IsoCardMixin.serialize_apdu(apdu_data)
         
     | 
| 
      
 44 
     | 
    
         
            +
                IsoCardMixin.deserialize_response response
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
              
         
     | 
| 
      
 47 
     | 
    
         
            +
              # Serializes an APDU for wire transmission.
         
     | 
| 
      
 48 
     | 
    
         
            +
              #
         
     | 
| 
      
 49 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 50 
     | 
    
         
            +
              #   transport.wire_apdu(apdu_data) -> array
         
     | 
| 
      
 51 
     | 
    
         
            +
              #
         
     | 
| 
      
 52 
     | 
    
         
            +
              # The following keys are recognized in the APDU hash:
         
     | 
| 
      
 53 
     | 
    
         
            +
              #   cla:: the CLA byte in the APDU (optional, defaults to 0) 
         
     | 
| 
      
 54 
     | 
    
         
            +
              #   ins:: the INS byte in the APDU -- the first byte seen by a JavaCard applet
         
     | 
| 
      
 55 
     | 
    
         
            +
              #   p12:: 2-byte array containing the P1 and P2 bytes in the APDU
         
     | 
| 
      
 56 
     | 
    
         
            +
              #   p1, p2:: the P1 and P2 bytes in the APDU (optional, both default to 0)
         
     | 
| 
      
 57 
     | 
    
         
            +
              #   data:: the extra data in the APDU (optional, defaults to nothing)
         
     | 
| 
      
 58 
     | 
    
         
            +
              def self.serialize_apdu(apdu_data)
         
     | 
| 
      
 59 
     | 
    
         
            +
                raise 'Unspecified INS in apdu_data' unless apdu_data[:ins]
         
     | 
| 
      
 60 
     | 
    
         
            +
                apdu = [ apdu_data[:cla] || 0, apdu_data[:ins] ]
         
     | 
| 
      
 61 
     | 
    
         
            +
                if apdu_data[:p12]
         
     | 
| 
      
 62 
     | 
    
         
            +
                  unless apdu_data[:p12].length == 2
         
     | 
| 
      
 63 
     | 
    
         
            +
                    raise "Malformed P1,P2 - #{apdu_data[:p12]}"
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  apdu += apdu_data[:p12]
         
     | 
| 
      
 66 
     | 
    
         
            +
                else
         
     | 
| 
      
 67 
     | 
    
         
            +
                  apdu << (apdu_data[:p1] || 0)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  apdu << (apdu_data[:p2] || 0)
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
                if apdu_data[:data]
         
     | 
| 
      
 71 
     | 
    
         
            +
                  apdu << apdu_data[:data].length
         
     | 
| 
      
 72 
     | 
    
         
            +
                  apdu += apdu_data[:data]
         
     | 
| 
      
 73 
     | 
    
         
            +
                else
         
     | 
| 
      
 74 
     | 
    
         
            +
                  apdu << 0
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
                apdu
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
              
         
     | 
| 
      
 79 
     | 
    
         
            +
              # De-serializes a ISO7816 response APDU.
         
     | 
| 
      
 80 
     | 
    
         
            +
              # 
         
     | 
| 
      
 81 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 82 
     | 
    
         
            +
              #   transport.deserialize_response(response) -> hash
         
     | 
| 
      
 83 
     | 
    
         
            +
              #
         
     | 
| 
      
 84 
     | 
    
         
            +
              # The response contains the following keys:
         
     | 
| 
      
 85 
     | 
    
         
            +
              #   status:: the 2-byte status code (e.g. 0x9000 is OK)
         
     | 
| 
      
 86 
     | 
    
         
            +
              #   data:: the additional data in the response
         
     | 
| 
      
 87 
     | 
    
         
            +
              def self.deserialize_response(response)
         
     | 
| 
      
 88 
     | 
    
         
            +
                { :status => response[-2] * 256 + response[-1], :data => response[0...-2] }
         
     | 
| 
      
 89 
     | 
    
         
            +
              end  
         
     | 
| 
      
 90 
     | 
    
         
            +
            end  # module IsoCardMixin
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            end  # module Smartcard::Iso
         
     | 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # The protocol used to talk to ISO7816 smart-cards in IBM JCOP simulators.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            # :nodoc: namespace
         
     | 
| 
      
 8 
     | 
    
         
            +
            module Smartcard::Iso
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # Mixin implementing the JCOP simulator protocol.
         
     | 
| 
      
 12 
     | 
    
         
            +
            #
         
     | 
| 
      
 13 
     | 
    
         
            +
            # The (pretty informal) protocol specification is contained in the JavaDocs for
         
     | 
| 
      
 14 
     | 
    
         
            +
            # the class com.ibm.jc.terminal.RemoteJCTerminal and should be easy to find by
         
     | 
| 
      
 15 
     | 
    
         
            +
            # http://www.google.com/search?q=%22com.ibm.jc.terminal.RemoteJCTerminal%22  
         
     | 
| 
      
 16 
     | 
    
         
            +
            module JcopRemoteProtocol
         
     | 
| 
      
 17 
     | 
    
         
            +
              # Encodes and sends a JCOP simulator message to a TCP socket.
         
     | 
| 
      
 18 
     | 
    
         
            +
              #
         
     | 
| 
      
 19 
     | 
    
         
            +
              # The message must contain the following keys:
         
     | 
| 
      
 20 
     | 
    
         
            +
              #   type:: Integer expressing the message type (e.g. 1 = APDU exchange)
         
     | 
| 
      
 21 
     | 
    
         
            +
              #   node:: Integer expressing the node address (e.g. 0 for most purposes)
         
     | 
| 
      
 22 
     | 
    
         
            +
              #   data:: message payload, as an array of Integers ranging from 0 to 255
         
     | 
| 
      
 23 
     | 
    
         
            +
              def send_message(socket, message)
         
     | 
| 
      
 24 
     | 
    
         
            +
                raw_message = [message[:type], message[:node], message[:data].length].
         
     | 
| 
      
 25 
     | 
    
         
            +
                              pack('CCn') + message[:data].pack('C*')
         
     | 
| 
      
 26 
     | 
    
         
            +
                socket.send raw_message, 0
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              # Reads and decodes a JCOP simulator message from a TCP socket.
         
     | 
| 
      
 30 
     | 
    
         
            +
              # 
         
     | 
| 
      
 31 
     | 
    
         
            +
              # :call_seq:
         
     | 
| 
      
 32 
     | 
    
         
            +
              #   client.read_message(socket) -> Hash or nil
         
     | 
| 
      
 33 
     | 
    
         
            +
              #
         
     | 
| 
      
 34 
     | 
    
         
            +
              # If the other side of the TCP socket closes the connection, this method
         
     | 
| 
      
 35 
     | 
    
         
            +
              # returns nil. Otherwise, a Hash is returned, with the format required by the
         
     | 
| 
      
 36 
     | 
    
         
            +
              # JcopRemoteProtocol#send_message.
         
     | 
| 
      
 37 
     | 
    
         
            +
              def recv_message(socket)
         
     | 
| 
      
 38 
     | 
    
         
            +
                header = ''
         
     | 
| 
      
 39 
     | 
    
         
            +
                while header.length < 4
         
     | 
| 
      
 40 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 41 
     | 
    
         
            +
                    partial = socket.recv 4 - header.length
         
     | 
| 
      
 42 
     | 
    
         
            +
                  rescue  # Abrupt hangups result in exceptions that we catch here.        
         
     | 
| 
      
 43 
     | 
    
         
            +
                    return nil
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  return false if partial.length == 0
         
     | 
| 
      
 46 
     | 
    
         
            +
                  header += partial
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
                message_type, node_address, data_length = *header.unpack('CCn')
         
     | 
| 
      
 49 
     | 
    
         
            +
                raw_data = ''
         
     | 
| 
      
 50 
     | 
    
         
            +
                while raw_data.length < data_length
         
     | 
| 
      
 51 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 52 
     | 
    
         
            +
                    partial = socket.recv data_length - raw_data.length
         
     | 
| 
      
 53 
     | 
    
         
            +
                  rescue  # Abrupt hangups result in exceptions that we catch here.
         
     | 
| 
      
 54 
     | 
    
         
            +
                    return nil
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  return false if partial.length == 0
         
     | 
| 
      
 57 
     | 
    
         
            +
                  raw_data += partial
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                return false unless raw_data.length == data_length
         
     | 
| 
      
 61 
     | 
    
         
            +
                data = raw_data.unpack('C*')
         
     | 
| 
      
 62 
     | 
    
         
            +
                return { :type => message_type, :node => node_address, :data => data }
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
            end  # module JcopRemoteProtocol
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            end  # namespace Smartcard::Iso
         
     | 
| 
         @@ -0,0 +1,178 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # The protocol used to talk to ISO7816 smart-cards in IBM JCOP simulators.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # :nodoc: namespace
         
     | 
| 
      
 10 
     | 
    
         
            +
            module Smartcard::Iso
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Stubs out the methods that can be implemented by the serving logic in a
         
     | 
| 
      
 14 
     | 
    
         
            +
            # JCOP remote server. Serving logic classes should mix in this module, to
         
     | 
| 
      
 15 
     | 
    
         
            +
            # avoid having unimplemented methods.
         
     | 
| 
      
 16 
     | 
    
         
            +
            module JcopRemoteServingStubs
         
     | 
| 
      
 17 
     | 
    
         
            +
              # Called when a client connection accepted.
         
     | 
| 
      
 18 
     | 
    
         
            +
              #
         
     | 
| 
      
 19 
     | 
    
         
            +
              # This method serves as a notification to the serving logic implementation.
         
     | 
| 
      
 20 
     | 
    
         
            +
              # Its return value is discarded.
         
     | 
| 
      
 21 
     | 
    
         
            +
              def connection_start
         
     | 
| 
      
 22 
     | 
    
         
            +
                nil
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              # Called when a client connection is closed.
         
     | 
| 
      
 26 
     | 
    
         
            +
              #
         
     | 
| 
      
 27 
     | 
    
         
            +
              # This method serves as a notification to the serving logic implementation.
         
     | 
| 
      
 28 
     | 
    
         
            +
              # Its return value is discarded.
         
     | 
| 
      
 29 
     | 
    
         
            +
              def connection_end
         
     | 
| 
      
 30 
     | 
    
         
            +
                nil
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
              
         
     | 
| 
      
 33 
     | 
    
         
            +
              # Serving logic handling an APDU exchange.
         
     | 
| 
      
 34 
     | 
    
         
            +
              #
         
     | 
| 
      
 35 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 36 
     | 
    
         
            +
              #   logic.exchange_apdu(apdu) -> array
         
     | 
| 
      
 37 
     | 
    
         
            +
              #
         
     | 
| 
      
 38 
     | 
    
         
            +
              # The |apdu| parameter is the request APDU, formatted as an array of
         
     | 
| 
      
 39 
     | 
    
         
            +
              # integers between 0 and 255. The method should return the response APDU,
         
     | 
| 
      
 40 
     | 
    
         
            +
              # formatted in a similar manner.  
         
     | 
| 
      
 41 
     | 
    
         
            +
              def exchange_apdu(apdu)
         
     | 
| 
      
 42 
     | 
    
         
            +
                # Dumb implementation that always returns OK.
         
     | 
| 
      
 43 
     | 
    
         
            +
                [0x90, 0x00]
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end  # module JcopRemoteServingStubs
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            # A server for the JCOP simulator protocol.
         
     | 
| 
      
 49 
     | 
    
         
            +
            #
         
     | 
| 
      
 50 
     | 
    
         
            +
            # The JCOP simulator protocol is generally useful when talking to a real JCOP
         
     | 
| 
      
 51 
     | 
    
         
            +
            # simulator. This server is only handy for testing, and for forwarding
         
     | 
| 
      
 52 
     | 
    
         
            +
            # connections (JCOP's Eclipse plug-in makes the simulator listen to 127.0.0.1,
         
     | 
| 
      
 53 
     | 
    
         
            +
            # and sometimes you want to use it from another box).
         
     | 
| 
      
 54 
     | 
    
         
            +
            class JcopRemoteServer
         
     | 
| 
      
 55 
     | 
    
         
            +
              include JcopRemoteProtocol  
         
     | 
| 
      
 56 
     | 
    
         
            +
              
         
     | 
| 
      
 57 
     | 
    
         
            +
              # Creates a new JCOP server.
         
     | 
| 
      
 58 
     | 
    
         
            +
              #
         
     | 
| 
      
 59 
     | 
    
         
            +
              # The options hash supports the following keys:
         
     | 
| 
      
 60 
     | 
    
         
            +
              #   port:: the port to serve on
         
     | 
| 
      
 61 
     | 
    
         
            +
              #   ip:: the IP of the interface to serve on (defaults to all interfaces)
         
     | 
| 
      
 62 
     | 
    
         
            +
              #   reusable:: if set, the serving port can be shared with another
         
     | 
| 
      
 63 
     | 
    
         
            +
              #              application (REUSEADDR flag will be set on the socket)
         
     | 
| 
      
 64 
     | 
    
         
            +
              #
         
     | 
| 
      
 65 
     | 
    
         
            +
              # If the |serving_logic| parameter is nil, a serving logic implementation
         
     | 
| 
      
 66 
     | 
    
         
            +
              # must be provided when calling JcopRemoteServer#run. The server will crash
         
     | 
| 
      
 67 
     | 
    
         
            +
              # otherwise.
         
     | 
| 
      
 68 
     | 
    
         
            +
              def initialize(options, serving_logic = nil)
         
     | 
| 
      
 69 
     | 
    
         
            +
                @logic = serving_logic
         
     | 
| 
      
 70 
     | 
    
         
            +
                @running = false
         
     | 
| 
      
 71 
     | 
    
         
            +
                @options = options
         
     | 
| 
      
 72 
     | 
    
         
            +
                @mutex = Mutex.new
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
              
         
     | 
| 
      
 75 
     | 
    
         
            +
              # Runs the serving loop indefinitely.
         
     | 
| 
      
 76 
     | 
    
         
            +
              #
         
     | 
| 
      
 77 
     | 
    
         
            +
              # This method serves incoming conenctions until #stop is called.
         
     | 
| 
      
 78 
     | 
    
         
            +
              #
         
     | 
| 
      
 79 
     | 
    
         
            +
              # If |serving_logic| contains a non-nil value, it overrides any previously
         
     | 
| 
      
 80 
     | 
    
         
            +
              # specified serving logic implementation. If no implementation is specified
         
     | 
| 
      
 81 
     | 
    
         
            +
              # when the server is instantiated via JcopRemoteServer#new, one must be
         
     | 
| 
      
 82 
     | 
    
         
            +
              # passed into |serving_logic|.
         
     | 
| 
      
 83 
     | 
    
         
            +
              def run(serving_logic = nil)
         
     | 
| 
      
 84 
     | 
    
         
            +
                @mutex.synchronize do
         
     | 
| 
      
 85 
     | 
    
         
            +
                  @logic ||= serving_logic
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @serving_socket = serving_socket @options
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @running = true
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
                loop do
         
     | 
| 
      
 90 
     | 
    
         
            +
                  break unless @mutex.synchronize { @running }
         
     | 
| 
      
 91 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 92 
     | 
    
         
            +
                    client_socket, client_address = @serving_socket.accept
         
     | 
| 
      
 93 
     | 
    
         
            +
                  rescue
         
     | 
| 
      
 94 
     | 
    
         
            +
                    # An exception will occur if the socket is closed
         
     | 
| 
      
 95 
     | 
    
         
            +
                    break
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @logic.connection_start
         
     | 
| 
      
 98 
     | 
    
         
            +
                  loop do        
         
     | 
| 
      
 99 
     | 
    
         
            +
                    break unless @mutex.synchronize { @running }
         
     | 
| 
      
 100 
     | 
    
         
            +
                    break unless process_request client_socket
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
                  client_socket.close rescue nil
         
     | 
| 
      
 103 
     | 
    
         
            +
                  @logic.connection_end  # implemented by subclass
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
                @mutex.synchronize do
         
     | 
| 
      
 106 
     | 
    
         
            +
                  @serving_socket.close if @serving_socket
         
     | 
| 
      
 107 
     | 
    
         
            +
                  @serving_socket = nil
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
              # Stops the serving loop.
         
     | 
| 
      
 112 
     | 
    
         
            +
              def stop
         
     | 
| 
      
 113 
     | 
    
         
            +
                @mutex.synchronize do
         
     | 
| 
      
 114 
     | 
    
         
            +
                  if @running
         
     | 
| 
      
 115 
     | 
    
         
            +
                    @serving_socket.close rescue nil
         
     | 
| 
      
 116 
     | 
    
         
            +
                    @serving_socket = nil
         
     | 
| 
      
 117 
     | 
    
         
            +
                    @running = false
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
                
         
     | 
| 
      
 121 
     | 
    
         
            +
                # TODO(costan): figure out a way to let serving logic reach this directly.
         
     | 
| 
      
 122 
     | 
    
         
            +
              end
         
     | 
| 
      
 123 
     | 
    
         
            +
              
         
     | 
| 
      
 124 
     | 
    
         
            +
              
         
     | 
| 
      
 125 
     | 
    
         
            +
              # Creates a socket listening to incoming connections to this server.
         
     | 
| 
      
 126 
     | 
    
         
            +
              # 
         
     | 
| 
      
 127 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 128 
     | 
    
         
            +
              #   server.establish_socket(options) -> Socket
         
     | 
| 
      
 129 
     | 
    
         
            +
              #
         
     | 
| 
      
 130 
     | 
    
         
            +
              # The |options| parameter supports the same keys as the options parameter
         
     | 
| 
      
 131 
     | 
    
         
            +
              # of JcopRemoteServer#new.
         
     | 
| 
      
 132 
     | 
    
         
            +
              #
         
     | 
| 
      
 133 
     | 
    
         
            +
              # Returns a Socket configured to accept incoming connections. 
         
     | 
| 
      
 134 
     | 
    
         
            +
              def serving_socket(options)
         
     | 
| 
      
 135 
     | 
    
         
            +
                port = options[:port] || 0
         
     | 
| 
      
 136 
     | 
    
         
            +
                interface_ip = options[:ip] || '0.0.0.0'
         
     | 
| 
      
 137 
     | 
    
         
            +
                serving_address = Socket.pack_sockaddr_in port, interface_ip
         
     | 
| 
      
 138 
     | 
    
         
            +
                
         
     | 
| 
      
 139 
     | 
    
         
            +
                socket = Socket.new Socket::AF_INET, Socket::SOCK_STREAM,
         
     | 
| 
      
 140 
     | 
    
         
            +
                                    Socket::PF_UNSPEC
         
     | 
| 
      
 141 
     | 
    
         
            +
                
         
     | 
| 
      
 142 
     | 
    
         
            +
                if options[:reusable]
         
     | 
| 
      
 143 
     | 
    
         
            +
                  socket.setsockopt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
                socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true      
         
     | 
| 
      
 146 
     | 
    
         
            +
                socket.bind serving_address
         
     | 
| 
      
 147 
     | 
    
         
            +
                socket.listen 5
         
     | 
| 
      
 148 
     | 
    
         
            +
                socket
         
     | 
| 
      
 149 
     | 
    
         
            +
              end
         
     | 
| 
      
 150 
     | 
    
         
            +
              private :serving_socket
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
              # Performs a request/response cycle.
         
     | 
| 
      
 153 
     | 
    
         
            +
              #
         
     | 
| 
      
 154 
     | 
    
         
            +
              # :call-seq:
         
     | 
| 
      
 155 
     | 
    
         
            +
              #   server.process_request(socket) -> Boolean
         
     | 
| 
      
 156 
     | 
    
         
            +
              #
         
     | 
| 
      
 157 
     | 
    
         
            +
              # Returns true if the server should do another request/response cycle, or
         
     | 
| 
      
 158 
     | 
    
         
            +
              # false if this client indicated it's done talking to the server.
         
     | 
| 
      
 159 
     | 
    
         
            +
              def process_request(socket)
         
     | 
| 
      
 160 
     | 
    
         
            +
                return false unless request = recv_message(socket)
         
     | 
| 
      
 161 
     | 
    
         
            +
                
         
     | 
| 
      
 162 
     | 
    
         
            +
                case request[:type]
         
     | 
| 
      
 163 
     | 
    
         
            +
                when 0
         
     | 
| 
      
 164 
     | 
    
         
            +
                  # Wait for card; no-op, because that should have happen when the client
         
     | 
| 
      
 165 
     | 
    
         
            +
                  # connected.
         
     | 
| 
      
 166 
     | 
    
         
            +
                  send_message socket, :type => 0, :node => 0, :data => [3, 1, 4, 1, 5, 9]
         
     | 
| 
      
 167 
     | 
    
         
            +
                when 1
         
     | 
| 
      
 168 
     | 
    
         
            +
                  # ATR exchange; the class' bread and butter
         
     | 
| 
      
 169 
     | 
    
         
            +
                  response = @logic.exchange_apdu request[:data]
         
     | 
| 
      
 170 
     | 
    
         
            +
                  send_message socket, :type => 1, :node => 0, :data => response
         
     | 
| 
      
 171 
     | 
    
         
            +
                else
         
     | 
| 
      
 172 
     | 
    
         
            +
                  send_message socket, :type => request[:type], :node => 0, :data => []
         
     | 
| 
      
 173 
     | 
    
         
            +
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
              end
         
     | 
| 
      
 175 
     | 
    
         
            +
              private :process_request    
         
     | 
| 
      
 176 
     | 
    
         
            +
            end  # module JcopRemoteServer
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
            end  # namespace Smartcard::Iso
         
     | 
| 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Interface to ISO7816 smart-cards in IBM JCOP simulators.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # :nodoc: namespace
         
     | 
| 
      
 10 
     | 
    
         
            +
            module Smartcard::Iso
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Implements the transport layer for a JCOP simulator instance.
         
     | 
| 
      
 14 
     | 
    
         
            +
            class JcopRemoteTransport
         
     | 
| 
      
 15 
     | 
    
         
            +
              include IsoCardMixin
         
     | 
| 
      
 16 
     | 
    
         
            +
              include JcopRemoteProtocol
         
     | 
| 
      
 17 
     | 
    
         
            +
              
         
     | 
| 
      
 18 
     | 
    
         
            +
              # Creates a new unconnected transport for a JCOP simulator serving TCP/IP.
         
     | 
| 
      
 19 
     | 
    
         
            +
              #
         
     | 
| 
      
 20 
     | 
    
         
            +
              # The options parameter must have the following keys:
         
     | 
| 
      
 21 
     | 
    
         
            +
              #   host:: the DNS name or IP of the host running the JCOP simulator
         
     | 
| 
      
 22 
     | 
    
         
            +
              #   port:: the TCP/IP port of the JCOP simulator server
         
     | 
| 
      
 23 
     | 
    
         
            +
              def initialize(options)
         
     | 
| 
      
 24 
     | 
    
         
            +
                @host, @port = options[:host], options[:port]
         
     | 
| 
      
 25 
     | 
    
         
            +
                @socket = nil
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
              
         
     | 
| 
      
 28 
     | 
    
         
            +
              # 
         
     | 
| 
      
 29 
     | 
    
         
            +
              def exchange_apdu(apdu)
         
     | 
| 
      
 30 
     | 
    
         
            +
                send_message @socket, :type => 1, :node => 0, :data => apdu
         
     | 
| 
      
 31 
     | 
    
         
            +
                recv_message(@socket)[:data]
         
     | 
| 
      
 32 
     | 
    
         
            +
              end  
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              # Makes a transport-level connection to the TEM.
         
     | 
| 
      
 35 
     | 
    
         
            +
              def connect
         
     | 
| 
      
 36 
     | 
    
         
            +
                begin
         
     | 
| 
      
 37 
     | 
    
         
            +
                  Socket.getaddrinfo(@host, @port, Socket::AF_INET,
         
     | 
| 
      
 38 
     | 
    
         
            +
                                     Socket::SOCK_STREAM).each do |addr_info|
         
     | 
| 
      
 39 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 40 
     | 
    
         
            +
                      @socket = Socket.new(addr_info[4], addr_info[5], addr_info[6])
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @socket.connect Socket.pack_sockaddr_in(addr_info[1], addr_info[3])
         
     | 
| 
      
 42 
     | 
    
         
            +
                      break
         
     | 
| 
      
 43 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 44 
     | 
    
         
            +
                      @socket = nil
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end  
         
     | 
| 
      
 47 
     | 
    
         
            +
                  raise 'Connection refused' unless @socket
         
     | 
| 
      
 48 
     | 
    
         
            +
                  
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # Wait for the card to be inserted.
         
     | 
| 
      
 50 
     | 
    
         
            +
                  send_message @socket, :type => 0, :node => 0, :data => [0, 1, 0, 0]
         
     | 
| 
      
 51 
     | 
    
         
            +
                  recv_message @socket  # ATR should come here, but who cares      
         
     | 
| 
      
 52 
     | 
    
         
            +
                rescue Exception
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @socket = nil
         
     | 
| 
      
 54 
     | 
    
         
            +
                  raise
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              # Breaks down the transport-level connection to the TEM.
         
     | 
| 
      
 59 
     | 
    
         
            +
              def disconnect
         
     | 
| 
      
 60 
     | 
    
         
            +
                if @socket
         
     | 
| 
      
 61 
     | 
    
         
            +
                  @socket.close
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @socket = nil
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
              
         
     | 
| 
      
 66 
     | 
    
         
            +
              def to_s
         
     | 
| 
      
 67 
     | 
    
         
            +
                "#<JCOP Remote Terminal: disconnected>" if @socket.nil?
         
     | 
| 
      
 68 
     | 
    
         
            +
                "#<JCOP Remote Terminal: #{@host}:#{@port}>"
         
     | 
| 
      
 69 
     | 
    
         
            +
              end  
         
     | 
| 
      
 70 
     | 
    
         
            +
            end  # class JcopRemoteTransport 
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            end  # module Smartcard::Iso
         
     | 
| 
         @@ -0,0 +1,94 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Interface to ISO7816 smart-cards in PC/SC readers.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'smartcard'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            # :nodoc: namespace
         
     | 
| 
      
 11 
     | 
    
         
            +
            module Smartcard::Iso
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Implements the transport layer for a smartcard connected to a PC/SC reader.
         
     | 
| 
      
 14 
     | 
    
         
            +
            class PcscTransport
         
     | 
| 
      
 15 
     | 
    
         
            +
              include IsoCardMixin
         
     | 
| 
      
 16 
     | 
    
         
            +
              PCSC = Smartcard::PCSC
         
     | 
| 
      
 17 
     | 
    
         
            +
              
         
     | 
| 
      
 18 
     | 
    
         
            +
              def initialize(options)
         
     | 
| 
      
 19 
     | 
    
         
            +
                @options = options
         
     | 
| 
      
 20 
     | 
    
         
            +
                @context = nil
         
     | 
| 
      
 21 
     | 
    
         
            +
                @card = nil
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def exchange_apdu(apdu)
         
     | 
| 
      
 25 
     | 
    
         
            +
                xmit_apdu_string = apdu.pack('C*')
         
     | 
| 
      
 26 
     | 
    
         
            +
                result_string = @card.transmit xmit_apdu_string, @xmit_ioreq, @recv_ioreq
         
     | 
| 
      
 27 
     | 
    
         
            +
                return result_string.unpack('C*')
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
              
         
     | 
| 
      
 30 
     | 
    
         
            +
              def connect
         
     | 
| 
      
 31 
     | 
    
         
            +
                @context = PCSC::Context.new(PCSC::SCOPE_SYSTEM) if @context.nil?
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                if @options[:reader_name]
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @reader_name = @options[:reader_name]
         
     | 
| 
      
 35 
     | 
    
         
            +
                else
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # get the first reader      
         
     | 
| 
      
 37 
     | 
    
         
            +
                  readers = @context.list_readers nil
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @reader_name = readers[@options[:reader_index] || 0]
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                # get the reader's status
         
     | 
| 
      
 42 
     | 
    
         
            +
                reader_states = PCSC::ReaderStates.new(1)
         
     | 
| 
      
 43 
     | 
    
         
            +
                reader_states.set_reader_name_of!(0, @reader_name)
         
     | 
| 
      
 44 
     | 
    
         
            +
                reader_states.set_current_state_of!(0, PCSC::STATE_UNKNOWN)
         
     | 
| 
      
 45 
     | 
    
         
            +
                @context.get_status_change reader_states, 100
         
     | 
| 
      
 46 
     | 
    
         
            +
                reader_states.acknowledge_events!
         
     | 
| 
      
 47 
     | 
    
         
            +
                
         
     | 
| 
      
 48 
     | 
    
         
            +
                # prompt for card insertion unless that already happened
         
     | 
| 
      
 49 
     | 
    
         
            +
                if (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0
         
     | 
| 
      
 50 
     | 
    
         
            +
                  puts "Please insert TEM card in reader #{@reader_name}\n"
         
     | 
| 
      
 51 
     | 
    
         
            +
                  while (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0 do
         
     | 
| 
      
 52 
     | 
    
         
            +
                    @context.get_status_change reader_states, PCSC::INFINITE_TIMEOUT
         
     | 
| 
      
 53 
     | 
    
         
            +
                    reader_states.acknowledge_events!
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  puts "Card detected\n"
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
                
         
     | 
| 
      
 58 
     | 
    
         
            +
                # connect to card
         
     | 
| 
      
 59 
     | 
    
         
            +
                @card = PCSC::Card.new @context, @reader_name, PCSC::SHARE_EXCLUSIVE,
         
     | 
| 
      
 60 
     | 
    
         
            +
                                       PCSC::PROTOCOL_ANY
         
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                # build the transmit / receive IoRequests
         
     | 
| 
      
 63 
     | 
    
         
            +
                status = @card.status
         
     | 
| 
      
 64 
     | 
    
         
            +
                @xmit_ioreq = @@xmit_iorequest[status[:protocol]]
         
     | 
| 
      
 65 
     | 
    
         
            +
                if RUBY_PLATFORM =~ /win/ and (not RUBY_PLATFORM =~ /darwin/)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  @recv_ioreq = nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                else
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @recv_ioreq = PCSC::IoRequest.new
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
              
         
     | 
| 
      
 72 
     | 
    
         
            +
              def disconnect
         
     | 
| 
      
 73 
     | 
    
         
            +
                unless @card.nil?
         
     | 
| 
      
 74 
     | 
    
         
            +
                  @card.disconnect PCSC::DISPOSITION_LEAVE
         
     | 
| 
      
 75 
     | 
    
         
            +
                  @card = nil
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
                unless @context.nil?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  @context.release
         
     | 
| 
      
 79 
     | 
    
         
            +
                  @context = nil
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
              end  
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              def to_s
         
     | 
| 
      
 84 
     | 
    
         
            +
                "#<PC/SC Terminal: disconnected>" if @card.nil?
         
     | 
| 
      
 85 
     | 
    
         
            +
                "#<PC/SC Terminal: #{@reader_name}>"
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
              
         
     | 
| 
      
 88 
     | 
    
         
            +
              @@xmit_iorequest = {
         
     | 
| 
      
 89 
     | 
    
         
            +
                Smartcard::PCSC::PROTOCOL_T0 => Smartcard::PCSC::IOREQUEST_T0,
         
     | 
| 
      
 90 
     | 
    
         
            +
                Smartcard::PCSC::PROTOCOL_T1 => Smartcard::PCSC::IOREQUEST_T1,
         
     | 
| 
      
 91 
     | 
    
         
            +
              }
         
     | 
| 
      
 92 
     | 
    
         
            +
            end  # class PcscTransport
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
            end  # module Smartcard::Iso
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Interface for ISO7816 cards.
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            # The transport module contains classes responsible for transferring APDUs
         
     | 
| 
      
 9 
     | 
    
         
            +
            # from a high-level representation to the smart card hardware.
         
     | 
| 
      
 10 
     | 
    
         
            +
            module Smartcard::Iso
         
     | 
| 
      
 11 
     | 
    
         
            +
              # Shortcut for Smartcard::Iso::AutoConfigurator#auto_transport
         
     | 
| 
      
 12 
     | 
    
         
            +
              def self.auto_transport
         
     | 
| 
      
 13 
     | 
    
         
            +
                Smartcard::Iso::AutoConfigurator.auto_transport
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         
            File without changes
         
     | 
    
        data/lib/smartcard/pcsc.so
    CHANGED
    
    | 
         Binary file 
     | 
    
        data/lib/smartcard.rb
    CHANGED
    
    | 
         @@ -1 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'smartcard/pcsc'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'smartcard/pcsc/pcsc_exception.rb'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'smartcard/iso/iso_card_mixin.rb'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'smartcard/iso/jcop_remote_protocol.rb'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'smartcard/iso/jcop_remote_transport.rb'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'smartcard/iso/jcop_remote_server.rb'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'smartcard/iso/pcsc_transport.rb'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'smartcard/iso/transport.rb'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            require 'smartcard/iso/auto_configurator.rb'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            require 'smartcard/gp/gp_card_mixin.rb'
         
     | 
    
        data/smartcard.gemspec
    CHANGED
    
    | 
         @@ -2,23 +2,23 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            Gem::Specification.new do |s|
         
     | 
| 
       4 
4 
     | 
    
         
             
              s.name = %q{smartcard}
         
     | 
| 
       5 
     | 
    
         
            -
              s.version = "0. 
     | 
| 
      
 5 
     | 
    
         
            +
              s.version = "0.4.0"
         
     | 
| 
       6 
6 
     | 
    
         
             
              s.platform = %q{x86-mswin32-60}
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
              s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
         
     | 
| 
       9 
9 
     | 
    
         
             
              s.authors = ["Victor Costan"]
         
     | 
| 
       10 
     | 
    
         
            -
              s.date = %q{2009- 
     | 
| 
      
 10 
     | 
    
         
            +
              s.date = %q{2009-08-19}
         
     | 
| 
       11 
11 
     | 
    
         
             
              s.description = %q{Interface with ISO 7816 smart cards.}
         
     | 
| 
       12 
12 
     | 
    
         
             
              s.email = %q{victor@costan.us}
         
     | 
| 
       13 
     | 
    
         
            -
              s.extra_rdoc_files = ["BUILD", "CHANGELOG", "ext/smartcard_pcsc/extconf.rb", "ext/smartcard_pcsc/pcsc.h", "ext/smartcard_pcsc/pcsc_card.c", "ext/smartcard_pcsc/pcsc_constants.c", "ext/smartcard_pcsc/pcsc_context.c", "ext/smartcard_pcsc/pcsc_exception.c", "ext/smartcard_pcsc/pcsc_io_request.c", "ext/smartcard_pcsc/pcsc_main.c", "ext/smartcard_pcsc/pcsc_multi_strings.c", "ext/smartcard_pcsc/pcsc_namespace.c", "ext/smartcard_pcsc/pcsc_reader_states.c", "ext/smartcard_pcsc/pcsc_surrogate_reader.h", "ext/smartcard_pcsc/pcsc_surrogate_wintypes.h", "lib/smartcard/pcsc_exception.rb", "lib/smartcard.rb", "LICENSE", "README"]
         
     | 
| 
       14 
     | 
    
         
            -
              s.files = ["BUILD", "CHANGELOG", "ext/smartcard_pcsc/extconf.rb", "ext/smartcard_pcsc/pcsc.h", "ext/smartcard_pcsc/pcsc_card.c", "ext/smartcard_pcsc/pcsc_constants.c", "ext/smartcard_pcsc/pcsc_context.c", "ext/smartcard_pcsc/pcsc_exception.c", "ext/smartcard_pcsc/pcsc_io_request.c", "ext/smartcard_pcsc/pcsc_main.c", "ext/smartcard_pcsc/pcsc_multi_strings.c", "ext/smartcard_pcsc/pcsc_namespace.c", "ext/smartcard_pcsc/pcsc_reader_states.c", "ext/smartcard_pcsc/pcsc_surrogate_reader.h", "ext/smartcard_pcsc/pcsc_surrogate_wintypes.h", "lib/smartcard/pcsc_exception.rb", "lib/smartcard.rb", "LICENSE", "Manifest", "README", "test/ 
     | 
| 
      
 13 
     | 
    
         
            +
              s.extra_rdoc_files = ["BUILD", "CHANGELOG", "ext/smartcard_pcsc/extconf.rb", "ext/smartcard_pcsc/pcsc.h", "ext/smartcard_pcsc/pcsc_card.c", "ext/smartcard_pcsc/pcsc_constants.c", "ext/smartcard_pcsc/pcsc_context.c", "ext/smartcard_pcsc/pcsc_exception.c", "ext/smartcard_pcsc/pcsc_io_request.c", "ext/smartcard_pcsc/pcsc_main.c", "ext/smartcard_pcsc/pcsc_multi_strings.c", "ext/smartcard_pcsc/pcsc_namespace.c", "ext/smartcard_pcsc/pcsc_reader_states.c", "ext/smartcard_pcsc/pcsc_surrogate_reader.h", "ext/smartcard_pcsc/pcsc_surrogate_wintypes.h", "lib/smartcard/gp/gp_card_mixin.rb", "lib/smartcard/iso/auto_configurator.rb", "lib/smartcard/iso/iso_card_mixin.rb", "lib/smartcard/iso/jcop_remote_protocol.rb", "lib/smartcard/iso/jcop_remote_server.rb", "lib/smartcard/iso/jcop_remote_transport.rb", "lib/smartcard/iso/pcsc_transport.rb", "lib/smartcard/iso/transport.rb", "lib/smartcard/pcsc/pcsc_exception.rb", "lib/smartcard.rb", "LICENSE", "README"]
         
     | 
| 
      
 14 
     | 
    
         
            +
              s.files = ["BUILD", "CHANGELOG", "ext/smartcard_pcsc/extconf.rb", "ext/smartcard_pcsc/pcsc.h", "ext/smartcard_pcsc/pcsc_card.c", "ext/smartcard_pcsc/pcsc_constants.c", "ext/smartcard_pcsc/pcsc_context.c", "ext/smartcard_pcsc/pcsc_exception.c", "ext/smartcard_pcsc/pcsc_io_request.c", "ext/smartcard_pcsc/pcsc_main.c", "ext/smartcard_pcsc/pcsc_multi_strings.c", "ext/smartcard_pcsc/pcsc_namespace.c", "ext/smartcard_pcsc/pcsc_reader_states.c", "ext/smartcard_pcsc/pcsc_surrogate_reader.h", "ext/smartcard_pcsc/pcsc_surrogate_wintypes.h", "lib/smartcard/gp/gp_card_mixin.rb", "lib/smartcard/iso/auto_configurator.rb", "lib/smartcard/iso/iso_card_mixin.rb", "lib/smartcard/iso/jcop_remote_protocol.rb", "lib/smartcard/iso/jcop_remote_server.rb", "lib/smartcard/iso/jcop_remote_transport.rb", "lib/smartcard/iso/pcsc_transport.rb", "lib/smartcard/iso/transport.rb", "lib/smartcard/pcsc/pcsc_exception.rb", "lib/smartcard.rb", "LICENSE", "Manifest", "Rakefile", "README", "smartcard.gemspec", "test/gp/gp_card_mixin_test.rb", "test/iso/auto_configurator_test.rb", "test/iso/iso_card_mixin_test.rb", "test/iso/jcop_remote_test.rb", "test/pcsc/containers_test.rb", "test/pcsc/smoke_test.rb", "tests/ts_pcsc_ext.rb", "lib/smartcard/pcsc.so"]
         
     | 
| 
       15 
15 
     | 
    
         
             
              s.homepage = %q{http://www.costan.us/smartcard}
         
     | 
| 
       16 
16 
     | 
    
         
             
              s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Smartcard", "--main", "README"]
         
     | 
| 
       17 
17 
     | 
    
         
             
              s.require_paths = ["lib", "ext"]
         
     | 
| 
       18 
18 
     | 
    
         
             
              s.rubyforge_project = %q{smartcard}
         
     | 
| 
       19 
     | 
    
         
            -
              s.rubygems_version = %q{1.3. 
     | 
| 
      
 19 
     | 
    
         
            +
              s.rubygems_version = %q{1.3.5}
         
     | 
| 
       20 
20 
     | 
    
         
             
              s.summary = %q{Interface with ISO 7816 smart cards.}
         
     | 
| 
       21 
     | 
    
         
            -
              s.test_files = ["test/ 
     | 
| 
      
 21 
     | 
    
         
            +
              s.test_files = ["test/gp/gp_card_mixin_test.rb", "test/iso/auto_configurator_test.rb", "test/iso/iso_card_mixin_test.rb", "test/iso/jcop_remote_test.rb", "test/pcsc/containers_test.rb", "test/pcsc/smoke_test.rb"]
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
              if s.respond_to? :specification_version then
         
     | 
| 
       24 
24 
     | 
    
         
             
                current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 3 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'smartcard'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'flexmock/test_unit'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            class GpCardMixinTest < Test::Unit::TestCase
         
     | 
| 
      
 14 
     | 
    
         
            +
              GpCardMixin = Smartcard::Gp::GpCardMixin
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
              # The sole purpose of this class is wrapping the mixin under test.
         
     | 
| 
      
 17 
     | 
    
         
            +
              class MixinWrapper
         
     | 
| 
      
 18 
     | 
    
         
            +
                include GpCardMixin
         
     | 
| 
      
 19 
     | 
    
         
            +
                include Smartcard::Iso::IsoCardMixin
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
              
         
     | 
| 
      
 22 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
                
         
     | 
| 
      
 25 
     | 
    
         
            +
              def test_select_application
         
     | 
| 
      
 26 
     | 
    
         
            +
                mock = MixinWrapper.new
         
     | 
| 
      
 27 
     | 
    
         
            +
                flexmock(mock).should_receive(:exchange_apdu).
         
     | 
| 
      
 28 
     | 
    
         
            +
                               with([0x00, 0xA4, 0x04, 0x00, 0x05,
         
     | 
| 
      
 29 
     | 
    
         
            +
                                     0x19, 0x83, 0x12, 0x29, 0x10]).
         
     | 
| 
      
 30 
     | 
    
         
            +
                               and_return([0x90, 0x00])
         
     | 
| 
      
 31 
     | 
    
         
            +
                mock.select_application([0x19, 0x83, 0x12, 0x29, 0x10])
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,119 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 3 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'smartcard'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'flexmock/test_unit'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            class AutoConfiguratorTest < Test::Unit::TestCase
         
     | 
| 
      
 14 
     | 
    
         
            +
              AutoConfigurator = Smartcard::Iso::AutoConfigurator
         
     | 
| 
      
 15 
     | 
    
         
            +
              PcscTransport = Smartcard::Iso::PcscTransport
         
     | 
| 
      
 16 
     | 
    
         
            +
              JcopRemoteTransport = Smartcard::Iso::JcopRemoteTransport
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 19 
     | 
    
         
            +
                @env_var = AutoConfigurator::ENVIRONMENT_VARIABLE_NAME 
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              def test_env_configuration_blank
         
     | 
| 
      
 23 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return(nil)
         
     | 
| 
      
 24 
     | 
    
         
            +
                assert_equal nil, AutoConfigurator.env_configuration
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
              def test_env_configuration_remote_port
         
     | 
| 
      
 27 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return(':6996')
         
     | 
| 
      
 28 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 29 
     | 
    
         
            +
                assert_equal JcopRemoteTransport, conf[:class]
         
     | 
| 
      
 30 
     | 
    
         
            +
                assert_equal({:host => '127.0.0.1', :port => 6996}, conf[:opts])
         
     | 
| 
      
 31 
     | 
    
         
            +
              end  
         
     | 
| 
      
 32 
     | 
    
         
            +
              def test_env_configuration_remote_noport
         
     | 
| 
      
 33 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return(':')
         
     | 
| 
      
 34 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 35 
     | 
    
         
            +
                assert_equal JcopRemoteTransport, conf[:class]
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_equal({:host => '127.0.0.1', :port => 8050}, conf[:opts])
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
              def test_env_configuration_remote_host_port
         
     | 
| 
      
 39 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).
         
     | 
| 
      
 40 
     | 
    
         
            +
                              and_return('@moonstone:6996')
         
     | 
| 
      
 41 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 42 
     | 
    
         
            +
                assert_equal JcopRemoteTransport, conf[:class]
         
     | 
| 
      
 43 
     | 
    
         
            +
                assert_equal({:host => 'moonstone', :port => 6996}, conf[:opts])
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
              def test_env_configuration_remote_host_noport    
         
     | 
| 
      
 46 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return('@moonstone')
         
     | 
| 
      
 47 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 48 
     | 
    
         
            +
                assert_equal JcopRemoteTransport, conf[:class]
         
     | 
| 
      
 49 
     | 
    
         
            +
                assert_equal({:host => 'moonstone', :port => 8050}, conf[:opts])
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
              def test_env_configuration_remote_ipv6_port
         
     | 
| 
      
 52 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).
         
     | 
| 
      
 53 
     | 
    
         
            +
                              and_return('@ff80::0080:6996')
         
     | 
| 
      
 54 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 55 
     | 
    
         
            +
                assert_equal JcopRemoteTransport, conf[:class]
         
     | 
| 
      
 56 
     | 
    
         
            +
                assert_equal({:host => 'ff80::0080', :port => 6996}, conf[:opts])
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
              def test_env_configuration_remote_ipv6_noport
         
     | 
| 
      
 59 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return('@ff80::0080:')
         
     | 
| 
      
 60 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 61 
     | 
    
         
            +
                assert_equal JcopRemoteTransport, conf[:class]
         
     | 
| 
      
 62 
     | 
    
         
            +
                assert_equal({:host => 'ff80::0080', :port => 8050}, conf[:opts])
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              def test_env_configuration_pcsc_reader_index
         
     | 
| 
      
 66 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return('#1')
         
     | 
| 
      
 67 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 68 
     | 
    
         
            +
                assert_equal PcscTransport, conf[:class]
         
     | 
| 
      
 69 
     | 
    
         
            +
                assert_equal({:reader_index => 0}, conf[:opts])
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
              def test_env_configuration_pcsc_reader_name
         
     | 
| 
      
 72 
     | 
    
         
            +
                reader_name = 'Awesome Reader'
         
     | 
| 
      
 73 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).
         
     | 
| 
      
 74 
     | 
    
         
            +
                            and_return(reader_name)
         
     | 
| 
      
 75 
     | 
    
         
            +
                conf = AutoConfigurator.env_configuration
         
     | 
| 
      
 76 
     | 
    
         
            +
                assert_equal PcscTransport, conf[:class]
         
     | 
| 
      
 77 
     | 
    
         
            +
                assert_equal({:reader_name => reader_name}, conf[:opts])
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
              
         
     | 
| 
      
 80 
     | 
    
         
            +
              def test_try_transport
         
     | 
| 
      
 81 
     | 
    
         
            +
                transport = Object.new
         
     | 
| 
      
 82 
     | 
    
         
            +
                flexmock(PcscTransport).should_receive(:new).with(:reader_index => 1).
         
     | 
| 
      
 83 
     | 
    
         
            +
                                        and_return(transport)
         
     | 
| 
      
 84 
     | 
    
         
            +
                flexmock(transport).should_receive(:connect)
         
     | 
| 
      
 85 
     | 
    
         
            +
                flexmock(PcscTransport).should_receive(:new).with(:reader_index => 2).
         
     | 
| 
      
 86 
     | 
    
         
            +
                                        and_raise('Boom headshot')
         
     | 
| 
      
 87 
     | 
    
         
            +
                failport = Object.new
         
     | 
| 
      
 88 
     | 
    
         
            +
                flexmock(PcscTransport).should_receive(:new).with(:reader_index => 3).
         
     | 
| 
      
 89 
     | 
    
         
            +
                                        and_return(failport)    
         
     | 
| 
      
 90 
     | 
    
         
            +
                flexmock(failport).should_receive(:connect).and_raise('Lag')
         
     | 
| 
      
 91 
     | 
    
         
            +
                
         
     | 
| 
      
 92 
     | 
    
         
            +
                config = { :class => PcscTransport, :opts => {:reader_index => 1} }
         
     | 
| 
      
 93 
     | 
    
         
            +
                assert_equal transport, AutoConfigurator.try_transport(config)
         
     | 
| 
      
 94 
     | 
    
         
            +
                config = { :class => PcscTransport, :opts => {:reader_index => 2} }
         
     | 
| 
      
 95 
     | 
    
         
            +
                assert_equal nil, AutoConfigurator.try_transport(config)
         
     | 
| 
      
 96 
     | 
    
         
            +
                config = { :class => PcscTransport, :opts => {:reader_index => 3} }
         
     | 
| 
      
 97 
     | 
    
         
            +
                assert_equal nil, AutoConfigurator.try_transport(config)
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
              
         
     | 
| 
      
 100 
     | 
    
         
            +
              def test_auto_transport_uses_env
         
     | 
| 
      
 101 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return('#1')
         
     | 
| 
      
 102 
     | 
    
         
            +
                transport = Object.new
         
     | 
| 
      
 103 
     | 
    
         
            +
                flexmock(PcscTransport).should_receive(:new).with(:reader_index => 0).
         
     | 
| 
      
 104 
     | 
    
         
            +
                                        and_return(transport)
         
     | 
| 
      
 105 
     | 
    
         
            +
                flexmock(transport).should_receive(:connect)
         
     | 
| 
      
 106 
     | 
    
         
            +
                
         
     | 
| 
      
 107 
     | 
    
         
            +
                assert_equal transport, AutoConfigurator.auto_transport
         
     | 
| 
      
 108 
     | 
    
         
            +
              end
         
     | 
| 
      
 109 
     | 
    
         
            +
              
         
     | 
| 
      
 110 
     | 
    
         
            +
              def test_auto_transport_with_defaults
         
     | 
| 
      
 111 
     | 
    
         
            +
                flexmock(ENV).should_receive(:[]).with(@env_var).and_return(nil)
         
     | 
| 
      
 112 
     | 
    
         
            +
                transport = Object.new
         
     | 
| 
      
 113 
     | 
    
         
            +
                flexmock(JcopRemoteTransport).should_receive(:new).and_return(nil)
         
     | 
| 
      
 114 
     | 
    
         
            +
                flexmock(PcscTransport).should_receive(:new).and_return(transport)
         
     | 
| 
      
 115 
     | 
    
         
            +
                flexmock(transport).should_receive(:connect)    
         
     | 
| 
      
 116 
     | 
    
         
            +
                    
         
     | 
| 
      
 117 
     | 
    
         
            +
                assert_equal transport, AutoConfigurator.auto_transport
         
     | 
| 
      
 118 
     | 
    
         
            +
              end
         
     | 
| 
      
 119 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,95 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 3 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'smartcard'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'flexmock/test_unit'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            class IsoCardMixinTest < Test::Unit::TestCase
         
     | 
| 
      
 14 
     | 
    
         
            +
              IsoCardMixin = Smartcard::Iso::IsoCardMixin
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
              # The sole purpose of this class is wrapping the mixin under test.
         
     | 
| 
      
 17 
     | 
    
         
            +
              class MixinWrapper
         
     | 
| 
      
 18 
     | 
    
         
            +
                include IsoCardMixin
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def test_serialize_apdu
         
     | 
| 
      
 25 
     | 
    
         
            +
                s = lambda { |apdu| IsoCardMixin.serialize_apdu apdu }
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                assert_equal [0x00, 0x05, 0x00, 0x00, 0x00], s[:ins => 0x05],
         
     | 
| 
      
 28 
     | 
    
         
            +
                             'Specified INS'
         
     | 
| 
      
 29 
     | 
    
         
            +
                assert_equal [0x00, 0x09, 0x00, 0x01, 0x00], s[:ins => 0x09, :p2 => 0x01],
         
     | 
| 
      
 30 
     | 
    
         
            +
                             'Specified INS and P2'
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert_equal [0x00, 0xF9, 0xAC, 0xEF, 0x00],
         
     | 
| 
      
 32 
     | 
    
         
            +
                             s[:ins => 0xF9, :p1 => 0xAC, :p2 => 0xEF],
         
     | 
| 
      
 33 
     | 
    
         
            +
                             'Specified INS, P1, P2'
         
     | 
| 
      
 34 
     | 
    
         
            +
                assert_equal [0x00, 0xFA, 0xAD, 0xEC, 0x00],
         
     | 
| 
      
 35 
     | 
    
         
            +
                             s[:ins => 0xFA, :p12 => [0xAD, 0xEC]],
         
     | 
| 
      
 36 
     | 
    
         
            +
                             'Specified INS, P1+P2'
         
     | 
| 
      
 37 
     | 
    
         
            +
                assert_equal [0x00, 0x0E, 0x00, 0x00, 0x04, 0x33, 0x95, 0x81, 0x63],
         
     | 
| 
      
 38 
     | 
    
         
            +
                             s[:ins => 0x0E, :data => [0x33, 0x95, 0x81, 0x63]],
         
     | 
| 
      
 39 
     | 
    
         
            +
                             'Specified INS and DATA'
         
     | 
| 
      
 40 
     | 
    
         
            +
                assert_equal [0x80, 0x0F, 0xBA, 0xBE, 0x03, 0x31, 0x41, 0x59],
         
     | 
| 
      
 41 
     | 
    
         
            +
                             s[:cla => 0x80, :ins => 0x0F, :p1 => 0xBA, :p2 => 0xBE,
         
     | 
| 
      
 42 
     | 
    
         
            +
                               :data => [0x31, 0x41, 0x59]],
         
     | 
| 
      
 43 
     | 
    
         
            +
                             'Specified everything'
         
     | 
| 
      
 44 
     | 
    
         
            +
                assert_raise(RuntimeError, 'Did not specify INS') do
         
     | 
| 
      
 45 
     | 
    
         
            +
                  s[:cla => 0x80, :p1 => 0xBA, :p2 => 0xBE, :data => [0x31, 0x41, 0x59]]
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
              
         
     | 
| 
      
 49 
     | 
    
         
            +
              def test_deserialize_response
         
     | 
| 
      
 50 
     | 
    
         
            +
                d = lambda { |response| IsoCardMixin.deserialize_response response }
         
     | 
| 
      
 51 
     | 
    
         
            +
                
         
     | 
| 
      
 52 
     | 
    
         
            +
                assert_equal({ :status => 0x9000, :data => [] }, d[[0x90, 0x00]])
         
     | 
| 
      
 53 
     | 
    
         
            +
                assert_equal({ :status => 0x8631, :data => [] }, d[[0x86, 0x31]])
         
     | 
| 
      
 54 
     | 
    
         
            +
                assert_equal({ :status => 0x9000, :data => [0x31, 0x41, 0x59, 0x26] },
         
     | 
| 
      
 55 
     | 
    
         
            +
                             d[[0x31, 0x41, 0x59, 0x26, 0x90, 0x00]])
         
     | 
| 
      
 56 
     | 
    
         
            +
                assert_equal({ :status => 0x7395, :data => [0x31, 0x41, 0x59, 0x26] },
         
     | 
| 
      
 57 
     | 
    
         
            +
                             d[[0x31, 0x41, 0x59, 0x26, 0x73, 0x95]])
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
              
         
     | 
| 
      
 60 
     | 
    
         
            +
              def win_mock
         
     | 
| 
      
 61 
     | 
    
         
            +
                mock = MixinWrapper.new
         
     | 
| 
      
 62 
     | 
    
         
            +
                flexmock(mock).should_receive(:exchange_apdu).
         
     | 
| 
      
 63 
     | 
    
         
            +
                               with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41]).
         
     | 
| 
      
 64 
     | 
    
         
            +
                               and_return([0x67, 0x31, 0x90, 0x00])
         
     | 
| 
      
 65 
     | 
    
         
            +
                mock
         
     | 
| 
      
 66 
     | 
    
         
            +
              end  
         
     | 
| 
      
 67 
     | 
    
         
            +
              def win_apdu
         
     | 
| 
      
 68 
     | 
    
         
            +
                {:ins => 0xF9, :p1 => 0xAC, :data => [0x31, 0x41]}
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
              
         
     | 
| 
      
 71 
     | 
    
         
            +
              def lose_mock
         
     | 
| 
      
 72 
     | 
    
         
            +
                mock = MixinWrapper.new
         
     | 
| 
      
 73 
     | 
    
         
            +
                flexmock(mock).should_receive(:exchange_apdu).
         
     | 
| 
      
 74 
     | 
    
         
            +
                               with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41]).
         
     | 
| 
      
 75 
     | 
    
         
            +
                               and_return([0x86, 0x31])
         
     | 
| 
      
 76 
     | 
    
         
            +
                mock
         
     | 
| 
      
 77 
     | 
    
         
            +
              end  
         
     | 
| 
      
 78 
     | 
    
         
            +
              def lose_apdu
         
     | 
| 
      
 79 
     | 
    
         
            +
                win_apdu
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              def test_iso_apdu
         
     | 
| 
      
 83 
     | 
    
         
            +
                assert_equal({:status => 0x9000, :data => [0x67, 0x31]},
         
     | 
| 
      
 84 
     | 
    
         
            +
                             win_mock.iso_apdu(win_apdu))
         
     | 
| 
      
 85 
     | 
    
         
            +
                assert_equal({:status => 0x8631, :data => []},
         
     | 
| 
      
 86 
     | 
    
         
            +
                             lose_mock.iso_apdu(lose_apdu))
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
              
         
     | 
| 
      
 89 
     | 
    
         
            +
              def test_iso_apdu_bang
         
     | 
| 
      
 90 
     | 
    
         
            +
                assert_equal [0x67, 0x31], win_mock.iso_apdu!(win_apdu)
         
     | 
| 
      
 91 
     | 
    
         
            +
                assert_raise(RuntimeError) do
         
     | 
| 
      
 92 
     | 
    
         
            +
                  lose_mock.iso_apdu!(lose_apdu)
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,87 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Author:: Victor Costan
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
         
     | 
| 
      
 3 
     | 
    
         
            +
            # License:: MIT
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require 'smartcard'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'flexmock/test_unit'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            # Tests JcopRemoteProtocol, JcopRemoteServer, and JcopRemoteTransport.
         
     | 
| 
      
 14 
     | 
    
         
            +
            class JcopRemoteTest < Test::Unit::TestCase
         
     | 
| 
      
 15 
     | 
    
         
            +
              Protocol = Smartcard::Iso::JcopRemoteProtocol
         
     | 
| 
      
 16 
     | 
    
         
            +
              Server = Smartcard::Iso::JcopRemoteServer
         
     | 
| 
      
 17 
     | 
    
         
            +
              Transport = Smartcard::Iso::JcopRemoteTransport
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              # Serving logic that records what it receives and replays a log.
         
     | 
| 
      
 20 
     | 
    
         
            +
              class Logic
         
     | 
| 
      
 21 
     | 
    
         
            +
                include Protocol
         
     | 
| 
      
 22 
     | 
    
         
            +
                attr_reader :received
         
     | 
| 
      
 23 
     | 
    
         
            +
                def initialize(responses)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @responses = responses
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @received = []
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
                def connection_start
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @received << :start
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                def connection_end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @received << :end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                def exchange_apdu(apdu)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @received << apdu
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @responses.shift
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
              
         
     | 
| 
      
 39 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 40 
     | 
    
         
            +
                @server = Server.new(:ip => '127.0.0.1', :port => 51995)
         
     | 
| 
      
 41 
     | 
    
         
            +
                @client = Transport.new :host => '127.0.0.1', :port => 51995
         
     | 
| 
      
 42 
     | 
    
         
            +
                @old_abort_on_exception = Thread.abort_on_exception
         
     | 
| 
      
 43 
     | 
    
         
            +
                Thread.abort_on_exception = true
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
              
         
     | 
| 
      
 46 
     | 
    
         
            +
              def teardown
         
     | 
| 
      
 47 
     | 
    
         
            +
                Thread.abort_on_exception = @old_abort_on_exception
         
     | 
| 
      
 48 
     | 
    
         
            +
                @server.stop
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              def test_apdu_exchange
         
     | 
| 
      
 52 
     | 
    
         
            +
                apdu_request = [0x31, 0x41, 0x59, 0x26, 0x53]
         
     | 
| 
      
 53 
     | 
    
         
            +
                apdu_response = [0x27, 0x90, 0x00]
         
     | 
| 
      
 54 
     | 
    
         
            +
                
         
     | 
| 
      
 55 
     | 
    
         
            +
                logic = Logic.new([apdu_response])
         
     | 
| 
      
 56 
     | 
    
         
            +
                Thread.new do
         
     | 
| 
      
 57 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @server.run logic
         
     | 
| 
      
 59 
     | 
    
         
            +
                  rescue Exception
         
     | 
| 
      
 60 
     | 
    
         
            +
                    print $!, "\n"
         
     | 
| 
      
 61 
     | 
    
         
            +
                    print $!.backtrace.join("\n")
         
     | 
| 
      
 62 
     | 
    
         
            +
                    raise
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
                Kernel.sleep 0.05  # Wait for the server to start up.
         
     | 
| 
      
 66 
     | 
    
         
            +
                @client.connect
         
     | 
| 
      
 67 
     | 
    
         
            +
                assert_equal apdu_response, @client.exchange_apdu(apdu_request)
         
     | 
| 
      
 68 
     | 
    
         
            +
                @client.disconnect
         
     | 
| 
      
 69 
     | 
    
         
            +
                Kernel.sleep 0.05  # Wait for the server to process the disconnect.
         
     | 
| 
      
 70 
     | 
    
         
            +
                assert_equal [:start, apdu_request, :end], logic.received
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
              
         
     | 
| 
      
 73 
     | 
    
         
            +
              def test_java_card_integration
         
     | 
| 
      
 74 
     | 
    
         
            +
                apdu_request = [0x00, 0x31, 0x41, 0x59, 0x00]
         
     | 
| 
      
 75 
     | 
    
         
            +
                apdu_response = [0x27, 0x90, 0x00]
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                logic = Logic.new([apdu_response])
         
     | 
| 
      
 78 
     | 
    
         
            +
                Thread.new { @server.run logic }
         
     | 
| 
      
 79 
     | 
    
         
            +
                Kernel.sleep 0.05  # Wait for the server to start up.
         
     | 
| 
      
 80 
     | 
    
         
            +
                @client.connect
         
     | 
| 
      
 81 
     | 
    
         
            +
                assert_equal [0x27],
         
     | 
| 
      
 82 
     | 
    
         
            +
                             @client.iso_apdu!(:ins => 0x31, :p1 => 0x41, :p2 => 0x59)
         
     | 
| 
      
 83 
     | 
    
         
            +
                @client.disconnect
         
     | 
| 
      
 84 
     | 
    
         
            +
                Kernel.sleep 0.05  # Wait for the server to process the disconnect.
         
     | 
| 
      
 85 
     | 
    
         
            +
                assert_equal [:start, apdu_request, :end], logic.received
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
            end
         
     | 
    
        data/tests/ts_pcsc_ext.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification 
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: smartcard
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version 
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.4.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: x86-mswin32-60
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors: 
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Victor Costan
         
     | 
| 
         @@ -9,7 +9,7 @@ autorequire: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            date: 2009- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2009-08-19 00:00:00 -04:00
         
     | 
| 
       13 
13 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       14 
14 
     | 
    
         
             
            dependencies: []
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
         @@ -35,7 +35,15 @@ extra_rdoc_files: 
     | 
|
| 
       35 
35 
     | 
    
         
             
            - ext/smartcard_pcsc/pcsc_reader_states.c
         
     | 
| 
       36 
36 
     | 
    
         
             
            - ext/smartcard_pcsc/pcsc_surrogate_reader.h
         
     | 
| 
       37 
37 
     | 
    
         
             
            - ext/smartcard_pcsc/pcsc_surrogate_wintypes.h
         
     | 
| 
       38 
     | 
    
         
            -
            - lib/smartcard/ 
     | 
| 
      
 38 
     | 
    
         
            +
            - lib/smartcard/gp/gp_card_mixin.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            - lib/smartcard/iso/auto_configurator.rb
         
     | 
| 
      
 40 
     | 
    
         
            +
            - lib/smartcard/iso/iso_card_mixin.rb
         
     | 
| 
      
 41 
     | 
    
         
            +
            - lib/smartcard/iso/jcop_remote_protocol.rb
         
     | 
| 
      
 42 
     | 
    
         
            +
            - lib/smartcard/iso/jcop_remote_server.rb
         
     | 
| 
      
 43 
     | 
    
         
            +
            - lib/smartcard/iso/jcop_remote_transport.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            - lib/smartcard/iso/pcsc_transport.rb
         
     | 
| 
      
 45 
     | 
    
         
            +
            - lib/smartcard/iso/transport.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/smartcard/pcsc/pcsc_exception.rb
         
     | 
| 
       39 
47 
     | 
    
         
             
            - lib/smartcard.rb
         
     | 
| 
       40 
48 
     | 
    
         
             
            - LICENSE
         
     | 
| 
       41 
49 
     | 
    
         
             
            - README
         
     | 
| 
         @@ -55,16 +63,28 @@ files: 
     | 
|
| 
       55 
63 
     | 
    
         
             
            - ext/smartcard_pcsc/pcsc_reader_states.c
         
     | 
| 
       56 
64 
     | 
    
         
             
            - ext/smartcard_pcsc/pcsc_surrogate_reader.h
         
     | 
| 
       57 
65 
     | 
    
         
             
            - ext/smartcard_pcsc/pcsc_surrogate_wintypes.h
         
     | 
| 
       58 
     | 
    
         
            -
            - lib/smartcard/ 
     | 
| 
      
 66 
     | 
    
         
            +
            - lib/smartcard/gp/gp_card_mixin.rb
         
     | 
| 
      
 67 
     | 
    
         
            +
            - lib/smartcard/iso/auto_configurator.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
            - lib/smartcard/iso/iso_card_mixin.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
            - lib/smartcard/iso/jcop_remote_protocol.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            - lib/smartcard/iso/jcop_remote_server.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
            - lib/smartcard/iso/jcop_remote_transport.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            - lib/smartcard/iso/pcsc_transport.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
            - lib/smartcard/iso/transport.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
            - lib/smartcard/pcsc/pcsc_exception.rb
         
     | 
| 
       59 
75 
     | 
    
         
             
            - lib/smartcard.rb
         
     | 
| 
       60 
76 
     | 
    
         
             
            - LICENSE
         
     | 
| 
       61 
77 
     | 
    
         
             
            - Manifest
         
     | 
| 
      
 78 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
       62 
79 
     | 
    
         
             
            - README
         
     | 
| 
       63 
     | 
    
         
            -
            - test/test_containers.rb
         
     | 
| 
       64 
     | 
    
         
            -
            - test/test_smoke.rb
         
     | 
| 
       65 
     | 
    
         
            -
            - tests/ts_pcsc_ext.rb
         
     | 
| 
       66 
80 
     | 
    
         
             
            - smartcard.gemspec
         
     | 
| 
       67 
     | 
    
         
            -
            -  
     | 
| 
      
 81 
     | 
    
         
            +
            - test/gp/gp_card_mixin_test.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - test/iso/auto_configurator_test.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - test/iso/iso_card_mixin_test.rb
         
     | 
| 
      
 84 
     | 
    
         
            +
            - test/iso/jcop_remote_test.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - test/pcsc/containers_test.rb
         
     | 
| 
      
 86 
     | 
    
         
            +
            - test/pcsc/smoke_test.rb
         
     | 
| 
      
 87 
     | 
    
         
            +
            - tests/ts_pcsc_ext.rb
         
     | 
| 
       68 
88 
     | 
    
         
             
            - lib/smartcard/pcsc.so
         
     | 
| 
       69 
89 
     | 
    
         
             
            has_rdoc: true
         
     | 
| 
       70 
90 
     | 
    
         
             
            homepage: http://www.costan.us/smartcard
         
     | 
| 
         @@ -96,10 +116,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       96 
116 
     | 
    
         
             
            requirements: []
         
     | 
| 
       97 
117 
     | 
    
         | 
| 
       98 
118 
     | 
    
         
             
            rubyforge_project: smartcard
         
     | 
| 
       99 
     | 
    
         
            -
            rubygems_version: 1.3. 
     | 
| 
      
 119 
     | 
    
         
            +
            rubygems_version: 1.3.5
         
     | 
| 
       100 
120 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       101 
121 
     | 
    
         
             
            specification_version: 3
         
     | 
| 
       102 
122 
     | 
    
         
             
            summary: Interface with ISO 7816 smart cards.
         
     | 
| 
       103 
123 
     | 
    
         
             
            test_files: 
         
     | 
| 
       104 
     | 
    
         
            -
            - test/ 
     | 
| 
       105 
     | 
    
         
            -
            - test/ 
     | 
| 
      
 124 
     | 
    
         
            +
            - test/gp/gp_card_mixin_test.rb
         
     | 
| 
      
 125 
     | 
    
         
            +
            - test/iso/auto_configurator_test.rb
         
     | 
| 
      
 126 
     | 
    
         
            +
            - test/iso/iso_card_mixin_test.rb
         
     | 
| 
      
 127 
     | 
    
         
            +
            - test/iso/jcop_remote_test.rb
         
     | 
| 
      
 128 
     | 
    
         
            +
            - test/pcsc/containers_test.rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            - test/pcsc/smoke_test.rb
         
     |