10
0
Fork 0

better apdu methods

This commit is contained in:
Kevin Redon 2011-04-30 16:41:33 +02:00
parent beda761dc0
commit c36d3614ed
2 changed files with 190 additions and 11 deletions

View File

@ -2,6 +2,10 @@
# This programm will create a client which can be used to test servers
require 'client'
#=================
#== client type ==
#=================
# wich IO to use
client_io = :tcp
# the IO itself
@ -30,17 +34,192 @@ else
raise "please defined which client to use"
end
client = Client.new(io)
client.start
client.connect
atr = client.atr
puts atr ? "ATR : #{atr.collect{|x| x.to_s(16).rjust(2,'0')}*' '}" : "could not get ATR"
#===============
#== constants ==
#===============
# to debug the program
# shows APDU IO
DEBUG = true
# the verbosity from common
VERBOSE = 0
# APDU constants (TS 102.221 10.1.2)
# SIM Class code (TS 51.011 9.2)
CLASS = 0xA0
# add the address (2 bytes) to the select command (TS 51.011 9.2.1)
SELECT = [CLASS, 0xA4, 0x00, 0x00, 0x02]
# get the response after a select (TS 51.011 9.1)
# add the length (P3) to get the information (= SW2 after SELECT)
GET_RESPONSE = [CLASS, 0xC0, 0x00, 0x00]
STATUS = [CLASS, 0xF2, 0x00, 0x00]
# add the length (P3) to have complete command
READ_BINARY = [CLASS,0xB0]
READ_RECORD = [CLASS,0xB2]
UPDATE_RECORD = [CLASS,0xDC]
CHV1 = [CLASS,0x20,0x00,0x01,0x08]
A38 = [CLASS,0x88,0x00,0x00,0x10]
# file address (TS 51.011 10.7, page 105)
MF = [0x3F,0x00]
#=========================
#== additionnal methods ==
#=========================
# transform binary string into readable hex string
class String
def to_hex_disp
to_return = ""
each_byte do |b|
to_return += b.to_s(16).rjust(2,"0")
to_return += " "
end
return to_return[0..-2].upcase
end
def to_hex
to_return = ""
each_byte do |b|
to_return += b.to_s(16).rjust(2,"0")
end
return "0x"+(to_return.downcase)
end
def char_at(index)
i=0
each_char do |c|
if i==index then
return c
else
i+=1
end
end
return nil
end
end
# reverse the nibbles of each byte
class Array
# print the nibbles (often BCD)
# - padding : the 0xf can be ignored (used as padding in BCD)
def nibble_str(padding=false)
# get nibble representation
to_return = collect { |b| (b&0x0F).to_s(16)+(b>>4).to_s(16) }
to_return = to_return.join
# remove the padding
to_return.gsub!('f',"") if padding
return to_return
end
def to_hex_disp
to_return = ""
each do |b|
to_return += b.to_s(16).rjust(2,"0")
to_return += " "
end
return to_return[0..-2].upcase
end
def to_hex
to_return = ""
each do |b|
to_return += b.to_s(16).rjust(2,"0")
end
return "0x"+(to_return.downcase)
end
end
#=============
#== methods ==
#=============
# send APDU (byte array) to card
# returns [response,sw1,sw2]
def transmit (apdu)
# send APDU
puts "< "+apdu.to_hex_disp if DEBUG
resp = @client.apdu(apdu)
puts "> "+resp.to_hex_disp if DEBUG
# parse response
response = resp[0..-3]
sw1 = resp[-2]
sw2 = resp[-1]
sw_check(sw1,sw2)
return response,sw1,sw2
end
# check if there is an error
# TS 51.011 9.4
def sw_check(sw1,sw2)
# verb for the exception
head = "SW error. "
category = ""
sw = " (#{sw1.to_s(16).rjust(2,'0')},#{sw2.to_s(16).rjust(2,'0')})"
error = nil
case sw1
when 0x94
category = "referencing management"
case sw2
when 0x00
error = "no EF selected"
when 0x02
error = "out of range (invalid address)"
when 0x04
error = "file ID not found/pattern not found"
when 0x08
error = "file is inconsistent with the command"
else
error = "unknown"
end
when 0x98
if sw2==0x04 then
error = "not allowed or wrong PIN"
else
error = "security error"
end
when 0x6B
error = "incorrect P1 or P2"
when 0x67
category = "application independent errors"
error = "incorrect P3"
else
if sw1!=0x9F and sw1!=0x90 then
error = "unknown response"
end
end
raise head+category+" : "+error+sw if error
end
# select a file. returns the response
def select(file)
# select file
response, sw1, sw2 = transmit(SELECT+file)
# get response
response, sw1, sw2 = transmit(GET_RESPONSE+[sw2])
return response
end
#==========
#== main ==
#==========
@client = Client.new(io,VERBOSE)
@client.start
@client.connect
atr = @client.atr
puts atr ? "ATR : #{atr.to_hex_disp}" : "could not get ATR"
# select MF
apdu_req = [0xA0,0xA4,0x00,0x00,0x02,0x3F,0x00]
puts "APDU request : #{apdu_req.collect{|x| x.to_s(16).rjust(2,'0')}*' '}"
apdu_resp = client.apdu(apdu_req)
puts apdu_resp ? "APDU response : #{apdu_resp.collect{|x| x.to_s(16).rjust(2,'0')}*' '}" : "could not get APDU response"
client.disconnect
transmit(SELECT+MF)
@client.disconnect
# close client_io
case client_io
@ -49,4 +228,4 @@ when :tcp
when :bt
io.close
bt.close
end
end

View File

@ -131,4 +131,4 @@ class Server < SAP
end
end
end
end