From 864997046bf6f81b73bb5a70a47d6f1db27b4498 Mon Sep 17 00:00:00 2001 From: Kevin Redon Date: Mon, 9 May 2011 15:22:24 +0200 Subject: [PATCH] info_client completely ported --- src/info_client.rb | 726 ++++++++++++++++++++++----------------------- 1 file changed, 361 insertions(+), 365 deletions(-) diff --git a/src/info_client.rb b/src/info_client.rb index 565d3d5..ce39c2f 100644 --- a/src/info_client.rb +++ b/src/info_client.rb @@ -28,6 +28,66 @@ require 'lib/apdu' class Info include APDU + + SERVICES = ["CHV1 disable function", + "Abbreviated Dialling Numbers (ADN)", + "Fixed Dialling Numbers (FDN)", + "Short Message Storage (SMS)", + "Advice of Charge (AoC)", + "Capability Configuration Parameters (CCP)", + "PLMN selector", + "RFU", + "MSISDN", + "Extension1", + "Extension2", + "SMS Parameters", + "Last Number Dialled (LND)", + "Cell Broadcast Message Identifier", + "Group Identifier Level 1", + "Group Identifier Level 2", + "Service Provider Name", + "Service Dialling Numbers (SDN)", + "Extension3", + "RFU", + "VGCS Group Identifier List (EFVGCS and EFVGCSS)", + "VBS Group Identifier List (EFVBS and EFVBSS)", + "enhanced Multi-Level Precedence and Pre-emption Service", + "Automatic Answer for eMLPP", + "Data download via SMS-CB", + "Data download via SMS-PP", + "Menu selection", + "Call control", + "Proactive SIM", + "Cell Broadcast Message Identifier Ranges", + "Barred Dialling Numbers (BDN)", + "Extension4", + "De-personalization Control Keys", + "Co-operative Network List", + "Short Message Status Reports", + "Network's indication of alerting in the MS", + "Mobile Originated Short Message control by SIM", + "GPRS", + "Image (IMG)", + "SoLSA (Support of Local Service Area)", + "USSD string data object supported in Call Control", + "RUN AT COMMAND command", + "User controlled PLMN Selector with Access Technology", + "Operator controlled PLMN Selector with Access Technology", + "HPLMN Selector with Access Technology", + "CPBCCH Information", + "Investigation Scan", + "Extended Capability Configuration Parameters", + "MExE", + "Reserved and shall be ignored", + "PLMN Network Name", + "Operator PLMN List", + "Mailbox Dialling Numbers", + "Message Waiting Indication Status", + "Call Forwarding Indication Status", + "Service Provider Display Information", + "Multimedia Messaging Service (MMS)", + "Extension 8", + "MMS User Connectivity Parameters"] # provide the IO to the SAP server def initialize(io) @@ -45,374 +105,310 @@ class Info def display # get the ATR puts "ATR : #{@client.atr.to_hex_disp}" + + # verify CHV1 + while chv_enabled? do + print "enter PIN : " + $stdout.flush + pin = gets.chomp + # pin is between 4 and 8 digits + unless pin.length>=4 and pin.length<=8 and pin.gsub(/\d/,"").length==0 then + puts "PIN has 4 to 8 digits" + redo + end + + # encode pin in T.50 on 8 bytes + chv = [0xFF]*8 + pin.length.times do |i| + chv[i]=0x30+pin[i,1].to_i + end + + # select DF_GSM + cd [MF,DF_GSM] + # verify CHV1 + begin + transmit(CHV1+chv) + break + rescue + puts "PIN wrong" + end + end + + # get ICCID + iccid = read_ef([MF,EF_ICCID]) + # get rid of the padding + iccid = iccid.nibble_str(true) + puts "ICCID : "+iccid + + # get IMSI + imsi = read_ef([MF,DF_GSM,EF_IMSI]) + # byte 1 is the length of the IMSI + imsi_length = imsi[0] + imsi = imsi[1,imsi_length] + # first nibble is for parity check (not done) + imsi = imsi.nibble_str[1..-1] + puts "IMSI : "+imsi + + # service provider name + begin + spn = read_ef([MF,DF_GSM,EF_SPN]) + spn_str = "service provider name : " + if spn==[0xff]*spn.length then + spn_str += "empty" + else + name = spn[1..-1] + name.collect!{|b| b==0xff ? nil : b}.compact! + spn_str += "name #{alphabet(name)}, " + spn_str += "display off the registered PLMN " + spn_str += spn[0]&0x01==0 ? "not required" : "required" + name = spn[1..-1] + name.collect!{|b| b==0xff ? nil : b}.compact! + spn_str += ", name #{alphabet(name)} #{spn.to_hex_disp}" + end + puts spn_str + rescue + puts "no service provider name" + end + + # get MSISDN + begin + msisdns = read_ef([MF,DF_TELECOM,EF_MSISDN]) + msisdn_str = "" + msisdns.each do |msisdn| + next if msisdn==[0xff]*msisdn.length + msisdn_str += " - " + alpha_id = msisdn[0,msisdn.length-14] + msisdn_str += "aplha identifier : #{alphabet(alpha_id)}" + #msisdn_str += ", BCD number/SSC length : #{msisdn[-14]}" + npi = case msisdn[-13]&0xf + when 0 + "unknown" + when 1 + "ISDN/telephony" + when 3 + "data" + when 4 + "telex" + when 5 + "private" + else + "reserved" + end + msisdn_str += ", " + msisdn_str += "numbering plan identifier : #{npi}" + ton = case (msisdn[-13]>>4)&0x7 + when 0 + "unknown" + when 1 + "international" + when 2 + "national" + when 3 + "network specific" + when 4 + "short code" + else + "reserved" + end + msisdn_str += ", " + msisdn_str += "type of number : #{ton}" + number = msisdn[-12,msisdn[-14]-1].nibble_str(true) + number.gsub!(/[Aa]/,"*") + number.gsub!(/[Bb]/,"#") + number.gsub!(/[Cc]/," ") + number.gsub!(/[Dd]/,"§") + number.gsub!(/[Ee]/,"1") + msisdn_str += ", " + msisdn_str += "number : #{number}" + msisdn_str += ", capability in EF_CCP #{msisdn[-2]}" unless msisdn[-2]==0xff + msisdn_str += ", entension in EF_EXT #{msisdn[-1]}" unless msisdn[-1]==0xff + msisdn_str += "\n" + end + if msisdn_str.length>0 then + puts "MSISIDN :" + puts msisdn_str + else + puts "MSISDN empty" + end + rescue + puts "no MSISDN" + end + + # get PLMsel + plmn = read_ef([DF_GSM,EF_PLMNSEL]) + # transform to MCC MNC + print "PLMN selector : " + plmns = "" + (plmn.length/3).times do |i| + mcc = plmn[3*i,2].nibble_str(true) + mnc = plmn[3*i+2,1].nibble_str + plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" + end + puts plmns[0..-2] + + # get higher priority PLMN search period + hpplmn = read_ef([MF,DF_GSM,EF_HPPLMN]) + puts "higher priority PLMN search period : #{hpplmn[0]*6} min" + + # get FPLMN + plmn = read_ef([MF,DF_GSM,EF_FPLMN]) + # transform to MCC MNC + if plmn[0,3]==[0xff]*3 then + puts "no forbidden PLMN" + else + print "forbidden PLMN : " + plmns = "" + (plmn.length/3).times do |i| + mcc = plmn[3*i,2].nibble_str(true) + mnc = plmn[3*i+2,1].nibble_str + plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" + end + puts plmns[0..-2] + end + + # get PLMNwAcT + begin + plmn = read_ef([MF,DF_GSM,EF_PLMNWACT]) + # transform to MCC MNC + print "user controlled PLMN : " + plmns = "" + (plmn.length/5).times do |i| + mcc = plmn[3*i,2].nibble_str(true) + mnc = plmn[3*i+2,1].nibble_str + plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" + end + puts plmns[0..-2] + rescue + puts "no user controlled PLMN" + end + + # get OPLMNwAcT + begin + plmn = read_ef([MF,DF_GSM,EF_OPLMNWACT]) + # transform to MCC MNC + print "operator controlled PLMN : " + plmns = "" + (plmn.length/5).times do |i| + mcc = plmn[3*i,2].nibble_str(true) + mnc = plmn[3*i+2,1].nibble_str + plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" + end + puts plmns[0..-2] + rescue + puts "no operator controlled PLMN" + end + + # access control class + acc = read_ef([MF,DF_GSM,EF_ACC]) + puts "access control class :" + acc=acc[1]+(acc[0]<<8) + 16.times do |b| + next if b==10 + text = (acc>>b)&0x01==1 ? "allocated" : "not allocted" + puts " - ACC #{b} : #{text}" + end + + # get Kc + kc = read_ef([MF,DF_GSM,EF_KC]) + puts "Kc [seq.] : #{kc[0,8].to_hex_disp} [#{kc[8]}]" + + # run A38 algo + # the rands + rands = [] + 16.times do |i| + rands << [(i<<4)+i]*16 + end + # the results + puts "some KCs (RAND SRES Kc) :" + rands.each do |r| + response = a38(r) + puts " - #{r.to_hex_disp.gsub(' ','')} #{response[0,4].to_hex_disp.gsub(' ','')} #{response[4..-1].to_hex_disp.gsub(' ','')}" + end + + # get the phase EFPhase + phase = read_ef([MF,DF_GSM,EF_PHASE]) + case phase[0] + when 0 + puts "phase : 1" + when 2 + puts "phase : 2" + when 3 + puts "phase : 2 and PROFILE DOWNLOAD required" + else + puts "phase : unkown" + end + + # get EFsst + puts "SIM service table :" + sst = read_ef([MF,DF_GSM,EF_SST]) + sst.each_index do |i| + (0..4).each do |j| + service_nb = i*4+j + service = SERVICES[service_nb] + service = "unknown" unless service + if ((sst[i]>>(j*2))&0x01)==0x01 then + service_alloc = "allocated" + else + service_alloc = "not allocated" + end + if ((sst[i]>>(j*2+1))&0x01)==0x01 then + service_act = "activated" + else + service_act = "not activated" + end + puts " - #{service_nb+1} #{service} : #{service_alloc}, #{service_act}" + end + end + + # get the phase + ad = read_ef([MF,DF_GSM,EF_AD]) + puts "administration data :" + ms = " - MS operation mode : " + ms += case ad[0] + when 0x00 + "normal operation" + when 0x80 + "type approval operations" + when 0x01 + "normal operation + specific facilities" + when 0x81 + "type approval operations + specific facilities" + when 0x02 + "maintenance (off line)" + when 0x04 + "cell test operation" + end + puts ms + ofm = " - OFM (Operational Feature Monitor) : " + ofm += ad[2]&0x01==0x00 ? "disabled" : "enabled" + puts ofm + if ad.length>3 then + puts " - length of MNC in the IMSI : #{ad[3]}" + end + + # location information + loci = read_ef([MF,DF_GSM,EF_LOCI]) + puts "location informtion :" + puts " - TMSI : #{loci[0,4].to_hex_disp.gsub(' ','')}" + puts " - LAI : #{loci[4,5].to_hex_disp.gsub(' ','')}" + puts " - TMSI TIME : #{loci[9]==0 ? 'infinite' : (loci[9]*6).to_s+' min'}" + status = " - location update status : " + status += case loci[9]&0x7 + when 0 + "updated" + when 1 + "not updated" + when 2 + "PLMN not allowed" + when 3 + "location area not allowed" + else + "reserved" + end + puts status end def close @client.disconnect end end - -=begin - -# verify CHV1 -while chv_enabled? do - - print "enter PIN : " - pin = gets.chomp - # pin is between 4 and 8 digits - unless pin.length>=4 and pin.length<=8 and pin.gsub(/\d/,"").length==0 then - puts "PIN has 4 to 8 digits" - redo - end - - # encode pin in T.50 on 8 bytes - chv = [0xFF]*8 - pin.length.times do |i| - chv[i]=0x30+pin[i,1].to_i - end - - # select DF_GSM - cd [MF,DF_GSM] - # verify CHV1 - begin - transmit(CHV1+chv) - break - rescue - puts "PIN wrong" - end -end - -# get ICCID -iccid = read_ef([MF,EF_ICCID]) -# get rid of the padding -iccid = iccid.nibble_str(true) -puts "ICCID : "+iccid - -# get IMSI -imsi = read_ef([MF,DF_GSM,EF_IMSI]) -# byte 1 is the length of the IMSI -imsi_length = imsi[0] -imsi = imsi[1,imsi_length] -# first nibble is for parity check (not done) -imsi = imsi.nibble_str[1..-1] -puts "IMSI : "+imsi - -# service provider name -begin - spn = read_ef([MF,DF_GSM,EF_SPN]) - spn_str = "service provider name : " - if spn==[0xff]*spn.length then - spn_str += "empty" - else - name = spn[1..-1] - name.collect!{|b| b==0xff ? nil : b}.compact! - spn_str += "name #{alphabet(name)}, " - spn_str += "display off the registered PLMN " - spn_str += spn[0]&0x01==0 ? "not required" : "required" - name = spn[1..-1] - name.collect!{|b| b==0xff ? nil : b}.compact! - spn_str += ", name #{alphabet(name)} #{spn.to_hex_disp}" - end - puts spn_str -rescue - puts "no service provider name" -end - -# get MSISDN -begin - msisdns = read_ef([MF,DF_TELECOM,EF_MSISDN]) - msisdn_str = "" - msisdns.each do |msisdn| - next if msisdn==[0xff]*msisdn.length - msisdn_str += " - " - alpha_id = msisdn[0,msisdn.length-14] - msisdn_str += "aplha identifier : #{alphabet(alpha_id)}" - #msisdn_str += ", BCD number/SSC length : #{msisdn[-14]}" - npi = case msisdn[-13]&0xf - when 0 - "unknown" - when 1 - "ISDN/telephony" - when 3 - "data" - when 4 - "telex" - when 5 - "private" - else - "reserved" - end - msisdn_str += ", " - msisdn_str += "numbering plan identifier : #{npi}" - ton = case (msisdn[-13]>>4)&0x7 - when 0 - "unknown" - when 1 - "international" - when 2 - "national" - when 3 - "network specific" - when 4 - "short code" - else - "reserved" - end - msisdn_str += ", " - msisdn_str += "type of number : #{ton}" - number = msisdn[-12,msisdn[-14]-1].nibble_str(true) - number.gsub!(/[Aa]/,"*") - number.gsub!(/[Bb]/,"#") - number.gsub!(/[Cc]/," ") - number.gsub!(/[Dd]/,"§") - number.gsub!(/[Ee]/,"1") - msisdn_str += ", " - msisdn_str += "number : #{number}" - msisdn_str += ", capability in EF_CCP #{msisdn[-2]}" unless msisdn[-2]==0xff - msisdn_str += ", entension in EF_EXT #{msisdn[-1]}" unless msisdn[-1]==0xff - msisdn_str += "\n" - end - if msisdn_str.length>0 then - puts "MSISIDN :" - puts msisdn_str - else - puts "MSISDN empty" - end -rescue - puts "no MSISDN" -end - -# get PLMsel -plmn = read_ef([DF_GSM,EF_PLMNSEL]) -# transform to MCC MNC -print "PLMN selector : " -plmns = "" -(plmn.length/3).times do |i| - mcc = plmn[3*i,2].nibble_str(true) - mnc = plmn[3*i+2,1].nibble_str - plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" -end -puts plmns[0..-2] - -# get higher priority PLMN search period -hpplmn = read_ef([MF,DF_GSM,EF_HPPLMN]) -puts "higher priority PLMN search period : #{hpplmn[0]*6} min" - -# get FPLMN -plmn = read_ef([MF,DF_GSM,EF_FPLMN]) -# transform to MCC MNC -if plmn[0,3]==[0xff]*3 then - puts "no forbidden PLMN" -else - print "forbidden PLMN : " - plmns = "" - (plmn.length/3).times do |i| - mcc = plmn[3*i,2].nibble_str(true) - mnc = plmn[3*i+2,1].nibble_str - plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" - end - puts plmns[0..-2] -end - -# get PLMNwAcT -begin - plmn = read_ef([MF,DF_GSM,EF_PLMNWACT]) - # transform to MCC MNC - print "user controlled PLMN : " - plmns = "" - (plmn.length/5).times do |i| - mcc = plmn[3*i,2].nibble_str(true) - mnc = plmn[3*i+2,1].nibble_str - plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" - end - puts plmns[0..-2] -rescue - puts "no user controlled PLMN" -end - -# get OPLMNwAcT -begin - plmn = read_ef([MF,DF_GSM,EF_OPLMNWACT]) - # transform to MCC MNC - print "operator controlled PLMN : " - plmns = "" - (plmn.length/5).times do |i| - mcc = plmn[3*i,2].nibble_str(true) - mnc = plmn[3*i+2,1].nibble_str - plmns += "#{mcc} #{mnc}," unless mcc=="" and mnc=="ff" - end - puts plmns[0..-2] -rescue - puts "no operator controlled PLMN" -end - -# access control class -acc = read_ef([MF,DF_GSM,EF_ACC]) -puts "access control class :" -acc=acc[1]+(acc[0]<<8) -16.times do |b| - next if b==10 - text = (acc>>b)&0x01==1 ? "allocated" : "not allocted" - puts " - ACC #{b} : #{text}" -end - -# get Kc -kc = read_ef([MF,DF_GSM,EF_KC]) -puts "Kc [seq.] : #{kc[0,8].to_hex_disp} [#{kc[8]}]" - -# run A38 algo -# the rands -rands = [] -16.times do |i| - rands << [(i<<4)+i]*16 -end -# the results -puts "some KCs (RAND SRES Kc) :" -rands.each do |r| - response = a38(r) - puts " - #{r.to_hex_disp.gsub(' ','')} #{response[0,4].to_hex_disp.gsub(' ','')} #{response[4..-1].to_hex_disp.gsub(' ','')}" -end - -# get the phase EFPhase -phase = read_ef([MF,DF_GSM,EF_PHASE]) -case phase[0] -when 0 - puts "phase : 1" -when 2 - puts "phase : 2" -when 3 - puts "phase : 2 and PROFILE DOWNLOAD required" -else - puts "phase : unkown" -end - -# get EFsst -SERVICES = [ -"CHV1 disable function", -"Abbreviated Dialling Numbers (ADN)", -"Fixed Dialling Numbers (FDN)", -"Short Message Storage (SMS)", -"Advice of Charge (AoC)", -"Capability Configuration Parameters (CCP)", -"PLMN selector", -"RFU", -"MSISDN", -"Extension1", -"Extension2", -"SMS Parameters", -"Last Number Dialled (LND)", -"Cell Broadcast Message Identifier", -"Group Identifier Level 1", -"Group Identifier Level 2", -"Service Provider Name", -"Service Dialling Numbers (SDN)", -"Extension3", -"RFU", -"VGCS Group Identifier List (EFVGCS and EFVGCSS)", -"VBS Group Identifier List (EFVBS and EFVBSS)", -"enhanced Multi-Level Precedence and Pre-emption Service", -"Automatic Answer for eMLPP", -"Data download via SMS-CB", -"Data download via SMS-PP", -"Menu selection", -"Call control", -"Proactive SIM", -"Cell Broadcast Message Identifier Ranges", -"Barred Dialling Numbers (BDN)", -"Extension4", -"De-personalization Control Keys", -"Co-operative Network List", -"Short Message Status Reports", -"Network's indication of alerting in the MS", -"Mobile Originated Short Message control by SIM", -"GPRS", -"Image (IMG)", -"SoLSA (Support of Local Service Area)", -"USSD string data object supported in Call Control", -"RUN AT COMMAND command", -"User controlled PLMN Selector with Access Technology", -"Operator controlled PLMN Selector with Access Technology", -"HPLMN Selector with Access Technology", -"CPBCCH Information", -"Investigation Scan", -"Extended Capability Configuration Parameters", -"MExE", -"Reserved and shall be ignored", -"PLMN Network Name", -"Operator PLMN List", -"Mailbox Dialling Numbers", -"Message Waiting Indication Status", -"Call Forwarding Indication Status", -"Service Provider Display Information", -"Multimedia Messaging Service (MMS)", -"Extension 8", -"MMS User Connectivity Parameters"] -puts "SIM service table :" -sst = read_ef([MF,DF_GSM,EF_SST]) -sst.each_index do |i| - (0..4).each do |j| - service_nb = i*4+j - service = SERVICES[service_nb] - service = "unknown" unless service - if ((sst[i]>>(j*2))&0x01)==0x01 then - service_alloc = "allocated" - else - service_alloc = "not allocated" - end - if ((sst[i]>>(j*2+1))&0x01)==0x01 then - service_act = "activated" - else - service_act = "not activated" - end - puts " - #{service_nb+1} #{service} : #{service_alloc}, #{service_act}" - end -end - -# get the phase -ad = read_ef([MF,DF_GSM,EF_AD]) -puts "administration data :" -ms = " - MS operation mode : " -ms += case ad[0] -when 0x00 - "normal operation" -when 0x80 - "type approval operations" -when 0x01 - "normal operation + specific facilities" -when 0x81 - "type approval operations + specific facilities" -when 0x02 - "maintenance (off line)" -when 0x04 - "cell test operation" -end -puts ms -ofm = " - OFM (Operational Feature Monitor) : " -ofm += ad[2]&0x01==0x00 ? "disabled" : "enabled" -puts ofm -if ad.length>3 then - puts " - length of MNC in the IMSI : #{ad[3]}" -end - -# location information -loci = read_ef([MF,DF_GSM,EF_LOCI]) -puts "location informtion :" -puts " - TMSI : #{loci[0,4].to_hex_disp.gsub(' ','')}" -puts " - LAI : #{loci[4,5].to_hex_disp.gsub(' ','')}" -puts " - TMSI TIME : #{loci[9]==0 ? 'infinite' : (loci[9]*6).to_s+' min'}" -status = " - location update status : " -status += case loci[9]&0x7 -when 0 - "updated" -when 1 - "not updated" -when 2 - "PLMN not allowed" -when 3 - "location area not allowed" -else - "reserved" -end -puts status - -=end