# coding=utf-8 # (C) 2022 by Harald Welte # # 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 . import logging from typing import Tuple import pyshark from osmocom.gsmtap import GsmtapMessage from pySim.utils import h2b from pySim.apdu.ts_102_221 import ApduCommands as UiccApduCommands from pySim.apdu.ts_102_222 import ApduCommands as UiccAdmApduCommands from pySim.apdu.ts_31_102 import ApduCommands as UsimApduCommands from pySim.apdu.global_platform import ApduCommands as GpApduCommands from . import ApduSource, PacketType, CardReset ApduCommands = UiccApduCommands + UiccAdmApduCommands + UsimApduCommands + GpApduCommands logger = logging.getLogger(__name__) class _PysharkGsmtap(ApduSource): """APDU Source [provider] base class for reading GSMTAP SIM APDU via tshark.""" def __init__(self, pyshark_inst): self.pyshark = pyshark_inst self.bank_id = None self.bank_slot = None self.cmd_tpdu = None super().__init__() def read_packet(self) -> PacketType: p = self.pyshark.next() return self._parse_packet(p) def _set_or_verify_bank_slot(self, bsl: Tuple[int, int]): """Keep track of the bank:slot to make sure we don't mix traces of multiple cards""" if not self.bank_id: self.bank_id = bsl[0] self.bank_slot = bsl[1] else: if self.bank_id != bsl[0] or self.bank_slot != bsl[1]: raise ValueError('Received data for unexpected B(%u:%u)' % (bsl[0], bsl[1])) def _parse_packet(self, p) -> PacketType: udp_layer = p['udp'] udp_payload_hex = udp_layer.get_field('payload').replace(':','') gsmtap = GsmtapMessage(h2b(udp_payload_hex)) gsmtap_msg = gsmtap.decode() if gsmtap_msg['type'] != 'sim': raise ValueError('Unsupported GSMTAP type %s' % gsmtap_msg['type']) sub_type = gsmtap_msg['sub_type'] if sub_type == 'apdu': return ApduCommands.parse_cmd_bytes(gsmtap_msg['body']) if sub_type == 'atr': # card has been reset return CardReset(gsmtap_msg['body']) if sub_type in ['pps_req', 'pps_rsp']: # simply ignore for now pass else: raise ValueError('Unsupported GSMTAP-SIM sub-type %s' % sub_type) class PysharkGsmtapPcap(_PysharkGsmtap): """APDU Source [provider] class for reading GSMTAP from a PCAP file via pyshark, which in turn uses tshark (part of wireshark). """ def __init__(self, pcap_filename): """ Args: pcap_filename: File name of the pcap file to be opened """ pyshark_inst = pyshark.FileCapture(pcap_filename, display_filter='gsm_sim', use_json=True, keep_packets=False) super().__init__(pyshark_inst)