Vadim Yanitskiy has submitted this change and it was merged. ( https://gerrit.osmocom.org/11480 )
Change subject: pySim/transport: introduce Calypso based reader interface ...................................................................... pySim/transport: introduce Calypso based reader interface This interface allows to use a Calypso based phone (e.g. Motorola C1XX) as a SIM card reader. It basically implements a few L1CTL messages that are used to interact with the SIM card through the OsmocomBB 'layer1' firmware. Please note, that this is an experimental implementation, and there is a risk that SIM programming would fail. Nevertheless, I've managed to program and read one of my SIMs a few times. Change-Id: Iec8101140581bf9e2cf7cf3a0b54bdf1875fc51b --- M pySim/exceptions.py A pySim/transport/calypso.py 2 files changed, 160 insertions(+), 0 deletions(-) Approvals: Jenkins Builder: Verified Harald Welte: Looks good to me, but someone else must approve tnt: Looks good to me, approved diff --git a/pySim/exceptions.py b/pySim/exceptions.py index 403f54c..831b1c9 100644 --- a/pySim/exceptions.py +++ b/pySim/exceptions.py @@ -31,3 +31,6 @@ class ProtocolError(exceptions.Exception): pass + +class ReaderError(exceptions.Exception): + pass diff --git a/pySim/transport/calypso.py b/pySim/transport/calypso.py new file mode 100644 index 0000000..fd501b5 --- /dev/null +++ b/pySim/transport/calypso.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" pySim: Transport Link for Calypso bases phones +""" + +# +# Copyright (C) 2018 Vadim Yanitskiy <axilira...@gmail.com> +# +# 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 __future__ import absolute_import + +import select +import struct +import socket +import os + +from pySim.transport import LinkBase +from pySim.exceptions import * +from pySim.utils import h2b, b2h + +class L1CTLMessage(object): + + # Every (encoded) L1CTL message has the following structure: + # - msg_length (2 bytes, net order) + # - l1ctl_hdr (packed structure) + # - msg_type + # - flags + # - padding (2 spare bytes) + # - ... payload ... + + def __init__(self, msg_type, flags = 0x00): + # Init L1CTL message header + self.data = struct.pack("BBxx", msg_type, flags) + + def gen_msg(self): + return struct.pack("!H", len(self.data)) + self.data + +class L1CTLMessageReset(L1CTLMessage): + + # L1CTL message types + L1CTL_RESET_REQ = 0x0d + L1CTL_RESET_IND = 0x07 + L1CTL_RESET_CONF = 0x0e + + # Reset types + L1CTL_RES_T_BOOT = 0x00 + L1CTL_RES_T_FULL = 0x01 + L1CTL_RES_T_SCHED = 0x02 + + def __init__(self, type = L1CTL_RES_T_FULL): + super(L1CTLMessageReset, self).__init__(self.L1CTL_RESET_REQ) + self.data += struct.pack("Bxxx", type) + +class L1CTLMessageSIM(L1CTLMessage): + + # SIM related message types + L1CTL_SIM_REQ = 0x16 + L1CTL_SIM_CONF = 0x17 + + def __init__(self, pdu): + super(L1CTLMessageSIM, self).__init__(self.L1CTL_SIM_REQ) + self.data += pdu + +class CalypsoSimLink(LinkBase): + + def __init__(self, sock_path = "/tmp/osmocom_l2"): + # Make sure that a given socket path exists + if not os.path.exists(sock_path): + raise ReaderError("There is no such ('%s') UNIX socket" % sock_path) + + print("Connecting to osmocon at '%s'..." % sock_path) + + # Establish a client connection + self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.sock.connect(sock_path) + + def __del__(self): + self.sock.close() + + def wait_for_rsp(self, exp_len = 128): + # Wait for incoming data (timeout is 3 seconds) + s, _, _ = select.select([self.sock], [], [], 3.0) + if not s: + raise ReaderError("Timeout waiting for card response") + + # Receive expected amount of bytes from osmocon + rsp = self.sock.recv(exp_len) + return rsp + + def reset_card(self): + # Request FULL reset + req_msg = L1CTLMessageReset() + self.sock.send(req_msg.gen_msg()) + + # Wait for confirmation + rsp = self.wait_for_rsp() + rsp_msg = struct.unpack_from("!HB", rsp) + if rsp_msg[1] != L1CTLMessageReset.L1CTL_RESET_CONF: + raise ReaderError("Failed to reset Calypso PHY") + + def connect(self): + self.reset_card() + + def disconnect(self): + pass # Nothing to do really ... + + def wait_for_card(self, timeout = None, newcardonly = False): + pass # Nothing to do really ... + + def send_apdu_raw(self, pdu): + """see LinkBase.send_apdu_raw""" + + # Request FULL reset + req_msg = L1CTLMessageSIM(h2b(pdu)) + self.sock.send(req_msg.gen_msg()) + + # Read message length first + rsp = self.wait_for_rsp(struct.calcsize("!H")) + msg_len = struct.unpack_from("!H", rsp)[0] + if msg_len < struct.calcsize("BBxx"): + raise ReaderError("Missing L1CTL header for L1CTL_SIM_CONF") + + # Read the whole message then + rsp = self.sock.recv(msg_len) + + # Verify L1CTL header + hdr = struct.unpack_from("BBxx", rsp) + if hdr[0] != L1CTLMessageSIM.L1CTL_SIM_CONF: + raise ReaderError("Unexpected L1CTL message received") + + # Verify the payload length + offset = struct.calcsize("BBxx") + if len(rsp) <= offset: + raise ProtocolError("Empty response from SIM?!?") + + # Omit L1CTL header + rsp = rsp[offset:] + + # Unpack data and SW + data = rsp[:-2] + sw = rsp[-2:] + + return b2h(data), b2h(sw) -- To view, visit https://gerrit.osmocom.org/11480 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-MessageType: merged Gerrit-Change-Id: Iec8101140581bf9e2cf7cf3a0b54bdf1875fc51b Gerrit-Change-Number: 11480 Gerrit-PatchSet: 3 Gerrit-Owner: Vadim Yanitskiy <axilira...@gmail.com> Gerrit-Assignee: tnt <t...@246tnt.com> Gerrit-Reviewer: Harald Welte <lafo...@gnumonks.org> Gerrit-Reviewer: Jenkins Builder (1000002) Gerrit-Reviewer: Vadim Yanitskiy <axilira...@gmail.com> Gerrit-Reviewer: tnt <t...@246tnt.com>