sysmo-usim-tool/simcard.py

217 lines
5.2 KiB
Python
Raw Normal View History

#!/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)