Module: Smartcard::Iso::IsoCardMixin

Included in:
Gp::GpCardMixin, JcopRemoteTransport, PcscTransport
Defined in:
lib/smartcard/iso/iso_card_mixin.rb

Overview

Module intended to be mixed into transport implementations to mediate between a high level format for ISO7816-specific APDUs and the wire-level APDU request and response formats.

The mix-in calls exchange_apdu in the transport implementation. It supplies the APDU data as an array of integers between 0 and 255, and expects a response in the same format.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.deserialize_response(response) ⇒ Object

De-serializes a ISO7816 response APDU.

:call-seq:

IsoCardMixin.deserialize_response(response) -> hash

The response contains the following keys:

status:: the 2-byte status code (e.g. 0x9000 is OK)
data:: the additional data in the response


90
91
92
# File 'lib/smartcard/iso/iso_card_mixin.rb', line 90

def self.deserialize_response(response)
  { :status => response[-2] * 256 + response[-1], :data => response[0...-2] }
end

.serialize_apdu(apdu_data) ⇒ Object

Serializes an APDU for wire transmission.

:call-seq:

IsoCardMixin.serialize_apdu(apdu_data) -> array

The following keys are recognized in the APDU hash:

cla:: the CLA byte in the APDU (optional, defaults to 0) 
ins:: the INS byte in the APDU -- the first byte seen by a JavaCard applet
p12:: 2-byte array containing the P1 and P2 bytes in the APDU
p1, p2:: the P1 and P2 bytes in the APDU (optional, both default to 0)
data:: the extra data in the APDU (optional, defaults to nothing)
le:: the expected data length (defaults to 0; set to +false+ to avoid
     sending an Le byte)


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/smartcard/iso/iso_card_mixin.rb', line 60

def self.serialize_apdu(apdu_data)
  raise 'Unspecified INS in apdu_data' unless apdu_data[:ins]
  apdu = [ apdu_data[:cla] || 0, apdu_data[:ins] ]
  if apdu_data[:p12]
    unless apdu_data[:p12].length == 2
      raise "Malformed P1,P2 - #{apdu_data[:p12]}"
    end
    apdu += apdu_data[:p12]
  else
    apdu << (apdu_data[:p1] || 0)
    apdu << (apdu_data[:p2] || 0)
  end
  if apdu_data[:data]
    apdu << apdu_data[:data].length
    apdu += apdu_data[:data]
  else
    apdu << 0
  end
  apdu << (apdu_data[:le] || 0) unless apdu_data[:le] == false
  apdu
end

Instance Method Details

#iso_apdu(apdu_data) ⇒ Object

Performs an APDU exchange with the ISO7816 card.

:call-seq:

transport.iso_apdu(apdu_data) -> hash

The apdu_data should be in the format expected by IsoCardMixin#serialize_apdu. The response will be as specified in IsoCardMixin#deserialize_response.



42
43
44
45
# File 'lib/smartcard/iso/iso_card_mixin.rb', line 42

def iso_apdu(apdu_data)
  response = self.exchange_apdu IsoCardMixin.serialize_apdu(apdu_data)
  IsoCardMixin.deserialize_response response
end

#iso_apdu!(apdu_data) ⇒ Object

APDU exchange with the ISO7816 card, raising an ApduError if the return code is not success (0x9000).

:call_seq:

transport.iso_apdu!(apdu_data) -> array

The apdu_data should be in the format expected by IsoCardMixin#serialize_apdu. Returns the response data, if the response status indicates success (0x9000). Otherwise, raises an ApduError.

Raises:



28
29
30
31
32
# File 'lib/smartcard/iso/iso_card_mixin.rb', line 28

def iso_apdu!(apdu_data)
  response = self.iso_apdu apdu_data
  return response[:data] if response[:status] == 0x9000
  raise ApduError, response
end