Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 39 additions & 12 deletions cyclonedx/model/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,10 @@ class AlgorithmProperties:
def __init__(
self, *,
primitive: Optional[CryptoPrimitive] = None,
algorithm_family: Optional[str] = None,
parameter_set_identifier: Optional[str] = None,
curve: Optional[str] = None,
elliptic_curve: Optional[str] = None,
execution_environment: Optional[CryptoExecutionEnvironment] = None,
implementation_platform: Optional[CryptoImplementationPlatform] = None,
certification_levels: Optional[Iterable[CryptoCertificationLevel]] = None,
Expand All @@ -356,8 +358,10 @@ def __init__(
nist_quantum_security_level: Optional[int] = None,
) -> None:
self.primitive = primitive
self.algorithm_family = algorithm_family
self.parameter_set_identifier = parameter_set_identifier
self.curve = curve
self.elliptic_curve = elliptic_curve
self.execution_environment = execution_environment
self.implementation_platform = implementation_platform
self.certification_levels = certification_levels or []
Expand Down Expand Up @@ -392,7 +396,18 @@ def primitive(self, primitive: Optional[CryptoPrimitive]) -> None:
self._primitive = primitive

@property
@serializable.view(SchemaVersion1Dot7)
@serializable.xml_sequence(2)
def algorithm_family(self) -> Optional[str]:
"""The standardized family identifier for the algorithm."""
return self._algorithm_family

@algorithm_family.setter
def algorithm_family(self, algorithm_family: Optional[str]) -> None:
self._algorithm_family = algorithm_family

@property
@serializable.xml_sequence(3)
def parameter_set_identifier(self) -> Optional[str]:
"""
An identifier for the parameter set of the cryptographic algorithm. Examples: in AES128, '128' identifies the
Expand All @@ -409,7 +424,7 @@ def parameter_set_identifier(self, parameter_set_identifier: Optional[str]) -> N
self._parameter_set_identifier = parameter_set_identifier

@property
@serializable.xml_sequence(3)
@serializable.xml_sequence(4)
def curve(self) -> Optional[str]:
"""
The specific underlying Elliptic Curve (EC) definition employed which is an indicator of the level of security
Expand All @@ -427,7 +442,18 @@ def curve(self, curve: Optional[str]) -> None:
self._curve = curve

@property
@serializable.xml_sequence(4)
@serializable.view(SchemaVersion1Dot7)
@serializable.xml_sequence(5)
def elliptic_curve(self) -> Optional[str]:
"""The standardized identifier of the elliptic curve used by the algorithm."""
return self._elliptic_curve

@elliptic_curve.setter
def elliptic_curve(self, elliptic_curve: Optional[str]) -> None:
self._elliptic_curve = elliptic_curve

@property
@serializable.xml_sequence(6)
def execution_environment(self) -> Optional[CryptoExecutionEnvironment]:
"""
The target and execution environment in which the algorithm is implemented in.
Expand All @@ -442,7 +468,7 @@ def execution_environment(self, execution_environment: Optional[CryptoExecutionE
self._execution_environment = execution_environment

@property
@serializable.xml_sequence(4)
@serializable.xml_sequence(7)
def implementation_platform(self) -> Optional[CryptoImplementationPlatform]:
"""
The target platform for which the algorithm is implemented. The implementation can be 'generic', running on
Expand All @@ -462,7 +488,7 @@ def implementation_platform(self, implementation_platform: Optional[CryptoImplem
@serializable.view(SchemaVersion1Dot6)
@serializable.view(SchemaVersion1Dot7)
@serializable.xml_array(serializable.XmlArraySerializationType.FLAT, child_name='certificationLevel')
@serializable.xml_sequence(5)
@serializable.xml_sequence(8)
def certification_levels(self) -> 'SortedSet[CryptoCertificationLevel]':
"""
The certification that the implementation of the cryptographic algorithm has received, if any. Certifications
Expand All @@ -478,7 +504,7 @@ def certification_levels(self, certification_levels: Iterable[CryptoCertificatio
self._certification_levels = SortedSet(certification_levels)

@property
@serializable.xml_sequence(6)
@serializable.xml_sequence(9)
def mode(self) -> Optional[CryptoMode]:
"""
The mode of operation in which the cryptographic algorithm (block cipher) is used.
Expand All @@ -493,7 +519,7 @@ def mode(self, mode: Optional[CryptoMode]) -> None:
self._mode = mode

@property
@serializable.xml_sequence(8)
@serializable.xml_sequence(10)
def padding(self) -> Optional[CryptoPadding]:
"""
The padding scheme that is used for the cryptographic algorithm.
Expand All @@ -509,7 +535,7 @@ def padding(self, padding: Optional[CryptoPadding]) -> None:

@property
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, child_name='cryptoFunction')
@serializable.xml_sequence(9)
@serializable.xml_sequence(11)
def crypto_functions(self) -> 'SortedSet[CryptoFunction]':
"""
The cryptographic functions implemented by the cryptographic algorithm.
Expand All @@ -524,7 +550,7 @@ def crypto_functions(self, crypto_functions: Iterable[CryptoFunction]) -> None:
self._crypto_functions = SortedSet(crypto_functions)

@property
@serializable.xml_sequence(10)
@serializable.xml_sequence(12)
def classical_security_level(self) -> Optional[int]:
"""
The classical security level that a cryptographic algorithm provides (in bits).
Expand All @@ -539,7 +565,7 @@ def classical_security_level(self, classical_security_level: Optional[int]) -> N
self._classical_security_level = classical_security_level

@property
@serializable.xml_sequence(11)
@serializable.xml_sequence(13)
def nist_quantum_security_level(self) -> Optional[int]:
"""
The NIST security strength category as defined in
Expand All @@ -564,9 +590,10 @@ def nist_quantum_security_level(self, nist_quantum_security_level: Optional[int]

def __comparable_tuple(self) -> _ComparableTuple:
return _ComparableTuple((
self.primitive, self._parameter_set_identifier, self.curve, self.execution_environment,
self.implementation_platform, _ComparableTuple(self.certification_levels), self.mode, self.padding,
_ComparableTuple(self.crypto_functions), self.classical_security_level, self.nist_quantum_security_level,
self.primitive, self.algorithm_family, self.parameter_set_identifier, self.curve, self.elliptic_curve,
self.execution_environment, self.implementation_platform, _ComparableTuple(self.certification_levels),
self.mode, self.padding, _ComparableTuple(self.crypto_functions), self.classical_security_level,
self.nist_quantum_security_level,
))

def __eq__(self, other: object) -> bool:
Expand Down
2 changes: 2 additions & 0 deletions tests/_data/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ def get_crypto_properties_algorithm() -> CryptoProperties:
asset_type=CryptoAssetType.ALGORITHM,
algorithm_properties=AlgorithmProperties(
primitive=CryptoPrimitive.KEM,
algorithm_family='ML-KEM',
parameter_set_identifier='a-parameter-set-id',
curve='9n8y2oxty3ao83n8qc2g2x3qcw4jt4wj',
elliptic_curve='nist/P-256',
execution_environment=CryptoExecutionEnvironment.SOFTWARE_PLAIN_RAM,
implementation_platform=CryptoImplementationPlatform.GENERIC,
certification_levels=[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"bom-ref": "8182921e-0588-472e-b8f9-9c527c68f067",
"cryptoProperties": {
"algorithmProperties": {
"algorithmFamily": "ML-KEM",
"certificationLevel": [
"fips140-1-l1",
"fips140-2-l3",
Expand All @@ -15,6 +16,7 @@
"unknown"
],
"curve": "9n8y2oxty3ao83n8qc2g2x3qcw4jt4wj",
"ellipticCurve": "nist/P-256",
"executionEnvironment": "software-plain-ram",
"implementationPlatform": "generic",
"mode": "ecb",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
<assetType>algorithm</assetType>
<algorithmProperties>
<primitive>kem</primitive>
<algorithmFamily>ML-KEM</algorithmFamily>
<parameterSetIdentifier>a-parameter-set-id</parameterSetIdentifier>
<curve>9n8y2oxty3ao83n8qc2g2x3qcw4jt4wj</curve>
<ellipticCurve>nist/P-256</ellipticCurve>
<executionEnvironment>software-plain-ram</executionEnvironment>
<implementationPlatform>generic</implementationPlatform>
<certificationLevel>fips140-1-l1</certificationLevel>
Expand Down
21 changes: 21 additions & 0 deletions tests/test_model_crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OWASP Foundation. All Rights Reserved.

from json import loads as json_loads
from unittest import TestCase

from cyclonedx.model.bom_ref import BomRef
Expand All @@ -29,6 +30,7 @@
RelatedCryptoMaterialSecuredBy,
RelatedCryptoMaterialType,
)
from cyclonedx.schema.schema import SchemaVersion1Dot6, SchemaVersion1Dot7


class TestModelAlgorithmProperties(TestCase):
Expand Down Expand Up @@ -134,3 +136,22 @@ def test_protocol_properties_sorting(self) -> None:
proto_list = [proto3, proto1, proto2]
sorted_protos = sorted(proto_list)
self.assertEqual(len(sorted_protos), 3)


class TestModelAlgorithmPropertiesV17(TestCase):

def test_new_algorithm_identifiers_and_legacy_curve(self) -> None:
properties = AlgorithmProperties(
algorithm_family='AES',
curve='legacy-curve',
elliptic_curve='nist/P-256',
)
data_1_7 = json_loads(properties.as_json(view_=SchemaVersion1Dot7))
self.assertEqual('AES', data_1_7['algorithmFamily'])
self.assertEqual('nist/P-256', data_1_7['ellipticCurve'])
self.assertEqual('legacy-curve', data_1_7['curve'])

data_1_6 = json_loads(properties.as_json(view_=SchemaVersion1Dot6))
self.assertNotIn('algorithmFamily', data_1_6)
self.assertNotIn('ellipticCurve', data_1_6)
self.assertEqual('legacy-curve', data_1_6['curve'])