Skip to content

Commit 693762a

Browse files
authored
fix: cpe validation and standardize tests data (#4014)
fixes #4013
1 parent 812e8de commit 693762a

File tree

4 files changed

+39
-29
lines changed

4 files changed

+39
-29
lines changed

cve_bin_tool/sbom_manager/__init__.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -179,19 +179,29 @@ def get_vendor(self, product: str) -> list:
179179
vendorlist.append("UNKNOWN")
180180
return vendorlist
181181

182-
def is_valid_purl(self, purl_string: str):
182+
def is_valid_string(self, string_type: str, ref_string: str) -> bool:
183183
"""
184-
Validate the PURL string is the correct form.
184+
Validate the PURL, CPE string is the correct form.
185185
186186
Args:
187-
- purl_string (str): Package URL string
187+
- ref_string (str): PURL, CPE strings
188+
- string_type (str): ref_string type. (purl, cpe22 or cpe23)
188189
189190
Returns:
190-
- bool: True if the purl_string parameter is a valid purl string, False otherwise.
191+
- bool: True if the ref_string parameter is a valid purl or cpe string, False otherwise.
191192
192193
"""
193-
purl_pattern = r"^(?P<scheme>.+):(?P<type>.+)/(?P<namespace>.+)/(?P<name>.+)@(?P<version>.+)\??(?P<qualifiers>.*)#?(?P<subpath>.*)$"
194-
return re.match(purl_pattern, purl_string) is not None
194+
string_pattern: str
195+
if string_type == "purl":
196+
string_pattern = r"^(?P<scheme>.+):(?P<type>.+)/(?P<namespace>.+)/(?P<name>.+)@(?P<version>.+)\??(?P<qualifiers>.*)#?(?P<subpath>.*)$"
197+
198+
elif string_type == "cpe23":
199+
string_pattern = r"^cpe:2\.3:[aho\*\-](:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?\!\"#\$%&'\(\)\+,\-\.\/:;<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)|[\*\-]))(:(((\?*|\*?)([a-zA-Z0-9\-\._]|(\\[\\\*\?\!\"#\$%&'\(\)\+,\-\.\/:;<=>@\[\]\^`\{\|}~]))+(\?*|\*?))|[\*\-])){4}"
200+
201+
elif string_type == "cpe22":
202+
string_pattern = r"^[c][pP][eE]:/[AHOaho]?(:[A-Za-z0-9\._\-~%]*){0,6}"
203+
204+
return re.match(string_pattern, ref_string) is not None
195205

196206
def parse_sbom(self) -> [(str, str, str)]:
197207
"""
@@ -271,14 +281,16 @@ def parse_ext_ref(self, ext_ref) -> (str | None, str | None, str | None):
271281
"""
272282
decoded = {}
273283
for ref in ext_ref:
274-
if ref[1] == "cpe23Type":
275-
decoded["cpe23Type"] = self.decode_cpe23(ref[2])
284+
ref_type = ref[1]
285+
ref_string = ref[2]
286+
if ref_type == "cpe23Type" and self.is_valid_string("cpe23", ref_string):
287+
decoded["cpe23Type"] = self.decode_cpe23(ref_string)
276288

277-
elif ref[1] == "cpe22Type":
278-
decoded["cpe22Type"] = self.decode_cpe22(ref[2])
289+
elif ref_type == "cpe22Type" and self.is_valid_string("cpe22", ref_string):
290+
decoded["cpe22Type"] = self.decode_cpe22(ref_string)
279291

280-
elif ref[1] == "purl":
281-
decoded["purl"] = self.decode_purl(ref[2])
292+
elif ref_type == "purl" and self.is_valid_string("purl", ref_string):
293+
decoded["purl"] = self.decode_purl(ref_string)
282294

283295
# No ext-ref matches, return none
284296
return decoded.get(
@@ -298,6 +310,7 @@ def decode_cpe22(self, cpe22) -> (str | None, str | None, str | None):
298310
information extracted from the CPE 2.2 string, or None if the information is incomplete.
299311
300312
"""
313+
301314
cpe = cpe22.split(":")
302315
vendor, product, version = cpe[2], cpe[3], cpe[4]
303316
# Return available data, convert empty fields to None
@@ -315,6 +328,7 @@ def decode_cpe23(self, cpe23) -> (str | None, str | None, str | None):
315328
information extracted from the CPE 2.3 string, or None if the information is incomplete.
316329
317330
"""
331+
318332
cpe = cpe23.split(":")
319333
vendor, product, version = cpe[3], cpe[4], cpe[5]
320334
# Return available data, convert empty fields to None
@@ -335,10 +349,9 @@ def decode_purl(self, purl) -> (str | None, str | None, str | None):
335349
vendor = None # Because the vendor and product identifiers in the purl don't always align
336350
product = None # with the CVE DB, only the version is parsed.
337351
version = None
338-
if self.is_valid_purl(purl):
339-
# Process purl identifier
340-
purl_info = PackageURL.from_string(purl).to_dict()
341-
version = purl_info.get("version")
352+
# Process purl identifier
353+
purl_info = PackageURL.from_string(purl).to_dict()
354+
version = purl_info.get("version")
342355

343356
return [vendor or None, product or None, version or None]
344357

test/sbom/cyclonedx_bad_cpe22.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"supplier": {
3636
"name": "ijg"
3737
},
38-
"cpe": "cpe:/a::libjpeg:8b"
38+
"cpe": "cpe:::libjpeg:8b"
3939
},
4040
{
4141
"type": "library",
@@ -45,7 +45,7 @@
4545
"supplier": {
4646
"name": "libexpat project"
4747
},
48-
"cpe": "cpe:/a:libexpat_project::2.0.1"
48+
"cpe": "cpe::libexpat_project::2.0.1"
4949
},
5050
{
5151
"type": "library",
@@ -55,7 +55,7 @@
5555
"supplier": {
5656
"name": "gnu"
5757
},
58-
"cpe": "cpe:/a:gnu:ncurses:"
58+
"cpe": "cpe::gnu:ncurses:"
5959
},
6060
{
6161
"type": "library",

test/sbom/cyclonedx_bad_purl.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
{
3131
"type": "library",
3232
"bom-ref": "2-libjpeg",
33-
"name": "libjpeg",
33+
"name": "libjpeg-novendor",
3434
"version": "8b",
3535
"supplier": {
3636
"name": "ijg"
@@ -50,7 +50,7 @@
5050
{
5151
"type": "library",
5252
"bom-ref": "4-ncurses",
53-
"name": "ncurses",
53+
"name": "ncurses-noversion",
5454
"version": "5.9.noversion",
5555
"supplier": {
5656
"name": "gnu"

test/test_sbom.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,12 @@ class TestSBOM:
4343
]
4444

4545
PARSED_BAD_SBOM_DATA = [
46-
# Unknown vendor has multiple results
47-
ProductInfo(vendor="ijg", product="libjpeg", version="8b"),
48-
ProductInfo(vendor="unknown", product="libjpeg", version="8b"),
49-
ProductInfo(vendor="jpeg", product="libjpeg", version="8b"),
50-
ProductInfo(vendor="libjpeg_project", product="libjpeg", version="8b"),
51-
# Unknown project pulls the product name from the SBOM
46+
ProductInfo(vendor="UNKNOWN", product="libjpeg-novendor", version="8b"),
5247
ProductInfo(vendor="libexpat_project", product="libexpat", version="2.0.1"),
53-
# Unknown version pulls the version number from the SBOM
54-
ProductInfo(vendor="gnu", product="ncurses", version="5.9.noversion"),
48+
ProductInfo(
49+
vendor="UNKNOWN", product="ncurses-noversion", version="5.9.noversion"
50+
),
51+
ProductInfo(vendor="zlib", product="zlib", version="1.2.3"),
5552
]
5653
PARSED_EXT_REF_PRIORITY_SBOM_DATA = [
5754
ProductInfo(vendor="ijg", product="libjpeg", version="8b"),

0 commit comments

Comments
 (0)