diff --git a/card.py b/card.py
deleted file mode 100644
index 748a7ff..0000000
--- a/card.py
+++ /dev/null
@@ -1,186 +0,0 @@
-#!/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 .
-"""
-
-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)
-
-
diff --git a/simcard.py b/simcard.py
index f617ca1..915aa94 100644
--- a/simcard.py
+++ b/simcard.py
@@ -23,59 +23,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-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]
+from card.USIM import USIM
+from card.SIM import SIM
+from card.utils import *
# Files
GSM_SIM_MF = [0x3F, 0x00]
@@ -104,124 +54,81 @@ GSM_SIM_INS_UPDATE_RECORD_NEXT = 0x02
GSM_SIM_INS_UPDATE_RECORD_PREV = 0x03
GSM_SIM_INS_UPDATE_RECORD_ABS = 0x04
+class Card_res_apdu():
+ apdu = None
+ sw = None
+ swok = True
+
+ # convert Benoit Michau style result to sysmocom style result
+ def from_mich(self, mich):
+ self.apdu = mich[3]
+ self.sw = [ mich[2][0], mich[2][1] ]
+
+ def __str__(self):
+ dump = "APDU: " + hexdump(self.apdu)
+ dump += " SW: " + hexdump(self.sw)
+ return dump
+
# 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
+ def __init__(self, cardtype = GSM_USIM):
if cardtype == GSM_USIM:
+ self.card = USIM()
self.usim = True
else:
- self.usim = True
-
+ self.card = SIM()
+ self.usim = False
# 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
-
+ return self.card.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)
-
+ res = Card_res_apdu()
+ res.from_mich(self.card.SELECT_FILE(P2 = 0x0C, Data = fid))
+ return res
# 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 = len(chv)
- apdu = self.card.apdu(cla, ins, p2 = chv_no,
- p3 = length, data = chv)
- return self.card.transact(apdu, dry, strict)
-
+ res = Card_res_apdu()
+ res.from_mich(self.card.VERIFY(P2 = chv_no, Data = chv))
+ return res
# 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
-
+ res = self.card.VERIFY(P2 = chv_no)
+ return res[2][1] & 0x0F
# 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)
-
+ res = Card_res_apdu()
+ res.from_mich(self.card.UPDATE_BINARY(offs_high, offs_low, data))
+ return res
# 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)
-
+ res = Card_res_apdu()
+ res.from_mich(self.card.READ_BINARY(offs_high, offs_low, length))
+ return res
# 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)
+ res = Card_res_apdu()
+ res.from_mich(self.card.READ_RECORD(rec_no, GSM_SIM_INS_READ_RECORD_ABS, length))
+ return res
# 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)
-
-
-
-
-
-
-
-
-
-
-
-
+ res = Card_res_apdu()
+ res.from_mich(self.card.UPDATE_RECORD(rec_no, GSM_SIM_INS_UPDATE_RECORD_ABS, data))
+ return res
diff --git a/sysmo-usim-tool.sjs1.py b/sysmo-usim-tool.sjs1.py
index dd2af92..1ba436d 100755
--- a/sysmo-usim-tool.sjs1.py
+++ b/sysmo-usim-tool.sjs1.py
@@ -24,7 +24,7 @@ along with this program. If not, see .
"""
import sys, getopt
-from card import *
+from utils import *
from simcard import *
from sysmo_usimsjs1 import *
@@ -131,8 +131,7 @@ def main(argv):
# Claim terminal
print "Initializing smartcard terminal..."
- c = Card(getopt_verbose)
- sim = Simcard(c)
+ sim = Simcard()
print("")
print "Detected Card ICCID: ", sim.card.get_ICCID()
diff --git a/sysmo_usimsjs1.py b/sysmo_usimsjs1.py
index 063af57..baf1d82 100644
--- a/sysmo_usimsjs1.py
+++ b/sysmo_usimsjs1.py
@@ -49,8 +49,10 @@ along with this program. If not, see .
# +--[EF_KI 0x00FF]
+import sys
from card import *
from simcard import *
+from utils import *
# Files (propritary)
SYSMO_USIMSJS1_EF_KI = [0x00, 0xFF]