From: Stefano Tondo <[email protected]> CPE 2.3 formatted string binding (cpe:2.3:...) requires backslash escaping for special meta-characters according to NISTIR 7695. Characters like '++' and ':' in product names must be properly escaped to pass SBOM validation.
The CPE 2.3 specification defines two bindings: - URI binding (cpe:/...) uses percent-encoding - Formatted string binding (cpe:2.3:...) uses backslash escaping This patch implements the formatted string binding properly by escaping only the required meta-characters with backslash: - Backslash (\) -> \\ - Question mark (?) -> \? - Asterisk (*) -> \* - Colon (:) -> \: - Plus (+) -> \+ (required by some SBOM validators) All other characters including -, etc. are kept as-is without encoding. Example CPE identifiers: - cpe:2.3:*:*:crow:1.0+x:*:*:*:*:*:*:* - cpe:2.3:*:*:sdbus-c++:2.2.1:*:*:*:*:*:*:* Signed-off-by: Stefano Tondo <[email protected]> --- meta/lib/oe/cve_check.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/meta/lib/oe/cve_check.py b/meta/lib/oe/cve_check.py index ae194f27cf..fa210e2037 100644 --- a/meta/lib/oe/cve_check.py +++ b/meta/lib/oe/cve_check.py @@ -205,6 +205,34 @@ def get_patched_cves(d): return patched_cves +def cpe_escape(value): + r""" + Escape special characters for CPE 2.3 formatted string binding. + + CPE 2.3 formatted string binding (cpe:2.3:...) uses backslash escaping + for special meta-characters, NOT percent-encoding. Percent-encoding is + only used in the URI binding (cpe:/...). + + According to NISTIR 7695, these characters need escaping: + - Backslash (\) -> \\ + - Question mark (?) -> \? + - Asterisk (*) -> \* + - Colon (:) -> \: + - Plus (+) -> \+ (required by some SBOM validators) + """ + if not value: + return value + + # Escape special meta-characters for CPE 2.3 formatted string binding + # Order matters: escape backslash first to avoid double-escaping + result = value.replace('\\', '\\\\') + result = result.replace('?', '\\?') + result = result.replace('*', '\\*') + result = result.replace(':', '\\:') + result = result.replace('+', '\\+') + + return result + def get_cpe_ids(cve_product, version): """ Get list of CPE identifiers for the given product and version @@ -221,7 +249,14 @@ def get_cpe_ids(cve_product, version): else: vendor = "*" - cpe_id = 'cpe:2.3:*:{}:{}:{}:*:*:*:*:*:*:*'.format(vendor, product, version) + # Encode special characters per CPE 2.3 specification + encoded_vendor = cpe_escape(vendor) if vendor != "*" else vendor + encoded_product = cpe_escape(product) + encoded_version = cpe_escape(version) + + cpe_id = 'cpe:2.3:*:{}:{}:{}:*:*:*:*:*:*:*'.format( + encoded_vendor, encoded_product, encoded_version + ) cpe_ids.append(cpe_id) return cpe_ids -- 2.53.0
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#231594): https://lists.openembedded.org/g/openembedded-core/message/231594 Mute This Topic: https://lists.openembedded.org/mt/117922746/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
