iat-verifier: update Secure lifecycle claim

Update Secure lifecycle claim based on
https://www.ietf.org/archive/id/draft-tschofenig-rats-psa-token-21.html

Change-Id: Id455ec764ceed0ea21eee6c30aec7ccf4b1ad3c7
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/iat-verifier/dev_scripts/generate-sample-iat.py b/iat-verifier/dev_scripts/generate-sample-iat.py
index 84985de..cf0f700 100755
--- a/iat-verifier/dev_scripts/generate-sample-iat.py
+++ b/iat-verifier/dev_scripts/generate-sample-iat.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 # -----------------------------------------------------------------------------
-# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -45,7 +45,7 @@
   ImplementationIdClaim.get_claim_key(): ORIGIN,
   ChallengeClaim.get_claim_key(): NONCE,
   ClientIdClaim.get_claim_key(): 2,
-  SecurityLifecycleClaim.get_claim_key(): SecurityLifecycleClaim.SL_SECURED,
+  SecurityLifecycleClaim.get_claim_key(): 0x1000,
   ProfileIdClaim.get_claim_key(): 'http://example.com',
   BootSeedClaim.get_claim_key(): BOOT_SEED,
   SWComponentsClaim.get_claim_key(): [
diff --git a/iat-verifier/iatverifier/cca_claims.py b/iat-verifier/iatverifier/cca_claims.py
index d176656..7948425 100644
--- a/iat-verifier/iatverifier/cca_claims.py
+++ b/iat-verifier/iatverifier/cca_claims.py
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# Copyright (c) 2022, Arm Limited. All rights reserved.
+# Copyright (c) 2022-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -9,6 +9,7 @@
 import logging
 
 from iatverifier.attest_token_verifier import AttestationClaim, CompositeAttestClaim
+from iatverifier.lifecycle_claim import GenericLifecycleClaim
 
 logger = logging.getLogger('iat-verifiers')
 
@@ -167,7 +168,7 @@
     def verify(self, token_item):
         self._check_type(self.get_claim_name(), token_item.value, bytes)
 
-class CCAPlatformLifecycleClaim(AttestationClaim):
+class CCAPlatformLifecycleClaim(GenericLifecycleClaim):
 
     SL_VALUES= [
         ("UNKNOWN", 0x0000, 0x00ff),
@@ -185,45 +186,6 @@
     def get_claim_name(self=None):
         return 'CCA_PLATFORM_LIFECYCLE'
 
-    @classmethod
-    def parse_raw(cls, raw_value):
-        try:
-            int_value = int(raw_value, 16)
-        except ValueError:
-            # It is not a hex number. Try to decode known text values
-            pass
-        for text, min, max in cls.SL_VALUES:
-            if raw_value.startswith(text.lower()):
-                raw_value = raw_value[len(text):]
-            else:
-                continue
-            if len(raw_value) == 0:
-                return min
-            assert raw_value.startswith("_0x")
-            raw_value = raw_value[3:]
-            int_value = int(raw_value, 16)
-            assert(min <= int_value <= max)
-            return int_value
-        assert False
-
-    @classmethod
-    def get_formatted_value(cls, value):
-        for text, min, max in cls.SL_VALUES:
-            if min <= value <= max:
-                return f"{text}_{value:04x}".lower()
-        return f"INVALID_{value:04x}"
-
-    def verify(self, token_item):
-        self._check_type(self.get_claim_name, token_item.value, int)
-        value_valid = False
-        for _, min, max in CCAPlatformLifecycleClaim.SL_VALUES:
-            if min <= token_item.value <= max:
-                value_valid = True
-                break
-        if not value_valid:
-            msg = 'Invalid Platform Lifecycle claim "0x{:02x}"'
-            self.verifier.error(msg.format(token_item.value))
-
 class CCASwCompHashAlgIdClaim(AttestationClaim):
     def get_claim_key(self=None):
         return 6
diff --git a/iat-verifier/iatverifier/lifecycle_claim.py b/iat-verifier/iatverifier/lifecycle_claim.py
new file mode 100644
index 0000000..4503d31
--- /dev/null
+++ b/iat-verifier/iatverifier/lifecycle_claim.py
@@ -0,0 +1,50 @@
+# -----------------------------------------------------------------------------
+# Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# -----------------------------------------------------------------------------
+
+from abc import ABC, abstractmethod
+from iatverifier.attest_token_verifier import AttestationClaim
+
+class GenericLifecycleClaim(AttestationClaim):
+
+    @classmethod
+    def parse_raw(cls, raw_value):
+        try:
+            int_value = int(raw_value, 16)
+        except ValueError:
+            # It is not a hex number. Try to decode known text values
+            pass
+        for text, min, max in cls.SL_VALUES:
+            if raw_value.startswith(text.lower()):
+                raw_value = raw_value[len(text):]
+            else:
+                continue
+            if len(raw_value) == 0:
+                return min
+            assert raw_value.startswith("_0x")
+            raw_value = raw_value[3:]
+            int_value = int(raw_value, 16)
+            assert(min <= int_value <= max)
+            return int_value
+        assert False
+
+    @classmethod
+    def get_formatted_value(cls, value):
+        for text, min, max in cls.SL_VALUES:
+            if min <= value <= max:
+                return f"{text}_{value:04x}".lower()
+        return f"INVALID_{value:04x}"
+
+    def verify(self, token_item):
+        self._check_type(self.get_claim_name, token_item.value, int)
+        value_valid = False
+        for _, min, max in self.SL_VALUES:
+            if min <= token_item.value <= max:
+                value_valid = True
+                break
+        if not value_valid:
+            msg = 'Invalid Lifecycle claim "0x{:02x}"'
+            self.verifier.error(msg.format(token_item.value))
diff --git a/iat-verifier/iatverifier/psa_2_0_0_token_claims.py b/iat-verifier/iatverifier/psa_2_0_0_token_claims.py
index 06f0e78..f5287c8 100644
--- a/iat-verifier/iatverifier/psa_2_0_0_token_claims.py
+++ b/iat-verifier/iatverifier/psa_2_0_0_token_claims.py
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -9,6 +9,7 @@
 
 from iatverifier.attest_token_verifier import AttestationClaim
 from iatverifier.attest_token_verifier import CompositeAttestClaim
+from iatverifier.lifecycle_claim import GenericLifecycleClaim
 
 # IAT custom claims
 ARM_RANGE = 2393
@@ -121,46 +122,24 @@
     def verify(self, token_item):
         self._check_type('CLIENT_ID', token_item.value, int)
 
-class SecurityLifecycleClaim(AttestationClaim):
+class SecurityLifecycleClaim(GenericLifecycleClaim):
     """Class representing a PSA Attestation Token Security Lifecycle claim"""
-    SL_SHIFT = 12
-
-    SL_NAMES = [
-        'SL_UNKNOWN',
-        'SL_PSA_ROT_PROVISIONING',
-        'SL_SECURED',
-        'SL_NON_PSA_ROT_DEBUG',
-        'SL_RECOVERABLE_PSA_ROT_DEBUG',
-        'SL_PSA_LIFECYCLE_DECOMMISSIONED',
+    SL_VALUES= [
+        ("SL_UNKNOWN", 0x0000, 0x00ff),
+        ("SL_ASSEMBLY_AND_TEST", 0x1000, 0x10ff),
+        ("SL_PSA_ROT_PROVISIONING", 0x2000, 0x20ff),
+        ("SL_SECURED", 0x3000, 0x30ff),
+        ("SL_NON_PSA_ROT_DEBUG", 0x4000, 0x40ff),
+        ("SL_RECOVERABLE_PSA_ROT_DEBUG", 0x5000, 0x50ff),
+        ("SL_DECOMMISSIONED", 0x6000, 0x60ff),
     ]
 
-    # Security Lifecycle claims
-    SL_UNKNOWN = 0x1000
-    SL_PSA_ROT_PROVISIONING = 0x2000
-    SL_SECURED = 0x3000
-    SL_NON_PSA_ROT_DEBUG = 0x4000
-    SL_RECOVERABLE_PSA_ROT_DEBUG = 0x5000
-    SL_PSA_LIFECYCLE_DECOMMISSIONED = 0x6000
-
     def get_claim_key(self=None):
         return ARM_RANGE + 2
 
     def get_claim_name(self=None):
         return 'SECURITY_LIFECYCLE'
 
-    def verify(self, token_item):
-        self._check_type('SECURITY_LIFECYCLE', token_item.value, int)
-
-    @staticmethod
-    def parse_raw(raw_value):
-        name_idx = SecurityLifecycleClaim.SL_NAMES.index(raw_value.upper())
-        return (name_idx + 1) << SecurityLifecycleClaim.SL_SHIFT
-
-    @staticmethod
-    def get_formatted_value(value):
-        return SecurityLifecycleClaim.SL_NAMES[(value >> SecurityLifecycleClaim.SL_SHIFT) - 1]
-
-
 class ProfileIdClaim(AttestationClaim):
     """Class representing a PSA Attestation Token Profile Definition claim"""
     def get_claim_key(self=None):
diff --git a/iat-verifier/iatverifier/psa_iot_profile1_token_claims.py b/iat-verifier/iatverifier/psa_iot_profile1_token_claims.py
index a51b544..8fc2b4d 100644
--- a/iat-verifier/iatverifier/psa_iot_profile1_token_claims.py
+++ b/iat-verifier/iatverifier/psa_iot_profile1_token_claims.py
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -13,6 +13,7 @@
 
 from iatverifier.attest_token_verifier import AttestationClaim
 from iatverifier.attest_token_verifier import CompositeAttestClaim
+from iatverifier.lifecycle_claim import GenericLifecycleClaim
 
 # IAT custom claims
 ARM_RANGE = -75000
@@ -136,46 +137,24 @@
     def verify(self, token_item):
         self._check_type('CLIENT_ID', token_item.value, int)
 
-class SecurityLifecycleClaim(AttestationClaim):
+class SecurityLifecycleClaim(GenericLifecycleClaim):
     """Class representing a PSA Attestation Token Security Lifecycle claim"""
-    SL_SHIFT = 12
-
-    SL_NAMES = [
-        'SL_UNKNOWN',
-        'SL_PSA_ROT_PROVISIONING',
-        'SL_SECURED',
-        'SL_NON_PSA_ROT_DEBUG',
-        'SL_RECOVERABLE_PSA_ROT_DEBUG',
-        'SL_PSA_LIFECYCLE_DECOMMISSIONED',
+    SL_VALUES= [
+        ("SL_UNKNOWN", 0x0000, 0x00ff),
+        ("SL_ASSEMBLY_AND_TEST", 0x1000, 0x10ff),
+        ("SL_PSA_ROT_PROVISIONING", 0x2000, 0x20ff),
+        ("SL_SECURED", 0x3000, 0x30ff),
+        ("SL_NON_PSA_ROT_DEBUG", 0x4000, 0x40ff),
+        ("SL_RECOVERABLE_PSA_ROT_DEBUG", 0x5000, 0x50ff),
+        ("SL_DECOMMISSIONED", 0x6000, 0x60ff),
     ]
 
-    # Security Lifecycle claims
-    SL_UNKNOWN = 0x1000
-    SL_PSA_ROT_PROVISIONING = 0x2000
-    SL_SECURED = 0x3000
-    SL_NON_PSA_ROT_DEBUG = 0x4000
-    SL_RECOVERABLE_PSA_ROT_DEBUG = 0x5000
-    SL_PSA_LIFECYCLE_DECOMMISSIONED = 0x6000
-
     def get_claim_key(self=None):
         return ARM_RANGE - 2
 
     def get_claim_name(self=None):
         return 'SECURITY_LIFECYCLE'
 
-    def verify(self, token_item):
-        self._check_type('SECURITY_LIFECYCLE', token_item.value, int)
-
-    @classmethod
-    def parse_raw(cls, raw_value):
-        name_idx = cls.SL_NAMES.index(raw_value.upper())
-        return (name_idx + 1) << cls.SL_SHIFT
-
-    @classmethod
-    def get_formatted_value(cls, value):
-        return cls.SL_NAMES[(value >> cls.SL_SHIFT) - 1]
-
-
 class ProfileIdClaim(AttestationClaim):
     """Class representing a PSA Attestation Token Profile Definition claim"""
     def get_claim_key(self=None):
diff --git a/iat-verifier/tests/test_verifier.py b/iat-verifier/tests/test_verifier.py
index 8f64be8..2b7fe92 100644
--- a/iat-verifier/tests/test_verifier.py
+++ b/iat-verifier/tests/test_verifier.py
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2024, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -252,7 +252,7 @@
             cose_alg=cose_alg,
             signing_key=signing_key,
             configuration=self.config)).get_token_map()
-        self.assertEqual(iat['SECURITY_LIFECYCLE'], 'SL_SECURED')
+        self.assertEqual(iat['SECURITY_LIFECYCLE'], 'sl_secured_3000')
 
     def test_security_lifecycle_decoding(self):
         """Test security lifecycle decoding"""
@@ -266,4 +266,4 @@
             cose_alg=cose_alg,
             signing_key=signing_key,
             configuration=self.config)).get_token_map()
-        self.assertEqual(iat['SECURITY_LIFECYCLE'], 'SL_SECURED')
+        self.assertEqual(iat['SECURITY_LIFECYCLE'], 'sl_secured_3000')