sysmo-usim-tool: Add a tool for sysmosom specific tasks

This commit adds a tool that is intended to be used with sysmo-usim
only if some of the highly propritary parameters, which the regular
pysim can not handle, need to be configured.
This commit is contained in:
Philipp Maier 2017-02-23 14:47:38 +01:00
commit 4f2e60436b
5 changed files with 959 additions and 0 deletions

186
card.py Normal file
View File

@ -0,0 +1,186 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Smartcard Terminal IO Class
(C) 2017 by Sysmocom s.f.m.c. GmbH
All Rights Reserved
Author: Philipp Maier
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from smartcard.scard import *
import smartcard.util
from utils import *
# The following class abstract the terminal, however we reference it as "Card",
# because the terminal itsslef is not in the users interest, we are focussed
# on the card all the time. The abstraction done here is very simple and
# implements only the very basic functionality to communicate with a smartcard
# on APDU level.
#
# The classes Card_res_apdu and Card_apdu are helper classes in order to make
# passing the parameters/results simpler. They are not meant to be created
# anwhere else in the code. All handling is done through the Card class.
#
# The method apdu formats an APDU with its basic features (CLA, INS etc..)
# for the user. The user also may set an expected status word (Default is
# 0x9000). The status word is then checked when the transaction is performed
# using the transact method.
#
# The expected status word is a list of two bytes, each of the two bytes may be
# set to None. If this is the case the byte is not checked. If the whole list
# is set to none, the status word is not checked at all. If the status word
# check fails, the swok flag inside the repsonse apdu is set to false and an
# exception is thwron unless the strict parameter is not set to False.
#
# The user may set a dry-flag when calling the transact, then the transaction
# is not performed. Only the log line is printed. This is to verify if the
# transaction would be sent correctly, as some smartcad operations might
# be risky.
# Note: Programmed with the help of a blogpost from Ludovic Rousseau:
# https://ludovicrousseau.blogspot.de/2010/04/pcsc-sample-in-python.html
# A class to make handling of the responses a little simpler
# Note: Do not use directly, Card object will return responses.
class Card_res_apdu():
apdu = None
sw = None
swok = True
def __init__(self, apdu, sw):
self.apdu = apdu
self.sw = sw
def __str__(self):
dump = "APDU:" + hexdump(self.apdu)
dump += " SW:" + hexdump(self.sw)
return dump
# A class to make handling of the card input a little simpler
# Note: Do not use directly, use Card.apdu(...) instead
class Card_apdu():
apdu = None
sw = None
def __init__(self, cla, ins, p1, p2, p3, data, sw):
self.apdu = [cla, ins, p1, p2, p3]
if data:
self.apdu += data
self.sw = sw
def __str__(self):
dump = "APDU:" + hexdump(self.apdu)
return dump
# A class to abstract smartcard and terminal
class Card():
card = None
protocol = None
verbose = None
# Constructor: Set up connection to smartcard
def __init__(self, verbose = False):
self.verbose = verbose
# Eestablish a smartcard terminal context
hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER)
if hresult != SCARD_S_SUCCESS:
print " * Error: Unable to establish smartcard terminal context -- exiting"
exit(1)
# Select the next available smartcard terminal
hresult, terminals = SCardListReaders(hcontext, [])
if hresult != SCARD_S_SUCCESS or len(terminals) < 1:
print " * Error: No smartcard terminal found -- exiting"
exit(1)
terminal = terminals[0]
print " * Terminal:", terminal
# Establish connection to smartcard
hresult, hcard, dwActiveProtocol = SCardConnect(hcontext,
terminal, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
if hresult != SCARD_S_SUCCESS:
print " * Error: No smartcard detected -- exiting"
exit(1)
print " * Protocol: " + str(dwActiveProtocol)
self.card = hcard
self.protocol = dwActiveProtocol
# Print debug info
def __debug_print(self, message):
if self.verbose:
print message
# Perform smartcard transaction
def transact(self, apdu, dry = False, strict = True):
# Dry run
if (dry):
self.__debug_print(" Card transaction: " + str(apdu)
+ " ==> Dry run: Transaction not executed")
return Card_res_apdu(None,None)
# Perform transaction
hresult, response = SCardTransmit(self.card,
self.protocol, apdu.apdu)
if hresult != SCARD_S_SUCCESS:
self.__debug_print(" * Card transaction: " + str(apdu)
+ " ==> Error: Smartcard transaction failed")
return Card_res_apdu(None,None)
res = Card_res_apdu(response[:-2],response[-2:])
self.__debug_print(" Card transaction: " + str(apdu)
+ " ==> " + str(res))
# Check status word
if apdu.sw:
if apdu.sw[0] and apdu.sw[0] == res.sw[0]:
res.swok = True
elif apdu.sw[0]:
res.swok = False
self.__debug_print(" * Warning: Unexpected status word (SW1)!")
if apdu.sw[1] and apdu.sw[1] == res.sw[1]:
res.swok = True
elif apdu.sw[1]:
res.swok = False
self.__debug_print(" * Warning: Unexpected status word (SW2)!")
# If strict mode is turned on, the status word must match,
# otherwise an exception is thrown
if strict and res.swok == False:
raise ValueError('Transaction failed!')
return res
# set up a new APDU
def apdu(self, cla, ins, p1 = 0x00, p2 = 0x00, p3 = 0x00,
data = None, sw = [0x90, 0x00]):
return Card_apdu(cla, ins, p1, p2, p3, data, sw)

216
simcard.py Normal file
View File

@ -0,0 +1,216 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Simcard IO Class
(C) 2017 by Sysmocom s.f.m.c. GmbH
All Rights Reserved
Author: Philipp Maier
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from card import *
# This is an abstraction which offers a set of tools to handle the most basic
# operations that can be performed on a sim card. The implementation is not
# simcard model specific
# Classes
GSM_SIM_CLA = 0xA0
GSM_USIM_CLA = 0x00
# Instructions, see also GSM 11.11, Table 9 Coding of the commands
GSM_SIM_INS_SELECT = 0xA4
GSM_SIM_INS_STATUS = 0xF2
GSM_SIM_INS_READ_BINARY = 0xB0
GSM_SIM_INS_UPDATE_BINARY = 0xD6
GSM_SIM_INS_READ_RECORD = 0xB2
GSM_SIM_INS_UPDATE_RECORD = 0xDC
GSM_SIM_INS_SEEK = 0xA2
GSM_SIM_INS_INCREASE = 0x32
GSM_SIM_INS_VERIFY_CHV = 0x20
GSM_SIM_INS_CHANGE_CHV = 0x24
GSM_SIM_INS_DISABLE_CHV = 0x26
GSM_SIM_INS_ENABLE_CHV = 0x28
GSM_SIM_INS_UNBLOCK_CHV = 0x2C
GSM_SIM_INS_INVALIDATE = 0x04
GSM_SIM_INS_REHABILITATE = 0x44
GSM_SIM_INS_RUN_GSM_ALGORITHM = 0x88
GSM_SIM_INS_SLEEP = 0xFA
GSM_SIM_INS_GET_RESPONSE = 0xC0
GSM_SIM_INS_TERMINAL_PROFILE = 0x10
GSM_SIM_INS_ENVELOPE = 0xC2
GSM_SIM_INS_FETCH = 0x12
GSM_SIM_INS_TERMINAL_RESPONSE = 0x14
# Partial File tree:
# The following tree is incomplete, it just contains the files we have been
# interested in so far. A full SIM card file tree can be found in:
# GSM TS 11.11, Figure 8: "File identifiers and directory structures of GSM"
# 3GPP TS 31.102, cap. 4.7: "Files of USIM"
#
# [MF 0x3F00]
# |
# +--[EF_DIR 0x2F00]
# |
# +--[EF_ICCID 0x2FE2]
# |
# +--[DF_TELECOM 0x7F10]
# | |
# | +-[EF_ADN 0x7F20]
# |
# +--[DF_GSM 0x7F20]
# |
# +-[EF_IMSI 0x6F07]
# Files
GSM_SIM_MF = [0x3F, 0x00]
GSM_SIM_DF_TELECOM = [0x7F, 0x10]
GSM_SIM_DF_GSM = [0x7F, 0x20]
GSM_SIM_EF_ADN = [0x6f,0x3A]
GSM_SIM_EF_IMSI = [0x6F, 0x07]
GSM_SIM_EF_ICCID = [0x2F, 0xE2]
GSM_USIM_EF_DIR = [0x2F, 0x00] # See also: 3GPP TS 31.102 Table 105
# Card types
GSM_SIM = 0
GSM_USIM = 1
# CHV Types
GSM_CHV1 = 0x01
GSM_CHV2 = 0x02
# Record oriented read modes
GSM_SIM_INS_READ_RECORD_NEXT = 0x02
GSM_SIM_INS_READ_RECORD_PREV = 0x03
GSM_SIM_INS_READ_RECORD_ABS = 0x04
# Record oriented write modes
GSM_SIM_INS_UPDATE_RECORD_NEXT = 0x02
GSM_SIM_INS_UPDATE_RECORD_PREV = 0x03
GSM_SIM_INS_UPDATE_RECORD_ABS = 0x04
# A class to abstract a simcard.
class Simcard():
card = None
usim = None
# Constructor: Create a new simcard object
def __init__(self, terminal, cardtype = GSM_USIM):
self.card = terminal
if cardtype == GSM_USIM:
self.usim = True
else:
self.usim = True
# Find the right class byte, depending on the simcard type
def __get_cla(self, usim):
if (usim):
return GSM_USIM_CLA
else:
return GSM_SIM_CLA
# Select a file
def select(self, fid, dry = False, strict = True):
cla = self.__get_cla(self.usim)
ins = GSM_SIM_INS_SELECT
length = 0x02
apdu = self.card.apdu(cla, ins, p2 = 0x0C,
p3 = length, data = fid)
return self.card.transact(apdu, dry, strict)
# Perform card holder verification
def verify_chv(self, chv, chv_no, dry = False, strict = True):
cla = self.__get_cla(self.usim)
ins = GSM_SIM_INS_VERIFY_CHV
length = 0x08
apdu = self.card.apdu(cla, ins, p2 = chv_no,
p3 = length, data = chv)
return self.card.transact(apdu, dry, strict)
# Perform file operation (Write)
def update_binary(self, data, offset = 0, dry = False, strict = True):
cla = self.__get_cla(self.usim)
ins = GSM_SIM_INS_UPDATE_BINARY
length = len(data)
offs_high = (offset >> 8) & 0xFF
offs_low = offset & 0xFF
apdu = self.card.apdu(cla, ins, p1 = offs_high, p2 = offs_low,
p3 = length, data = data)
return self.card.transact(apdu, dry, strict)
# Perform file operation (Read, byte oriented)
def read_binary(self, length, offset = 0, dry = False, strict = True):
cla = self.__get_cla(self.usim)
ins = GSM_SIM_INS_READ_BINARY
offs_high = (offset >> 8) & 0xFF
offs_low = offset & 0xFF
apdu = self.card.apdu(cla, ins, p1 = offs_high,
p2 = offs_low, p3 = length)
return self.card.transact(apdu, dry, strict)
# Perform file operation (Read, record oriented)
def read_record(self, length, rec_no = 0, dry = False, strict = True):
cla = self.__get_cla(self.usim)
ins = GSM_SIM_INS_READ_RECORD
apdu = self.card.apdu(cla, ins, p1 = rec_no,
p2 = GSM_SIM_INS_READ_RECORD_ABS, p3 = length)
return self.card.transact(apdu, dry, strict)
# Perform file operation (Read, record oriented)
def update_record(self, data, rec_no = 0, dry = False, strict = True):
cla = self.__get_cla(self.usim)
ins = GSM_SIM_INS_UPDATE_RECORD
length = len(data)
apdu = self.card.apdu(cla, ins, p1 = rec_no,
p2 = GSM_SIM_INS_UPDATE_RECORD_ABS,
p3 = length, data = data)
return self.card.transact(apdu, dry, strict)

183
sysmo-usim-tool.sjs1.py Executable file
View File

@ -0,0 +1,183 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Commandline interface for sysmoUSIM-SJS1
(C) 2017 by Sysmocom s.f.m.c. GmbH
All Rights Reserved
Author: Philipp Maier
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import sys, getopt
from card import *
from simcard import *
from sysmo_usimsjs1 import *
def banner():
print "sysmoUSIM-SJS1 parameterization tool"
print "Copyright (c)2017 Sysmocom s.f.m.c. GmbH"
print ""
def helptext():
print " * Commandline options:"
print " -v, --verbose .................. Enable debug output (trace APDUs)"
print " -a, --adm1 CHV ................. Administrator PIN (e.g 55538407)"
print " -u, --usim ..................... Enable USIM mode"
print " -c, --classic .................. Disable USIM mode (make classic-sim)"
print " -m, --mode ..................... Display mode (classic-sim or USIM?)"
print " -t, --auth ..................... Show Authentication algorithms"
print " -T, --set-auth 2G:3G ........... Set 2G/3G Auth algo (e.g. 3:3)"
print " -l, --milenage ................. Show milenage parameters"
print " -L, --set-milenage HEXSTRING ... Set milenage parameters"
print " -o, --opc ...................... Show OP/c configuration"
print " -O, --set-op HEXSTRING ......... Set OP value"
print " -C, --set-opc HEXSTRING ........ Set OPc value"
print ""
def main(argv):
banner()
getopt_adm1 = None
getopt_write_sim_mode = None # True = USIM, False = classic SIM
getopt_show_sim_mode = False
getopt_verbose = False
getopt_show_auth = False
getopt_write_auth = None
getopt_show_milenage = False
getopt_write_milenage = None
getopt_show_opc = False
getopt_write_op = None
getopt_write_opc = None
# Analyze commandline options
try:
opts, args = getopt.getopt(argv,
"hva:ucmtT:lL:oO:C:",
["help","verbose","adm1=","usim","classic",
"mode","auth","set-auth=","milenage",
"set-milenage","opc","set-op=","set-opc="])
except getopt.GetoptError:
print " * Error: Invalid commandline options"
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
helptext()
sys.exit()
elif opt in ("-v", "--verbose"):
getopt_verbose = True
elif opt in ("-a", "--adm1"):
getopt_adm1 = ascii_to_list(arg)
elif opt in ("-u", "--usim"):
getopt_write_sim_mode = True
elif opt in ("-c", "--classic"):
getopt_write_sim_mode = False
elif opt in ("-m", "--mode"):
getopt_show_sim_mode = True
elif opt in ("-t", "--auth"):
getopt_show_auth = True
elif opt in ("-T", "--set-auth"):
getopt_write_auth = arg.split(':',1)
elif opt in ("-l", "--milenage"):
getopt_show_milenage = True
elif opt in ("-L", "--set-milenage"):
getopt_write_milenage = asciihex_to_list(arg)
elif opt in ("-o", "--opc"):
getopt_show_opc = True
elif opt in ("-O", "--set-op"):
getopt_write_op = asciihex_to_list(arg)
elif opt in ("-C", "--set-opc"):
getopt_write_opc = asciihex_to_list(arg)
if not getopt_adm1:
print " * Error: adm1 parameter missing -- exiting..."
print ""
sys.exit(1)
# Claim terminal
print "Initalizing smartcard terminal..."
c = Card(getopt_verbose)
sim = Simcard(c)
print("")
# Execute tasks
if getopt_write_sim_mode != None:
print "Programming SIM-Mode..."
sysmo_usim_write_sim_mode(sim, getopt_adm1,
getopt_write_sim_mode)
print("")
if getopt_show_sim_mode:
print "Reading SIM-Mode..."
sysmo_usim_show_sim_mode(sim, getopt_adm1)
print("")
if getopt_write_auth:
print "Programming Authentication parameters..."
sysmo_usim_write_auth_params(sim, getopt_adm1,
int(getopt_write_auth[0]),
int(getopt_write_auth[1]))
print("")
if getopt_show_auth:
print "Reading Authentication parameters..."
sysmo_usim_show_auth_params(sim, getopt_adm1)
print("")
if getopt_write_milenage:
print "Programming Milenage parameters..."
ef_mlngc = SYSMO_USIMSJS1_FILE_EF_MLNGC(getopt_write_milenage)
sysmo_usim_write_milenage_params(sim, getopt_adm1, ef_mlngc)
print("")
if getopt_show_milenage:
print "Reading Milenage parameters..."
sysmo_usim_show_milenage_params(sim, getopt_adm1)
print("")
if getopt_write_op:
print "Writing OP value..."
sysmo_usim_write_opc_params(sim,
getopt_adm1, 0, getopt_write_op)
print("")
if getopt_write_opc:
print "Writing OPCC value..."
sysmo_usim_write_opc_params(sim,
getopt_adm1, 1, getopt_write_opc)
print("")
if getopt_show_opc:
print "Reading OPC value..."
sysmo_usim_show_opc_params(sim, getopt_adm1)
print("")
print "Done!"
if __name__ == "__main__":
main(sys.argv[1:])

324
sysmo_usimsjs1.py Normal file
View File

@ -0,0 +1,324 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Gadgets to modify SYSMO USIM SJS1 parameters
(C) 2017 by Sysmocom s.f.m.c. GmbH
All Rights Reserved
Author: Philipp Maier
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
# Some gadgets to handle functions specific to Sysmo USIM SJS1. The gadgets are
# organized as a loose collection of python functions. Each function serves
# a specific task (e.g. modifiying the auth parameters). For each task two
# functions are implemented sysmo_usim_show_...() to inspect the data that is
# intended to be modified and sysmo_usim_write_...() to perform the actual
# modification task.
# Partial File tree:
# The following tree is incomplete, it just contains the propritary files we
# need to perform the tasks implemented below:
#
# [MF 0x3F00]
# |
# +--[DF_AUTH 0x7FCC]
# | |
# | +--[EF_AUTH 0x6F00]
# | |
# | +--[EF_MLNGC 0x6F01]
# |
# +--[DF_GSM 0x7F20]
# |
# +--[EF_OPC 0x00F7]
# |
# +--[EF_KI 0x00FF]
from card import *
from simcard import *
# Files (propritary)
SYSMO_USIMSJS1_EF_KI = [0x00, 0xFF]
SYSMO_USIMSJS1_EF_OPC = [0x00, 0xF7]
SYSMO_USIMSJS1_DF_AUTH = [0x7F, 0xCC] #FIXME: Manual does not mention name, just called it "DF_AUTH" might be wrong!
SYSMO_USIMSJS1_EF_AUTH = [0x6F, 0x00]
SYSMO_USIMSJS1_EF_MLNGC = [0x6F, 0x01]
# CHV Types
SYSMO_USIMSJS1_ADM1 = 0x0A
# Authentication algorithms (See sysmousim.pdf cap. 8.5)
SYSMO_USIMSJS1_ALGO_MILENAGE = 0x01
SYSMO_USIMSJS1_ALGO_COMP12V1 = 0x03
SYSMO_USIMSJS1_ALGO_XOR2G = 0x04
SYSMO_USIMSJS1_ALGO_COMP128V2 = 0x06
SYSMO_USIMSJS1_ALGO_COMP128V3 = 0x07
SYSMO_USIMSJS1_ALGO_XOR3G = 0x08
# Application identifier
SYSMO_USIM_AID = [0xa0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x02]
# Default content of record No.1 in EF.DIR
SYSMO_USIM_EF_DIR_REC_1_CONTENT = [0x61, 0x19, 0x4f, 0x10] + SYSMO_USIM_AID + \
[0xff, 0xff, 0xff, 0xff, 0x89, 0x07, 0x09, 0x00, 0x00, 0x50, 0x05,
0x55, 0x53, 0x69, 0x6d, 0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff]
# Abstraction for the file structure of EF.MLNGC, which holds the
# parameters of the milenage authentication algorithm
class SYSMO_USIMSJS1_FILE_EF_MLNGC:
# Default parameters, see also sysmousim-manual.pdf,
# cap. 8.6 "Milenage Configuration (Ci/Ri)
C1 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
C2 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]
C3 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02]
C4 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04]
C5 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08]
R1 = 0x40
R2 = 0x00
R3 = 0x20
R4 = 0x40
R5 = 0x60
def __init__(self, content = None):
if content == None:
return
if len(content) != 85:
return
self.C1 = content[0:16]
self.C2 = content[16:32]
self.C3 = content[32:48]
self.C4 = content[48:64]
self.C5 = content[64:80]
self.R1 = content[80]
self.R2 = content[81]
self.R3 = content[82]
self.R4 = content[83]
self.R5 = content[84]
def __str__(self):
dump = " C1: " + hexdump(self.C1) + "\n"
dump += " C2: " + hexdump(self.C2) + "\n"
dump += " C3: " + hexdump(self.C3) + "\n"
dump += " C4: " + hexdump(self.C4) + "\n"
dump += " C5: " + hexdump(self.C5) + "\n"
dump += " R1: " + str(hex(self.R1)) + "\n"
dump += " R2: " + str(hex(self.R2)) + "\n"
dump += " R3: " + str(hex(self.R3)) + "\n"
dump += " R4: " + str(hex(self.R4)) + "\n"
dump += " R5: " + str(hex(self.R5))
return dump
# Initalize card (select master file)
def sysmo_usim_init(sim):
print " * Initalizing..."
sim.select(GSM_SIM_MF)
# Authenticate as administrator
def sysmo_usim_admin_auth(sim, adm1):
print " * Authenticating at card as adminstrator..."
sim.verify_chv(adm1, SYSMO_USIMSJS1_ADM1)
# Show current athentication parameters
# (Which algorithim is used for which rat?)
def sysmo_usim_show_auth_params(sim, adm1):
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
print " * Reading..."
sim.select(SYSMO_USIMSJS1_DF_AUTH)
sim.select(SYSMO_USIMSJS1_EF_AUTH)
res = sim.read_binary(0x02)
print " * Current algorithm setting:"
print " 2G: " + str(hex(res.apdu[0]))
print " 3G: " + str(hex(res.apdu[1]))
# Program new authentication parameters
def sysmo_usim_write_auth_params(sim, adm1, algo_2g, algo_3g):
print " * New algorithm setting:"
print " 2G: " + str(hex(algo_2g))
print " 3G: " + str(hex(algo_3g))
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
print " * Programming..."
sim.select(SYSMO_USIMSJS1_DF_AUTH)
sim.select(SYSMO_USIMSJS1_EF_AUTH)
sim.update_binary([algo_2g,algo_3g])
# Show current milenage parameters
def sysmo_usim_show_milenage_params(sim, adm1):
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
# Show current milenage parameters
def sysmo_usim_show_milenage_params(sim, adm1):
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
sim.select(SYSMO_USIMSJS1_DF_AUTH)
sim.select(SYSMO_USIMSJS1_EF_MLNGC)
print " * Reading..."
ef_mlngc = SYSMO_USIMSJS1_FILE_EF_MLNGC()
res = sim.read_binary(16, offset = 0)
ef_mlngc.C1 = res.apdu
res = sim.read_binary(16, offset = 16)
ef_mlngc.C2 = res.apdu
res = sim.read_binary(16, offset = 32)
ef_mlngc.C3 = res.apdu
res = sim.read_binary(16, offset = 48)
ef_mlngc.C4 = res.apdu
res = sim.read_binary(16, offset = 64)
ef_mlngc.C5 = res.apdu
res = sim.read_binary(1, offset = 80)
ef_mlngc.R1 = res.apdu[0]
res = sim.read_binary(1, offset = 81)
ef_mlngc.R2 = res.apdu[0]
res = sim.read_binary(1, offset = 82)
ef_mlngc.R3 = res.apdu[0]
res = sim.read_binary(1, offset = 83)
ef_mlngc.R4 = res.apdu[0]
res = sim.read_binary(1, offset = 84)
ef_mlngc.R5 = res.apdu[0]
print " * Current Milenage Parameters in (EF.MLNGC):"
print str(ef_mlngc)
# Write new milenage parameters
def sysmo_usim_write_milenage_params(sim, adm1, ef_mlngc):
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
print " * New Milenage Parameters for (EF.MLNGC):"
print str(ef_mlngc)
sim.select(SYSMO_USIMSJS1_DF_AUTH)
sim.select(SYSMO_USIMSJS1_EF_MLNGC)
print " * Programming..."
sim.update_binary(ef_mlngc.C1, offset = 0)
sim.update_binary(ef_mlngc.C2, offset = 16)
sim.update_binary(ef_mlngc.C3, offset = 32)
sim.update_binary(ef_mlngc.C4, offset = 48)
sim.update_binary(ef_mlngc.C5, offset = 64)
sim.update_binary([ef_mlngc.R1], offset = 80)
sim.update_binary([ef_mlngc.R2], offset = 81)
sim.update_binary([ef_mlngc.R3], offset = 82)
sim.update_binary([ef_mlngc.R4], offset = 83)
sim.update_binary([ef_mlngc.R5], offset = 84)
# Show current OPc value
def sysmo_usim_show_opc_params(sim, adm1):
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
print " * Reading..."
sim.select(GSM_SIM_DF_GSM)
sim.select(SYSMO_USIMSJS1_EF_OPC)
res = sim.read_binary(17)
print " * Current OPc setting:"
print " OP: " + str(hex(res.apdu[0]))
print " OP/OPc: " + hexdump(res.apdu[1:])
# Program new OPc value
def sysmo_usim_write_opc_params(sim, adm1, select, op):
print " * New OPc setting:"
print " OP: " + str(hex(select))
print " OP/OPc: " + hexdump(op)
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
sim.select(GSM_SIM_DF_GSM)
sim.select(SYSMO_USIMSJS1_EF_OPC)
print " * Programming..."
sim.update_binary([select] + op)
# Show the enable status of the USIM application (app is enabled or disabled?)
def sysmo_usim_show_usim_status(sim, adm1):
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
print " * Reading..."
sim.select(GSM_USIM_EF_DIR)
res = sim.read_record(0x26, rec_no = 1)
print " * Current status of Record No.1 in EF.DIR:"
print " " + hexdump(res.apdu)
# Show the enable status of the USIM application (app is enabled or disabled?)
def sysmo_usim_show_sim_mode(sim, adm1):
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
print " * Reading..."
sim.select(GSM_USIM_EF_DIR)
res = sim.read_record(0x26, rec_no = 1)
print " * Current status of Record No. 1 in EF.DIR:"
print " " + hexdump(res.apdu)
if hexdump(SYSMO_USIM_AID) in hexdump(res.apdu):
print " ==> USIM application enabled"
else:
print " ==> USIM application disabled"
# Show the enable status of the USIM application (app is enabled or disabled?)
def sysmo_usim_write_sim_mode(sim, adm1, usim_enabled = True):
if usim_enabled:
new_record = SYSMO_USIM_EF_DIR_REC_1_CONTENT
else:
new_record = [0xFF] * len(SYSMO_USIM_EF_DIR_REC_1_CONTENT)
print " * New status of Record No.1 in EF.DIR:"
print " " + hexdump(new_record)
if hexdump(SYSMO_USIM_AID) in hexdump(new_record):
print " ==> USIM application enabled"
else:
print " ==> USIM application disabled"
sysmo_usim_init(sim)
sysmo_usim_admin_auth(sim, adm1)
print " * Programming..."
sim.select(GSM_USIM_EF_DIR)
sim.update_record(new_record, rec_no = 1)

50
utils.py Normal file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
A collection of useful routines to make this tool work
(C) 2017 by Sysmocom s.f.m.c. GmbH
All Rights Reserved
Author: Philipp Maier
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
# Convert list to an printable ascii hex string
def hexdump(array):
if array:
return ''.join('{:02x}'.format(x) for x in array)
else:
return "(no data)"
# Convert ascii string with decimal numbers to numeric ascii-code list
def ascii_to_list(string):
rc = []
for c in string:
rc.append(ord(c))
return rc
# Convert an ascii hex string to numeric list
def asciihex_to_list(string):
string = string.translate(None, ':')
try:
return map(ord, string.decode("hex"))
except:
print "Warning: Invalid hex string -- ignored!"
return []