blob: 8ea9ae7c5fa3fb616dd8ba415611aa0744ef6d6a [file] [log] [blame]
Harald Weltec95f6e22022-12-02 22:50:35 +01001# coding=utf-8
2
3# (C) 2022 by Harald Welte <laforge@osmocom.org>
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18
19import sys
20import logging
21from pprint import pprint as pp
22from typing import Tuple
23import pyshark
24
25from pySim.utils import h2b, b2h
26from pySim.apdu import Tpdu
27from pySim.gsmtap import GsmtapMessage
28from . import ApduSource, PacketType, CardReset
29
30from pySim.apdu.ts_102_221 import ApduCommands as UiccApduCommands
31from pySim.apdu.ts_31_102 import ApduCommands as UsimApduCommands
32from pySim.apdu.global_platform import ApduCommands as GpApduCommands
33ApduCommands = UiccApduCommands + UsimApduCommands + GpApduCommands
34
35logger = logging.getLogger(__name__)
36
37class _PysharkGsmtap(ApduSource):
38 """APDU Source [provider] base class for reading GSMTAP SIM APDU via tshark."""
39
40 def __init__(self, pyshark_inst):
41 self.pyshark = pyshark_inst
42 self.bank_id = None
43 self.bank_slot = None
44 self.cmd_tpdu = None
45 super().__init__()
46
47 def read_packet(self) -> PacketType:
48 p = self.pyshark.next()
49 return self._parse_packet(p)
50
51 def _set_or_verify_bank_slot(self, bsl: Tuple[int, int]):
52 """Keep track of the bank:slot to make sure we don't mix traces of multiple cards"""
53 if not self.bank_id:
54 self.bank_id = bsl[0]
55 self.bank_slot = bsl[1]
56 else:
57 if self.bank_id != bsl[0] or self.bank_slot != bsl[1]:
58 raise ValueError('Received data for unexpected B(%u:%u)' % (bsl[0], bsl[1]))
59
60 def _parse_packet(self, p) -> PacketType:
61 udp_layer = p['udp']
62 udp_payload_hex = udp_layer.get_field('payload').replace(':','')
63 gsmtap = GsmtapMessage(h2b(udp_payload_hex))
64 gsmtap_msg = gsmtap.decode()
65 if gsmtap_msg['type'] != 'sim':
66 raise ValueError('Unsupported GSMTAP type %s' % gsmtap_msg['type'])
67 sub_type = gsmtap_msg['sub_type']
68 if sub_type == 'apdu':
69 return ApduCommands.parse_cmd_bytes(gsmtap_msg['body'])
70 elif sub_type == 'atr':
71 # card has been reset
72 return CardReset()
73 elif sub_type in ['pps_req', 'pps_rsp']:
74 # simply ignore for now
75 pass
76 else:
77 raise ValueError('Unsupported GSMTAP-SIM sub-type %s' % sub_type)
78
79class PysharkGsmtapPcap(_PysharkGsmtap):
80 """APDU Source [provider] class for reading GSMTAP from a PCAP
81 file via pyshark, which in turn uses tshark (part of wireshark).
82 """
83 def __init__(self, pcap_filename):
84 """
85 Args:
86 pcap_filename: File name of the pcap file to be opened
87 """
88 pyshark_inst = pyshark.FileCapture(pcap_filename, display_filter='gsm_sim', use_json=True, keep_packets=False)
89 super().__init__(pyshark_inst)
90