laforge has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/35749?usp=email )


Change subject: pySim.esim: Add class for parsing/encoding eSIM activation codes
......................................................................

pySim.esim: Add class for parsing/encoding eSIM activation codes

Change-Id: I2256722c04b56e8d9c16a65e3cd94f6a46f4ed85
---
M pySim/esim/__init__.py
M tests/test_esim.py
2 files changed, 99 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/49/35749/1

diff --git a/pySim/esim/__init__.py b/pySim/esim/__init__.py
index 4d6c609..dfacb83 100644
--- a/pySim/esim/__init__.py
+++ b/pySim/esim/__init__.py
@@ -1,4 +1,5 @@
 import sys
+from typing import Optional
 from importlib import resources

 import asn1tools
@@ -14,3 +15,79 @@
     #else:
         #print(resources.read_text(__name__, 'asn1/rsp.asn'))
     return asn1tools.compile_string(asn_txt, codec='der')
+
+
+# SGP.22 section 4.1 Activation Code
+class ActivationCode:
+    def __init__(self, hostname:str, token:str, oid: Optional[str] = None, 
cc_required: Optional[bool] = False):
+        if '$' in hostname:
+            raise ValueError('$ sign not permitted in hostname')
+        self.hostname = hostname
+        if '$' in token:
+            raise ValueError('$ sign not permitted in token')
+        self.token = token
+        # TODO: validate OID
+        self.oid = oid
+        self.cc_required = cc_required
+        # only format 1 is specified and supported here
+        self.format = 1
+
+    @staticmethod
+    def decode_str(ac: str) -> dict:
+        if ac[0] != '1':
+            raise ValueError("Unsupported AC_Format '%s'!" % ac[0])
+        ac_elements = ac.split('$')
+        d = {
+            'oid': None,
+            'cc_required': False,
+          }
+        d['format'] = ac_elements.pop(0)
+        d['hostname'] = ac_elements.pop(0)
+        d['token'] = ac_elements.pop(0)
+        if len(ac_elements):
+            oid = ac_elements.pop(0)
+            if oid != '':
+                d['oid'] = oid
+        if len(ac_elements):
+            ccr = ac_elements.pop(0)
+            if ccr == '1':
+                d['cc_required'] = True
+        return d
+
+    @classmethod
+    def from_string(cls, ac: str) -> 'ActivationCode':
+        """Create new instance from SGP.22 section 4.1 string 
representation."""
+        d = cls.decode_str(ac)
+        return cls(d['hostname'], d['token'], d['oid'], d['cc_required'])
+
+    def to_string(self, for_qrcode:bool = False) -> str:
+        """Convert from internal representation to SGP.22 section 4.1 string 
representation."""
+        if for_qrcode:
+            ret = 'LPA:'
+        else:
+            ret = ''
+        ret += '%d$%s$%s' % (self.format, self.hostname, self.token)
+        if self.oid:
+            ret += '$%s' % (self.oid)
+        elif self.cc_required:
+            ret += '$'
+        if self.cc_required:
+            ret += '$1'
+        return ret
+
+    def __str__(self):
+        return self.to_string()
+
+    def to_qrcode(self):
+        """Encode internal representation to QR code."""
+        import qrcode
+        qr = qrcode.QRCode()
+        qr.add_data(self.to_string(for_qrcode=True))
+        return qr.make_image()
+
+    def __repr__(self):
+        return "ActivationCode(format=%u, hostname='%s', token='%s', oid=%s, 
cc_required=%s)" % (self.format,
+                                                                               
                  self.hostname,
+                                                                               
                  self.token,
+                                                                               
                  self.oid,
+                                                                               
                  self.cc_required)
diff --git a/tests/test_esim.py b/tests/test_esim.py
index d4b494e..81926e5 100755
--- a/tests/test_esim.py
+++ b/tests/test_esim.py
@@ -22,9 +22,22 @@
 from pySim.utils import b2h, h2b
 from pySim.esim.bsp import *
 import pySim.esim.rsp as rsp
+from pySim.esim import ActivationCode

 from cryptography.hazmat.primitives.asymmetric import ec

+class TestActivationCode(unittest.TestCase):
+    def test_de_encode(self):
+        STRS = ['1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815',
+                '1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$$1',
+                '1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746$1',
+                '1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746',
+                '1$SMDP.GSMA.COM$$1.3.6.1.4.1.31746']
+        for s in STRS:
+            ac = ActivationCode.from_string(s)
+            self.assertEqual(s, ac.to_string())
+
+
 class TestECKA(unittest.TestCase):
     def test_mode51(self):
         curve = ec.SECP256R1()

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

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I2256722c04b56e8d9c16a65e3cd94f6a46f4ed85
Gerrit-Change-Number: 35749
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <[email protected]>
Gerrit-MessageType: newchange

Reply via email to