Module: Smartcard::Gp::CapLoader

Defined in:
lib/smartcard/gp/cap_loader.rb

Overview

Logic for loading JavaCard CAP files.

Constant Summary collapse

TAG_NAMES =

Maps numeric tags to tag names.

{
  1 => :header, 2 => :directory, 3 => :applet, 4 => :import,
  5 => :constant_pool, 6 => :class, 7 => :method, 8 => :static_field,
  9 => :reference_location, 10 => :export, 11 => :descriptor, 12 => :debug
}
HEADER_FLAGS =

Masks for flags in the Header section.

[[:int_support, 1], [:has_exports, 2], [:has_applets, 4]]

Class Method Summary collapse

Class Method Details

.cap_load_data(cap_file) ⇒ Object

Loads a CAP file and serializes its components for on-card loading.

Returns a hash with the following keys:

:data:: array of bytes containing the executable load file for the CAP
:applets:: array of hashes, one for each applet in the CAP  
           (see parse_applets)
:header:: information about the CAP's header (see parse_header)


107
108
109
110
111
112
# File 'lib/smartcard/gp/cap_loader.rb', line 107

def self.cap_load_data(cap_file)
  components = load_cap cap_file
  { :data => serialize_components(components),
    :applets => parse_applets(components),
    :header => parse_header(components) } 
end

.load_cap(cap_file) ⇒ Object

Loads a CAP file.

Returns a hash mapping component names to component data.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/smartcard/gp/cap_loader.rb', line 19

def self.load_cap(cap_file)
  components = {}    
  Zip::ZipFile.open(cap_file) do |file|
    file.each do |entry|
      data = entry.get_input_stream { |io| io.read }
      offset = 0
      while offset < data.length          
        tag = TAG_NAMES[data[offset, 1].unpack('C').first]
        length = data[offset + 1, 2].unpack('n').first
        value = data[offset + 3, length]
        components[tag] = value
        offset += 3 + length
      end
    end
  end    
  components
end

.parse_applets(components) ⇒ Object

Parses the Applet section in a CAP file, obtaining applet AIDs.

Returns an array of hashes, one hash per applet. The hash has a key :aid that contains the applet’s AID.



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/smartcard/gp/cap_loader.rb', line 58

def self.parse_applets(components)    
  applets = []
  return applets unless section = components[:applet]
  offset = 1
  section[0].ord.times do
    aid_length = section[offset].ord
    install_method = section[offset + 1 + aid_length, 2].unpack('n').first
    applets << { :aid => section[offset + 1, aid_length].unpack('C*'),
                 :install_method => install_method }
    offset += 3 + aid_length
  end
  applets
end

.parse_header(components) ⇒ Object

Parses the Header section in a CAP file, obtaining package AIDs.

Returns a hash with the following keys:

:magic:: the header magic value
:version:: the CAP specification version (has :minor and :major keys)
:flags:: Set of package flags (see HEADER_FLAGS)
:package:: package information, has the following keys:
           :version:: package version (has :minor and :major keys)
           :aid:: the package's AID
           :name:: the package's name (may be absent)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/smartcard/gp/cap_loader.rb', line 82

def self.parse_header(components)
  component = components[:header]
  header = { :magic => component[0, 4].unpack('N').first,
      :version => { :minor => component[4].ord,
                    :major => component[5].ord } }    
  header[:flags] = Set.new(HEADER_FLAGS.select { |flag, mask|
      (component[6].ord & mask) == mask }.map { |flag, mask| flag })
  header[:package] = { :version => { :minor => component[7].ord,
                                     :major => component[8].ord }}
  aid_length = component[9].ord
  header[:package][:aid] = component[10, aid_length].unpack('C*')
  if component.length > 10 + aid_length
    name_length = component[10 + aid_length].ord
    header[:package][:name] = component[11 + aid_length, name_length]
  end
  header
end

.serialize_components(components) ⇒ Object

Serializes CAP components for on-card loading.

Returns an array of bytes.



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/smartcard/gp/cap_loader.rb', line 40

def self.serialize_components(components)
  [:header, :directory, :import, :applet, :class, :method, :static_field,
   :export, :constant_pool, :reference_location].map { |name|
    tag = TAG_NAMES.keys.find { |k| TAG_NAMES[k] == name }
    if components[name]
      length = [components[name].length].pack('n').unpack('C*')
      data = components[name].unpack('C*')
      [tag, length, data]
    else
      []
    end
  }.flatten
end