restructured files organisation
This commit is contained in:
parent
c36d3614ed
commit
863a4a26e5
|
@ -1,67 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'server'
|
||||
require 'socket'
|
||||
require 'xml'
|
||||
|
||||
class String
|
||||
# convert a hexadecimal string into binary array
|
||||
def hex2arr
|
||||
arr = []
|
||||
(self.length/2).times do |i|
|
||||
arr << self[i*2,2].to_i(16)
|
||||
end
|
||||
return arr
|
||||
end
|
||||
end
|
||||
|
||||
# SAP server using a SIM backup file
|
||||
class SIMServer < Server
|
||||
|
||||
def initialize(io,path="sim.xml")
|
||||
super(io)
|
||||
@xml_path = path
|
||||
end
|
||||
|
||||
# read file
|
||||
def connect
|
||||
|
||||
begin
|
||||
xml = IO.read(@xml_path)
|
||||
doc = XML::Parser.string(xml)
|
||||
@card = doc.parse
|
||||
rescue
|
||||
puts "can't read #{@xml_path}"
|
||||
status = create_message("STATUS_IND",[[0x08,[0x02]]])
|
||||
send(status)
|
||||
sleep 1
|
||||
redo
|
||||
end
|
||||
|
||||
# card ready
|
||||
# ["StatusChange",["Card reset"]]
|
||||
status = create_message("STATUS_IND",[[0x08,[0x01]]])
|
||||
send(status)
|
||||
log("server","connection established. SIM loaded",3)
|
||||
end
|
||||
|
||||
# get ATR
|
||||
def atr
|
||||
raise "connect to card to get ATR" unless @card
|
||||
return @card.find_first("/sim")["atr"].hex2arr
|
||||
end
|
||||
|
||||
# send APDU and get response
|
||||
def apdu(request)
|
||||
raise "connect to card to send APDU" unless @card
|
||||
raise "not implemented"
|
||||
response = @card.transmit(request.pack('C*')).unpack("C*")
|
||||
return response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# demo application, using TCP socket
|
||||
socket = TCPServer.new("localhost",1337)
|
||||
io = socket.accept
|
||||
server = SIMServer.new(io)
|
||||
server.start
|
|
@ -1,7 +0,0 @@
|
|||
javac.classpath=
|
||||
main.file=main.rb
|
||||
platform.active=default
|
||||
source.encoding=UTF-8
|
||||
spec.src.dir=spec
|
||||
src.dir=lib
|
||||
test.src.dir=test
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.ruby.rubyproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/ruby-project/1">
|
||||
<name>SAP</name>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
<root id="spec.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env ruby
|
||||
# This programm will forward APDU from a TCP port to a SAP server
|
||||
require 'lib/client'
|
||||
require 'socket'
|
||||
require 'client'
|
||||
|
||||
SAP_HOST = "localhost"
|
||||
SAP_PORT = "1337"
|
|
@ -1,4 +1,4 @@
|
|||
require 'client' # SAP client
|
||||
require 'lib/client' # SAP client
|
||||
require 'dbus' # libdbus-ruby
|
||||
|
||||
# class to connect to BT SAP server using BlueZ over dbus
|
||||
|
@ -254,4 +254,4 @@ class BluetoothClient
|
|||
@bt_adapter.RemoveDevice(@bt_sap.path) unless @trusted or @paired
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env ruby
|
||||
# This programm will create a client which can be used to test servers
|
||||
require 'client'
|
||||
require 'lib/client'
|
||||
|
||||
#=================
|
||||
#== client type ==
|
||||
|
@ -62,6 +62,11 @@ A38 = [CLASS,0x88,0x00,0x00,0x10]
|
|||
|
||||
# file address (TS 51.011 10.7, page 105)
|
||||
MF = [0x3F,0x00]
|
||||
EF_ICCID = [0x2F,0xE2]
|
||||
DF_GSM = [0x7F,0x20]
|
||||
EF_IMSI = [0x6F,0x07] # TS 51.011 10.3.2
|
||||
DF_TELECOM = [0x7F,0x10]
|
||||
EF_MSISDN = [0x6F,0x40] # TS 51.011 10.5.5
|
||||
|
||||
#=========================
|
||||
#== additionnal methods ==
|
||||
|
@ -217,8 +222,8 @@ end
|
|||
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]
|
||||
transmit(SELECT+MF)
|
||||
transmit(GET_RESPONSE+[0x1a])
|
||||
select(MF)
|
||||
@client.disconnect
|
||||
|
||||
# close client_io
|
|
@ -1,6 +1,6 @@
|
|||
# this is the client part of the SAP
|
||||
# it implements the state machine for the client
|
||||
require 'common'
|
||||
require 'lib/common'
|
||||
|
||||
# this is an abstract class
|
||||
# TODO :
|
||||
|
@ -198,4 +198,4 @@ class Client < SAP
|
|||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
# this is the server part of the SAP
|
||||
# it implements the state machine for the server
|
||||
# this is an abstract class
|
||||
require 'common'
|
||||
require 'lib/common'
|
||||
|
||||
# this is an bastract class
|
||||
# TODO (not implemented) :
|
|
@ -1,16 +1,14 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'server'
|
||||
require 'lib/server'
|
||||
require 'socket'
|
||||
require 'rubygems'
|
||||
require 'smartcard'
|
||||
=begin
|
||||
need to install
|
||||
sudo aptitude install ruby ruby-dev rubygems
|
||||
sudo aptitude install libpcsclite1 libpcsclite-dev libruby
|
||||
sudo gem install smartcard (http://www.rubygems.org/gems/smartcard)
|
||||
=end
|
||||
require 'rubygems'
|
||||
# smartcard 0.5.1 can not handle T=0 because of a FFI::Enum bug
|
||||
# patch existing
|
||||
require 'smartcard'
|
||||
|
||||
# SAP server using PCSC for the card
|
||||
class PCSCServer < Server
|
||||
|
@ -98,4 +96,4 @@ end
|
|||
socket = TCPServer.new("localhost",1337)
|
||||
io = socket.accept
|
||||
server = PCSCServer.new(io)
|
||||
server.start
|
||||
server.start
|
|
@ -0,0 +1,234 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'server'
|
||||
require 'socket'
|
||||
require 'xml'
|
||||
|
||||
# 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
|
||||
#to_return = "0x"+to_return
|
||||
return to_return.downcase
|
||||
end
|
||||
|
||||
# convert a hexadecimal string into binary array
|
||||
def hex2arr
|
||||
arr = []
|
||||
(self.length/2).times do |i|
|
||||
arr << self[i*2,2].to_i(16)
|
||||
end
|
||||
return arr
|
||||
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
|
||||
#to_return = "0x"+to_return
|
||||
return to_return.downcase
|
||||
end
|
||||
end
|
||||
|
||||
# SAP server using a SIM backup file
|
||||
class SIMServer < Server
|
||||
|
||||
def initialize(io,path="sim.xml")
|
||||
super(io)
|
||||
@xml_path = path
|
||||
end
|
||||
|
||||
#====================
|
||||
#== main functions ==
|
||||
#====================
|
||||
|
||||
# read file
|
||||
def connect
|
||||
|
||||
begin
|
||||
xml = IO.read(@xml_path)
|
||||
doc = XML::Parser.string(xml)
|
||||
@card = doc.parse
|
||||
rescue
|
||||
puts "can't read #{@xml_path}"
|
||||
status = create_message("STATUS_IND",[[0x08,[0x02]]])
|
||||
send(status)
|
||||
sleep 1
|
||||
redo
|
||||
end
|
||||
|
||||
# select MF
|
||||
node = select([0x3f,0x00])
|
||||
@response = node.find_first("./header").content.hex2arr
|
||||
|
||||
# card ready
|
||||
# ["StatusChange",["Card reset"]]
|
||||
status = create_message("STATUS_IND",[[0x08,[0x01]]])
|
||||
send(status)
|
||||
log("server","connection established. SIM loaded",3)
|
||||
end
|
||||
|
||||
# get ATR
|
||||
def atr
|
||||
raise "connect to card to get ATR" unless @card
|
||||
return @card.find_first("/sim")["atr"].hex2arr
|
||||
end
|
||||
|
||||
# send APDU and get response
|
||||
def apdu(request)
|
||||
raise "connect to card to send APDU" unless @card
|
||||
# check the size
|
||||
return [0x6f,0x00] unless request.length>=5
|
||||
# I can only handle SIM APDU (class A0)
|
||||
return [0x6e,0x00] unless request[0]==0xa0
|
||||
# default
|
||||
data = []
|
||||
sw = [0x6f,0x00]
|
||||
# the instruction
|
||||
case request[1]
|
||||
when 0xa4 # SELECT
|
||||
# remove the last response
|
||||
@response = nil
|
||||
# verify the apdu
|
||||
if request[2,2]!=[0x00,0x00] then
|
||||
# incorrect parameter P1 or P2
|
||||
sw = [0x6b,0x00]
|
||||
elsif request[4]!=0x02 then
|
||||
# incorrect parameter P3
|
||||
sw = [0x67,0x02]
|
||||
else
|
||||
# is the file ID present ?
|
||||
if request.length==7 then
|
||||
# check if the directory can be selected
|
||||
file_id = request[5,2]
|
||||
node = select(file_id)
|
||||
if node then
|
||||
# file selected, response awaiting
|
||||
@response = node.find_first("./header").content.hex2arr
|
||||
sw = [0x9f,@response.length]
|
||||
log("APDU select","file selected : #{file_id.to_hex_disp}",3)
|
||||
else
|
||||
# out of range (invalid address)
|
||||
sw = [0x94,0x02]
|
||||
log("APDU select","file not found/accessible : #{file_id.to_hex_disp}",3)
|
||||
end
|
||||
else
|
||||
# out of range (invalid address)
|
||||
sw = [0x94,0x02]
|
||||
log("APDU select","file not found/accessible : #{file_id.to_hex_disp}",3)
|
||||
end
|
||||
end
|
||||
when 0xc0 # GET RESPONSE
|
||||
# verify the apdu
|
||||
if request[2,2]!=[0x00,0x00] then
|
||||
# incorrect parameter P1 or P2
|
||||
sw = [0x6b,0x00]
|
||||
elsif !@response then
|
||||
# technical problem with no diagnostic given
|
||||
sw = [0x6f,0x00]
|
||||
elsif request[4]!=@response.length then
|
||||
# incorrect parameter P3
|
||||
sw = [0x67,@response.length]
|
||||
else
|
||||
# return the response
|
||||
data = @response
|
||||
sw = [0x90,0x00]
|
||||
end
|
||||
else # unknown instruction byte
|
||||
sw = [0x6d,0x00]
|
||||
end
|
||||
return data+sw
|
||||
end
|
||||
|
||||
#===================
|
||||
#== SIM functions ==
|
||||
#===================
|
||||
|
||||
# select file using the file ID
|
||||
# node representing the file is returned
|
||||
# nil is return if file does not exist or is unaccessible
|
||||
def select (id)
|
||||
response = nil
|
||||
# get the current location
|
||||
if @pwd then
|
||||
# get current directory
|
||||
dfs = [0x3f,0x5f,0x7f]
|
||||
if dfs.include? @pwd["id"][0,2].to_i(16) then
|
||||
current_directory = @pwd
|
||||
else
|
||||
current_directory = @pwd.find_first("..")
|
||||
end
|
||||
# find file
|
||||
if result=current_directory.find_first("./file[@id='#{id.to_hex}']") then
|
||||
# any file which is an immediate child of the current directory
|
||||
response = result
|
||||
elsif dfs.include? current_directory["id"][0,2].to_i(16) and result=current_directory.find_first("../file[@id='#{id.to_hex}']") then
|
||||
# any DF which is an immediate child of the parent of the current DF
|
||||
response = result
|
||||
elsif result=current_directory.find_first("..") and result["id"]==id.to_hex then
|
||||
# the parent of the current directory
|
||||
response = result
|
||||
elsif current_directory["id"]==id.to_hex then
|
||||
# the current DF
|
||||
response = current_directory
|
||||
elsif id==[0x3f,0x00] then
|
||||
# the MF
|
||||
response = @card.find_first("/sim/file[@id='3f00']")
|
||||
else
|
||||
response = nil
|
||||
end
|
||||
@pwd = response if response
|
||||
else
|
||||
# only MF is accessible
|
||||
if id==[0x3f,0x00] then
|
||||
@pwd = @card.find_first("/sim/file[@id='3f00']")
|
||||
response = @pwd
|
||||
else
|
||||
response=nil
|
||||
end
|
||||
end
|
||||
return response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# demo application, using TCP socket
|
||||
socket = TCPServer.new("localhost",1337)
|
||||
io = socket.accept
|
||||
server = SIMServer.new(io)
|
||||
server.start
|
Loading…
Reference in New Issue