blob: 0f77dfe35c91a004da913a19b63152ee7e763318 [file] [log] [blame]
Harald Weltec781ab82021-05-23 11:50:19 +02001#!/usr/bin/env python3
2
3# RESTful HTTP service for performing authentication against USIM cards
4#
5# (C) 2021 by Harald Welte <laforge@osmocom.org>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20import json
21import sys
22import argparse
23
24from klein import run, route
25
26from pySim.transport import ApduTracer
27from pySim.transport.pcsc import PcscSimLink
28from pySim.commands import SimCardCommands
29from pySim.cards import UsimCard
30from pySim.exceptions import *
31
32class ApduPrintTracer(ApduTracer):
33 def trace_response(self, cmd, sw, resp):
34 #print("CMD: %s -> RSP: %s %s" % (cmd, sw, resp))
35 pass
36
37@route('/sim-auth-api/v1/slot/<int:slot>')
38def auth(request, slot):
39 """REST API endpoint for performing authentication against a USIM.
40 Expects a JSON body containing RAND and AUTN.
41 Returns a JSON body containing RES, CK, IK and Kc."""
42 try:
43 # there are two hex-string JSON parameters in the body: rand and autn
44 content = json.loads(request.content.read())
45 rand = content['rand']
46 autn = content['autn']
47 except:
48 request.setResponseCode(400)
49 return "Malformed Request"
50
51 try:
52 tp = PcscSimLink(slot, apdu_tracer=ApduPrintTracer())
53 tp.connect()
54 except ReaderError:
55 request.setResponseCode(404)
56 return "Specified SIM Slot doesn't exist"
57 except ProtocolError:
58 request.setResponseCode(500)
59 return "Error"
60 except NoCardError:
61 request.setResponseCode(410)
62 return "No SIM card inserted in slot"
63
64 scc = SimCardCommands(tp)
65 card = UsimCard(scc)
66 # this should be part of UsimCard, but FairewavesSIM breaks with that :/
67 scc.cla_byte = "00"
68 scc.sel_ctrl = "0004"
69 try:
70 card.read_aids()
71 card.select_adf_by_aid(adf='usim')
72 res, sw = scc.authenticate(rand, autn)
73 except SwMatchError as e:
74 request.setResponseCode(500)
75 return "Communication Error %s" % e
76
77 tp.disconnect()
78
79 return json.dumps(res, indent=4)
80
81def main(argv):
82 parser = argparse.ArgumentParser()
83 parser.add_argument("-H", "--host", help="Host/IP to bind HTTP to", default="localhost")
84 parser.add_argument("-p", "--port", help="TCP port to bind HTTP to", default=8000)
85 #parser.add_argument("-v", "--verbose", help="increase output verbosity", action='count', default=0)
86
87 args = parser.parse_args()
88
89 run(args.host, args.port)
90
91if __name__ == "__main__":
92 main(sys.argv)