Tool to (re)configure the sysmoUSIM and sysmoISIM cards
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
5.6 KiB

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. Gadgets to modify SYSMO USIM SJS1 parameters
  5. (C) 2017 by Sysmocom s.f.m.c. GmbH
  6. All Rights Reserved
  7. Author: Philipp Maier
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. from card import *
  20. from simcard import *
  21. from utils import *
  22. import sys
  23. # CHV Types
  24. SYSMO_USIM_ADM1 = 0x0A
  25. class Sysmo_usim:
  26. sim = None
  27. def __init__(self, atr):
  28. print("Initializing smartcard terminal...")
  29. self.sim = Simcard(GSM_USIM, toBytes(atr))
  30. self.sim.card.SELECT_ADF_USIM()
  31. print(" * Detected Card IMSI: %s" % self.sim.card.get_imsi())
  32. if self.sim.has_isim:
  33. print(" ISIM Application installed")
  34. if self.sim.has_usim:
  35. print(" USIM Application installed")
  36. print("")
  37. def _warn_failed_auth(self, attempts = 3, keytype = "ADM1"):
  38. print(" === Authentication problem! The Card will permanently ===")
  39. print(" === lock down after %d failed attemts! Double check %s! ===" % (attempts, keytype))
  40. print("")
  41. def _warn_remaining_auth(self, attempts = 3, keytype = "ADM1"):
  42. print(" * Error: Only two authentication attempts remaining, we don't")
  43. print(" want to risk another failed authentication attempt!")
  44. print(" (double check ADM1 and use option -f to override)")
  45. print("")
  46. # Initalize card (select master file)
  47. def _init(self):
  48. print(" * Initalizing...")
  49. self.sim.select(GSM_SIM_MF)
  50. # Read files sensitively
  51. def _read_binary(self, length, offset=0):
  52. res = self.sim.read_binary(length, offset)
  53. if len(res.apdu) != length:
  54. print(" Error: could not read file (sw=%02x%02x) -- abort!\n" % (res.sw[0], res.sw[1]))
  55. exit(1)
  56. return res
  57. # Authenticate as administrator
  58. def admin_auth(self, adm1, force = False):
  59. print("Authenticating...")
  60. rc = True
  61. rem_attemts = self.sim.chv_retrys(SYSMO_USIM_ADM1)
  62. print(" * Remaining attempts: " + str(rem_attemts))
  63. # Stop if a decreased ADM1 retry counter is detected
  64. if(rem_attemts < 3) and force == False:
  65. self._warn_remaining_auth()
  66. self._warn_failed_auth()
  67. return False
  68. if(len(adm1) != 8):
  69. print(" * Error: Short ADM1, a valid ADM1 is 8 digits long!")
  70. print("")
  71. self._warn_failed_auth()
  72. return False
  73. # Try to authenticate
  74. try:
  75. print(" * Authenticating...")
  76. res = self.sim.verify_chv(adm1, SYSMO_USIM_ADM1)
  77. if res.sw != [0x90, 0x00]:
  78. raise
  79. print(" * Authentication successful")
  80. except:
  81. print(" * Error: Authentication failed!")
  82. rc = False
  83. # Read back and display remaining attemts
  84. rem_attemts = self.sim.chv_retrys(SYSMO_USIM_ADM1)
  85. print(" * Remaining attempts: " + str(rem_attemts))
  86. print("")
  87. if rc == False:
  88. self._warn_failed_auth()
  89. return rc
  90. # Show current ICCID value
  91. def show_iccid(self):
  92. print("Reading ICCID value...")
  93. self._init()
  94. print(" * Reading...")
  95. print(" * Card ICCID: %s" % self.sim.card.get_ICCID())
  96. print("")
  97. # Program new ICCID value
  98. # Note: Since the ICCID is a stanard file writing to it works the same
  99. # way for all card models. However, the ICCID may be linked to the
  100. # license management of the card O/S, so changing it might cause
  101. # problems for some cards models. (USE WITH CAUTION!)
  102. def write_iccid(self, iccid):
  103. print("Writing ICCID value...")
  104. self._init()
  105. print(" * New ICCID setting:")
  106. print(" ICCID: " + hexdump(iccid))
  107. self.sim.select(GSM_SIM_EF_ICCID)
  108. print(" * Programming...")
  109. self.sim.update_binary(swap_nibbles(iccid))
  110. print("")
  111. # Program new IMSI value
  112. def write_imsi(self, imsi):
  113. print("Writing IMSI value...")
  114. self._init()
  115. print(" * New ISMI setting:")
  116. print(" IMSI: " + hexdump(imsi))
  117. self.sim.select(GSM_SIM_DF_GSM)
  118. self.sim.select(GSM_SIM_EF_IMSI)
  119. imsi = [len(imsi)] + swap_nibbles(imsi)
  120. print(" * Programming...")
  121. self.sim.update_binary(imsi)
  122. print("")
  123. # Show current mnc length value
  124. def show_mnclen(self):
  125. print("Reading MNCLEN value...")
  126. self._init()
  127. print(" * Reading...")
  128. self.sim.select(GSM_SIM_DF_GSM)
  129. self.sim.select(GSM_SIM_EF_AD)
  130. res = self.sim.read_binary(4)
  131. print(" * Current MNCLEN setting:")
  132. print(" MNCLEN: " + "0x%02x" % res.apdu[3])
  133. print("")
  134. # Program new mnc length value
  135. def write_mnclen(self, mnclen):
  136. print("Writing MNCLEN value...")
  137. self._init()
  138. print(" * New MNCLEN setting:")
  139. print(" MNCLEN: " + "0x" + hexdump(mnclen))
  140. if len(mnclen) != 1:
  141. print(" * Error: mnclen value must consist of a single byte!")
  142. return
  143. self.sim.select(GSM_SIM_DF_GSM)
  144. self.sim.select(GSM_SIM_EF_AD)
  145. res = self.sim.read_binary(4)
  146. new_ad = res.apdu[0:3] + mnclen
  147. print(" * Programming...")
  148. self.sim.update_binary(new_ad)
  149. print("")
  150. # Show installed applications (AIDs)
  151. def show_aid(self):
  152. print("Reading application directory...");
  153. self._init()
  154. self.sim.card.get_AID()
  155. AID = self.sim.card.AID
  156. for a in AID:
  157. if a[0:7] == [0xA0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x02]:
  158. appstr = "USIM"
  159. elif a[0:7] == [0xA0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x04]:
  160. appstr = "ISIM"
  161. else:
  162. appstr = "(unknown)"
  163. print(" AID: " + hexdump(a[0:5]) + " " + hexdump(a[5:7]) + " " + hexdump(a[7:]) + " ==> " + appstr)
  164. print("")