From 14aaab262e68332f83c3224504f4cd1463b49c7c Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Fri, 17 Mar 2017 16:43:35 +0100 Subject: [PATCH] auth: prevent unintential card lock down If the user submints a wrong ADM1 key with the commandline, the authentication will fail. However, by the output of the program it mey not be clear to the user that the reason for the failure was a wrong ADM1 key. The user might try the same command with the same parameters a few time and lock down the card. This commit fixes that by failing gracefully with a very clear error message. Furthermore, if a decreased authentication counter is detected, no further authentication attempts will be made until the user supplies the option -f (--force). --- simcard.py | 15 +++++++++++++-- sysmo-usim-tool.sjs1.py | 16 ++++++++++++++-- sysmo_usimsjs1.py | 41 +++++++++++++++++++++++++++-------------- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/simcard.py b/simcard.py index 9241a46..f617ca1 100644 --- a/simcard.py +++ b/simcard.py @@ -146,13 +146,24 @@ class Simcard(): cla = self.__get_cla(self.usim) ins = GSM_SIM_INS_VERIFY_CHV - length = 0x08 - + length = len(chv) apdu = self.card.apdu(cla, ins, p2 = chv_no, p3 = length, data = chv) return self.card.transact(apdu, dry, strict) + # Read CHV retry counter + def chv_retrys(self, chv_no, dry = False, strict = True): + + cla = self.__get_cla(self.usim) + ins = GSM_SIM_INS_VERIFY_CHV + length = 0 + apdu = self.card.apdu(cla, ins, p2 = chv_no, + p3 = length, sw=[0x63, None]) + res = self.card.transact(apdu, dry, strict) + return res.sw[1] & 0x0F + + # Perform file operation (Write) def update_binary(self, data, offset = 0, dry = False, strict = True): diff --git a/sysmo-usim-tool.sjs1.py b/sysmo-usim-tool.sjs1.py index 5cf7568..0693989 100755 --- a/sysmo-usim-tool.sjs1.py +++ b/sysmo-usim-tool.sjs1.py @@ -70,15 +70,16 @@ def main(argv): getopt_write_opc = None getopt_show_ki = None getopt_write_ki = None + getopt_force = False # Analyze commandline options try: opts, args = getopt.getopt(argv, - "hva:ucmtT:lL:oO:C:kK:", + "hva:ucmtT:lL:oO:C:kK:f", ["help","verbose","adm1=","usim","classic", "mode","auth","set-auth=","milenage", "set-milenage","opc","set-op=","set-opc=", - "ki","set-ki="]) + "ki","set-ki=","force"]) except getopt.GetoptError: print " * Error: Invalid commandline options" sys.exit(2) @@ -115,6 +116,8 @@ def main(argv): getopt_show_ki = True elif opt in ("-K", "--set-ki"): getopt_write_ki = asciihex_to_list(arg) + elif opt in ("-f", "--force"): + getopt_force = True if not getopt_adm1: @@ -129,6 +132,15 @@ def main(argv): sim = Simcard(c) print("") + # Authenticate + print "Authenticating..." + if sysmo_usim_admin_auth(sim, getopt_adm1, getopt_force) == False: + print "" + print " === Authentication problem! The Card will permanently ===" + print " === lock down after 3 failed attemts! Double check ADM1! ===" + print "" + exit(1) + print("") # Execute tasks if getopt_write_sim_mode != None: diff --git a/sysmo_usimsjs1.py b/sysmo_usimsjs1.py index c0925a5..a68a3e5 100644 --- a/sysmo_usimsjs1.py +++ b/sysmo_usimsjs1.py @@ -137,16 +137,39 @@ def sysmo_usim_init(sim): # Authenticate as administrator -def sysmo_usim_admin_auth(sim, adm1): - print " * Authenticating at card as administrator..." - sim.verify_chv(adm1, SYSMO_USIMSJS1_ADM1) +def sysmo_usim_admin_auth(sim, adm1, force = False): + rc = True + rem_attemts = sim.chv_retrys(SYSMO_USIMSJS1_ADM1) + + print " * Remaining attempts: " + str(rem_attemts) + + # Stop if a decreased ADM1 retry counter is detected + if(rem_attemts < 3) and force == False: + print " * Error: Only two authentication attemts remaining, we don't" + print " want to risk another failed authentication attempt!" + print " (double check ADM1 and use option -f to override)" + return False + + # Try to authenticate + try: + print " * Authenticating..." + sim.verify_chv(adm1, SYSMO_USIMSJS1_ADM1) + print " * Authentication successful" + except: + print " * Error: Authentication failed!" + rc = False + + # Read back and display remaining attemts + rem_attemts = sim.chv_retrys(SYSMO_USIMSJS1_ADM1) + print " * Remaining attempts: " + str(rem_attemts) + + return rc # 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) @@ -165,7 +188,6 @@ def sysmo_usim_write_auth_params(sim, adm1, algo_2g, algo_3g): print " 3G: " + str(hex(algo_3g)) sysmo_usim_init(sim) - sysmo_usim_admin_auth(sim, adm1) print " * Programming..." sim.select(SYSMO_USIMSJS1_DF_AUTH) @@ -176,7 +198,6 @@ def sysmo_usim_write_auth_params(sim, adm1, 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) sim.select(SYSMO_USIMSJS1_DF_AUTH) sim.select(SYSMO_USIMSJS1_EF_MLNGC) @@ -211,7 +232,6 @@ def sysmo_usim_show_milenage_params(sim, adm1): # 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) @@ -235,7 +255,6 @@ def sysmo_usim_write_milenage_params(sim, adm1, ef_mlngc): # 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) @@ -254,7 +273,6 @@ def sysmo_usim_write_opc_params(sim, adm1, select, op): 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) @@ -266,7 +284,6 @@ def sysmo_usim_write_opc_params(sim, adm1, select, op): # Show current KI value def sysmo_usim_show_ki_params(sim, adm1): sysmo_usim_init(sim) - sysmo_usim_admin_auth(sim, adm1) print " * Reading..." sim.select(GSM_SIM_DF_GSM) @@ -283,7 +300,6 @@ def sysmo_usim_write_ki_params(sim, adm1, ki): print " KI: " + hexdump(ki) sysmo_usim_init(sim) - sysmo_usim_admin_auth(sim, adm1) sim.select(GSM_SIM_DF_GSM) sim.select(SYSMO_USIMSJS1_EF_KI) @@ -295,7 +311,6 @@ def sysmo_usim_write_ki_params(sim, adm1, ki): # 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) @@ -308,7 +323,6 @@ def sysmo_usim_show_usim_status(sim, adm1): # 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) @@ -338,7 +352,6 @@ def sysmo_usim_write_sim_mode(sim, adm1, usim_enabled = True): print " ==> USIM application disabled" sysmo_usim_init(sim) - sysmo_usim_admin_auth(sim, adm1) print " * Programming..." sim.select(GSM_USIM_EF_DIR)