diff options
author | Kevin Redon <kevredon@mail.tsaitgaist.info> | 2011-05-02 11:39:55 +0200 |
---|---|---|
committer | Kevin Redon <kevredon@mail.tsaitgaist.info> | 2011-05-02 11:39:55 +0200 |
commit | 863a4a26e52d01593e162063dd338ceffbf350c6 (patch) | |
tree | ab9f1f92648589f5d586abc817c4682edf1c0321 | |
parent | c36d3614ed4560762e9712387fcdabba400ca36a (diff) |
restructured files organisation
-rwxr-xr-x | lib/sim_server.rb | 67 | ||||
-rw-r--r-- | nbproject/project.properties | 7 | ||||
-rw-r--r-- | nbproject/project.xml | 16 | ||||
-rwxr-xr-x | src/apdu_client.rb (renamed from lib/apdu_client.rb) | 2 | ||||
-rw-r--r-- | src/bluetooth_client.rb (renamed from lib/bluetooth_client.rb) | 4 | ||||
-rwxr-xr-x | src/demo_client.rb (renamed from lib/demo_client.rb) | 11 | ||||
-rw-r--r-- | src/lib/client.rb (renamed from lib/client.rb) | 4 | ||||
-rw-r--r-- | src/lib/common.rb (renamed from lib/common.rb) | 0 | ||||
-rw-r--r-- | src/lib/server.rb (renamed from lib/server.rb) | 2 | ||||
-rwxr-xr-x | src/pcsc_server.rb (renamed from lib/pcsc_server.rb) | 10 | ||||
-rwxr-xr-x | src/sim_server.rb | 234 |
11 files changed, 252 insertions, 105 deletions
diff --git a/lib/sim_server.rb b/lib/sim_server.rb deleted file mode 100755 index a6e2f97..0000000 --- a/lib/sim_server.rb +++ /dev/null @@ -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
\ No newline at end of file diff --git a/nbproject/project.properties b/nbproject/project.properties deleted file mode 100644 index 38e19b2..0000000 --- a/nbproject/project.properties +++ /dev/null @@ -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 diff --git a/nbproject/project.xml b/nbproject/project.xml deleted file mode 100644 index bf56132..0000000 --- a/nbproject/project.xml +++ /dev/null @@ -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> diff --git a/lib/apdu_client.rb b/src/apdu_client.rb index 68042ec..8514bcf 100755 --- a/lib/apdu_client.rb +++ b/src/apdu_client.rb @@ -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" diff --git a/lib/bluetooth_client.rb b/src/bluetooth_client.rb index 0b6290e..bf69a0a 100644 --- a/lib/bluetooth_client.rb +++ b/src/bluetooth_client.rb @@ -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
\ No newline at end of file +end diff --git a/lib/demo_client.rb b/src/demo_client.rb index 44b93f5..264ee73 100755 --- a/lib/demo_client.rb +++ b/src/demo_client.rb @@ -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 diff --git a/lib/client.rb b/src/lib/client.rb index c6dff7a..2edd815 100644 --- a/lib/client.rb +++ b/src/lib/client.rb @@ -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
\ No newline at end of file +end diff --git a/lib/common.rb b/src/lib/common.rb index 5076ddd..5076ddd 100644 --- a/lib/common.rb +++ b/src/lib/common.rb diff --git a/lib/server.rb b/src/lib/server.rb index fa043ca..68c073a 100644 --- a/lib/server.rb +++ b/src/lib/server.rb @@ -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) : diff --git a/lib/pcsc_server.rb b/src/pcsc_server.rb index b38b264..641560e 100755 --- a/lib/pcsc_server.rb +++ b/src/pcsc_server.rb @@ -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
\ No newline at end of file +server.start diff --git a/src/sim_server.rb b/src/sim_server.rb new file mode 100755 index 0000000..ae4826b --- /dev/null +++ b/src/sim_server.rb @@ -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 |