diff --git a/cyclonedx/model/crypto.py b/cyclonedx/model/crypto.py index a3d32d0e..46dbf46d 100644 --- a/cyclonedx/model/crypto.py +++ b/cyclonedx/model/crypto.py @@ -78,16 +78,69 @@ class CryptoPrimitive(str, Enum): KDF = 'kdf' KEM = 'kem' KEY_AGREE = 'key-agree' + KEY_WRAP = 'key-wrap' # since CDX1.7 MAC = 'mac' PKE = 'pke' SIGNATURE = 'signature' STREAM_CIPHER = 'stream-cipher' XOF = 'xof' - + # -- OTHER = 'other' UNKNOWN = 'unknown' +class _CryptoPrimitiveSerializationHelper(serializable.helpers.BaseHelper): + """ THIS CLASS IS NON-PUBLIC API """ + + __CASES: dict[type[serializable.ViewType], frozenset[CryptoPrimitive]] = dict() + __CASES[SchemaVersion1Dot6] = frozenset({ + CryptoPrimitive.AE, + CryptoPrimitive.BLOCK_CIPHER, + CryptoPrimitive.COMBINER, + CryptoPrimitive.DRBG, + CryptoPrimitive.HASH, + CryptoPrimitive.KDF, + CryptoPrimitive.KEM, + CryptoPrimitive.KEY_AGREE, + CryptoPrimitive.MAC, + CryptoPrimitive.PKE, + CryptoPrimitive.SIGNATURE, + CryptoPrimitive.STREAM_CIPHER, + CryptoPrimitive.XOF, + CryptoPrimitive.OTHER, + CryptoPrimitive.UNKNOWN, + }) + __CASES[SchemaVersion1Dot7] = __CASES[SchemaVersion1Dot6] | { + CryptoPrimitive.KEY_WRAP, + } + + @classmethod + def __normalize(cls, cp: CryptoPrimitive, view: type[serializable.ViewType]) -> str: + return ( + cp + if cp in cls.__CASES.get(view, ()) + else CryptoPrimitive.OTHER + ).value + + @classmethod + def json_normalize(cls, o: Any, *, + view: Optional[type[serializable.ViewType]], + **__: Any) -> str: + assert view is not None + return cls.__normalize(o, view) + + @classmethod + def xml_normalize(cls, o: Any, *, + view: Optional[type[serializable.ViewType]], + **__: Any) -> str: + assert view is not None + return cls.__normalize(o, view) + + @classmethod + def deserialize(cls, o: Any) -> CryptoPrimitive: + return CryptoPrimitive(o) + + @serializable.serializable_enum class CryptoExecutionEnvironment(str, Enum): """ @@ -303,6 +356,7 @@ def __init__( self.nist_quantum_security_level = nist_quantum_security_level @property + @serializable.type_mapping(_CryptoPrimitiveSerializationHelper) @serializable.xml_sequence(1) def primitive(self) -> Optional[CryptoPrimitive]: """