laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/pysim/+/41875?usp=email )

Change subject: contrib: add utility to receive ES2+handleDownloadProgressInfo 
calls
......................................................................

contrib: add utility to receive ES2+handleDownloadProgressInfo calls

We already have a tool to work with the ES2+ API provided by an SMDP+
(es2p_client.py) With this tool we can only make API calls towards
an SMDP+. However, SGP.22 also defines a "reverse direction" ES2+
interface through wich the SMDP+ may make API calls towards the MNO.

At the moment the only possible MNO originated API call is
ES2+handleDownloadProgressInfo. Let's add a simple tool that runs a
HTTP server to receive and log the ES2+handleDownloadProgressInfo
requests.

Related: SYS#7825
Change-Id: I95af30cebae31f7dc682617b1866f4a2dc9b760c
---
A contrib/es2p_server.py
1 file changed, 99 insertions(+), 0 deletions(-)

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified




diff --git a/contrib/es2p_server.py b/contrib/es2p_server.py
new file mode 100755
index 0000000..6d71689
--- /dev/null
+++ b/contrib/es2p_server.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+
+# (C) 2026 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 Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import argparse
+import logging
+import json
+import asn1tools
+import asn1tools.codecs.ber
+import asn1tools.codecs.der
+import pySim.esim.rsp as rsp
+import pySim.esim.saip as saip
+from pySim.esim.es2p import param, Es2pApiServerMno, Es2pApiServerHandlerMno
+from osmocom.utils import b2h
+from datetime import datetime
+from analyze_simaResponse import split_sima_response
+
+logger = logging.getLogger(__name__)
+
+parser = argparse.ArgumentParser(description="""
+Utility to receive and log requests against the ES2+ API of an SM-DP+ 
according to GSMA SGP.22.""")
+parser.add_argument("--host", help="Host/IP to bind HTTP(S) to", 
default="localhost")
+parser.add_argument("--port", help="TCP port to bind HTTP(S) to", default=443, 
type=int)
+parser.add_argument('--server-cert', help='X.509 server certificate used to 
provide the ES2+ HTTPs service')
+parser.add_argument('--client-ca-cert', help='X.509 CA certificates to 
authenticate the requesting client(s)')
+parser.add_argument("-v", "--verbose", help="enable debug output", 
action='store_true', default=False)
+
+def decode_sima_response(sima_response):
+    decoded = []
+    euicc_response_list = split_sima_response(sima_response)
+    for euicc_response in euicc_response_list:
+        decoded.append(saip.asn1.decode('EUICCResponse', euicc_response))
+    return decoded
+
+def decode_result_data(result_data):
+    return rsp.asn1.decode('PendingNotification', result_data)
+
+def decode(data, path="/"):
+    if data is None:
+        return 'none'
+    elif type(data) is datetime:
+        return data.isoformat()
+    elif type(data) is tuple:
+        return {str(data[0]) : decode(data[1], path + str(data[0]) + "/")}
+    elif type(data) is list:
+        new_data = []
+        for item in data:
+            new_data.append(decode(item, path))
+        return new_data
+    elif type(data) is bytes:
+        return b2h(data)
+    elif type(data) is dict:
+        new_data = {}
+        for key, item in data.items():
+            new_key = str(key)
+            if path == '/' and new_key == 'resultData':
+                new_item = decode_result_data(item)
+            elif (path == 
'/resultData/profileInstallationResult/profileInstallationResultData/finalResult/successResult/'
 \
+                  or path == 
'/resultData/profileInstallationResult/profileInstallationResultData/finalResult/errorResult/')
 \
+                  and new_key == 'simaResponse':
+                new_item = decode_sima_response(item)
+            else:
+                new_item = item
+            new_data[new_key] = decode(new_item, path + new_key + "/")
+        return new_data
+    else:
+        return data
+
+class Es2pApiServerHandlerForLogging(Es2pApiServerHandlerMno):
+    def call_handleDownloadProgressInfo(self, data: dict) -> (dict, str):
+        logging.info("ES2+:handleDownloadProgressInfo: %s" % 
json.dumps(decode(data)))
+        return {}, None
+
+if __name__ == "__main__":
+    args = parser.parse_args()
+
+    logging.basicConfig(level=logging.DEBUG if args.verbose else 
logging.WARNING,
+                        format='%(asctime)s %(levelname)s %(message)s',
+                        datefmt='%Y-%m-%d %H:%M:%S')
+
+    Es2pApiServerMno(args.port, args.host, Es2pApiServerHandlerForLogging(), 
args.server_cert, args.client_ca_cert)
+

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/41875?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I95af30cebae31f7dc682617b1866f4a2dc9b760c
Gerrit-Change-Number: 41875
Gerrit-PatchSet: 3
Gerrit-Owner: dexter <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>

Reply via email to