10
0
Fork 0

restructured files organisation

This commit is contained in:
Kevin Redon 2011-05-02 11:39:55 +02:00
parent c36d3614ed
commit 863a4a26e5
11 changed files with 252 additions and 105 deletions

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) :

View File

@ -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

234
src/sim_server.rb Executable file
View File

@ -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