[PATCH 41 of 54] Add a CPE parser (and tests)
Wald Commits
scm-commit at wald.intevation.org
Wed Jan 7 10:56:58 CET 2015
# HG changeset patch
# User Benoît Allard <benoit.allard at greenbone.net>
# Date 1419859839 -3600
# Node ID 1d9b2b06067eb9bd9c400e2028f33f3c56dc6772
# Parent ba0eb65d413495f7c86594c9913bb9012e5934b1
Add a CPE parser (and tests)
diff -r ba0eb65d4134 -r 1d9b2b06067e farolluz/parsers/cpe.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/parsers/cpe.py Mon Dec 29 14:30:39 2014 +0100
@@ -0,0 +1,259 @@
+"""\
+a cpe class to ease the creation of a producttree based on cpe
+
+This is based on:
+
+ NIST Interagency Report 7695
+ Common Platform Enumeration: Naming Specification Version 2.3
+
+CPE is a trademark of The MITRE Corporation.
+
+"""
+
+import re
+
+PCT_MAP ={'!': "%21", '"': "%22", '#': "%23", '$': "%24", '%': "%25", '&': "%26",
+ "'": "%27", '(': "%28", ')': "%29", '*': "%2a", '+': "%2b", ',': "%2c",
+ '/': "%2f", ':': "%3a", ';': "%3b", '<': "%3c", "=": "%3d", '>': "%3e",
+ '?': "%3f", '@': "%40", '[': "%5b", '\\': "%5c","]": "%5d", '^': "%5e",
+ '`': "%60", '{': "%7b", '|': "%7c", '}': "%7d", "~": "%7e"}
+
+PCT_MAP_i = dict((v, k) for k, v in PCT_MAP.iteritems())
+
+def pct_encode(c):
+ """ Returns the right percent-encoding of c """
+ if c in "-.":
+ return c
+ return PCT_MAP[c]
+ return {'!': "%21", '"': "%22", '#': "%23", '$': "%24", '%': "%25", '&': "%26",
+ "'": "%27", '(': "%28", ')': "%29", '*': "%2a", '+': "%2b", ',': "%2c",
+ "-": c, '.': c, '/': "%2f", ':': "%3a", ';': "%3b", '<': "%3c",
+ "=": "%3d", '>': "%3e", '?': "%3f", '@': "%40", '[': "%5b", '\\': "%5c",
+ "]": "%5d", '^': "%5e", '`': "%60", '{': "%7b", '|': "%7c", '}': "%7d",
+ "~": "%7e"}[c]
+
+def decode(s):
+ if s == '':
+ return ANY
+ if s == '-':
+ return NA
+ s = s.lower()
+ res = ""
+ idx = 0
+ embedded = False
+ while idx < len(s):
+ c = s[idx]
+ if c in ".-~":
+ res += "\\" + c
+ embedded = True
+ elif c != '%':
+ res += c
+ embedded = True
+ else:
+ form = s[idx:idx+3]
+ if form == "%01":
+ if (((idx == 0) or (idx == (len(s) - 3))) or
+ ( not embedded and (s[idx-4:idx-1] == "%01")) or
+ (embedded and (len(s) > idx + 6) and (s[idx+3:idx+6] == "%01"))):
+ res += '?'
+ else:
+ raise ValueError
+ elif form == "%02":
+ if (idx == 0) or (idx == len(s) - 3):
+ res += '*'
+ else:
+ raise ValueError
+ else:
+ res += '\\' + PCT_MAP_i[form]
+ embedded = True
+ idx += 2
+ idx += 1
+ return CPEAttribute(res)
+
+def unbind_value_fs(s):
+ if s == '*':
+ return ANY
+ if s == '-':
+ return NA
+ res = ""
+ idx = 0
+ embedded = False
+ while idx < len(s):
+ c = s[idx]
+ if re.match("[a-zA-Z0-9_]", c) is not None:
+ res += c
+ embedded = True
+ elif c == "\\":
+ res += s[idx:idx+2]
+ embedded = True
+ idx += 1
+ elif c == "*":
+ if (idx == 0) or (idx == (len(s) - 1)):
+ res += c
+ embedded = True
+ else:
+ raise ValueError
+ elif c == "?":
+ if (((idx == 0) or (idx == (len(s) - 1))) or
+ (not embedded and (s[idx - 1] == "?")) or
+ (embedded and (s[idx + 1] == "?"))):
+ res += c
+ embedded = False
+ else:
+ raise ValueError
+ else:
+ res += "\\" + c
+ embedded = True
+ idx += 1
+ return CPEAttribute(res)
+
+class CPEAttribute(object):
+ """ We need a special class to deal with ANY / NA / "string" """
+
+ def __init__(self, value=None, any=False, na=False):
+ self.any = any
+ self.na = na
+ self.value = value
+
+ def bind_for_URI(self):
+# print self.any, self.na, self.value
+ if self.any:
+ return ""
+ if self.na:
+ return '-'
+ return self.transform_for_uri()
+
+ def transform_for_uri(self):
+ res = ""
+ idx = 0
+ while idx < len(self.value):
+ c = self.value[idx]
+ if re.match("[a-zA-Z0-9_]", c) is not None:
+ res += c
+ elif c == '\\':
+ idx += 1
+ c = self.value[idx]
+ res += pct_encode(c)
+ elif c == '?':
+ res += "%01"
+ elif c == '*':
+ res += "%02"
+ idx += 1
+ return res
+
+ def bind_for_fs(self):
+ if self.any:
+ return "*"
+ if self.na:
+ return "-"
+ return self.process_quoted_chars()
+
+ def process_quoted_chars(self):
+ res = ""
+ idx = 0
+ while idx < len(self.value):
+ c = self.value[idx]
+ if c != '\\':
+ res += c
+ else:
+ idx += 1
+ c = self.value[idx]
+ if c in ".-_":
+ res += c
+ else:
+ res += '\\' + c
+ idx += 1
+ return res
+
+ANY = CPEAttribute(any=True)
+NA = CPEAttribute(na=True)
+
+class CPE(object):
+
+ def __init__(self, part=None, vendor=None, product=None, version=None, update=None, edition=None, language=None, sw_edition=None, target_sw=None, target_hw=None, other=None):
+ self.part = part or CPEAttribute(any=True)
+ self.vendor = vendor or CPEAttribute(any=True)
+ self.product = product or CPEAttribute(any=True)
+ self.version = version or CPEAttribute(any=True)
+ self.update = update or CPEAttribute(any=True)
+ self.edition = edition or CPEAttribute(any=True)
+ self.language = language or CPEAttribute(any=True)
+ # Extended attributes:
+ self.sw_edition = sw_edition or CPEAttribute(any=True)
+ self.target_sw = target_sw or CPEAttribute(any=True)
+ self.target_hw = target_hw or CPEAttribute(any=True)
+ self.other = other or CPEAttribute(any=True)
+
+ def bind_to_URI(self):
+ uri = 'cpe:/'
+ uri += ':'.join(a.bind_for_URI() for a in (self.part, self.vendor, self.product, self.version, self.update))
+ # Special handling for edition
+ ed = self.edition.bind_for_URI()
+ sw_ed = self.sw_edition.bind_for_URI()
+ t_sw = self.target_sw.bind_for_URI()
+ t_hw = self.target_hw.bind_for_URI()
+ oth = self.other.bind_for_URI()
+ if sw_ed == "" and t_sw == "" and t_hw == "" and oth == "":
+ uri += ":" + ed
+ else:
+ uri += ":~" + '~'.join([ed, sw_ed, t_sw, t_hw, oth])
+ uri += ':' + self.language.bind_for_URI()
+ return uri.rstrip(':')
+
+ def unbind_URI(self, uri):
+ for idx, comp in enumerate(uri.split(':')):
+ if idx == 0:
+ continue
+ elif idx == 1:
+ self.part = decode(comp[1:])
+ elif idx == 2:
+ self.vendor = decode(comp)
+ elif idx == 3:
+ self.product = decode(comp)
+ elif idx == 4:
+ self.version = decode(comp)
+ elif idx == 5:
+ self.update = decode(comp)
+ elif idx == 6:
+ if comp == "" or comp[0] != '~':
+ self.edition = decode(comp)
+ else:
+ ed, sw_ed, t_sw, t_hw, oth = comp[1:].split('~')
+ self.edition = decode(ed)
+ self.sw_edition = decode(sw_ed)
+ self.target_sw = decode(t_sw)
+ self.target_hw = decode(t_hw)
+ self.other = decode(oth)
+ elif idx == 7:
+ self.language = decode(comp)
+
+ def bind_to_fs(self):
+ fs = 'cpe:2.3:'
+ fs += ':'.join(a.bind_for_fs() for a in (self.part, self.vendor, self.product, self.version, self.update, self.edition, self.language, self.sw_edition, self.target_sw, self.target_hw, self.other))
+ return fs
+
+ def unbind_fs(self, fs):
+ for idx, v in enumerate(fs.split(':')):
+ v = unbind_value_fs(v)
+ if idx == 2:
+ self.part = v
+ elif idx == 3:
+ self.vendor = v
+ elif idx == 4:
+ self.product = v
+ elif idx == 5:
+ self.version = v
+ elif idx == 6:
+ self.update = v
+ elif idx == 7:
+ self.edition = v
+ elif idx == 8:
+ self.language = v
+ elif idx == 9:
+ self.sw_edition = v
+ elif idx == 10:
+ self.target_sw = v
+ elif idx == 11:
+ self.target_hw = v
+ elif idx == 12:
+ self.other = v
diff -r ba0eb65d4134 -r 1d9b2b06067e tests/testCPE.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/testCPE.py Mon Dec 29 14:30:39 2014 +0100
@@ -0,0 +1,212 @@
+import unittest
+
+from farolluz.parsers.cpe import CPE, CPEAttribute
+
+class testbindToURI(unittest.TestCase):
+
+ def test_example1(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('microsoft'), product=CPEAttribute('internet_explorer'), version=CPEAttribute(r'8\.0\.6001'), update=CPEAttribute('beta'), edition=CPEAttribute(any=True))
+
+ self.assertEqual(cpe.bind_to_URI(), 'cpe:/a:microsoft:internet_explorer:8.0.6001:beta')
+
+ def test_example2(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('microsoft'), product=CPEAttribute('internet_explorer'), version=CPEAttribute(r'8\.*'), update=CPEAttribute('sp?'))
+
+ self.assertEqual(cpe.bind_to_URI(), 'cpe:/a:microsoft:internet_explorer:8.%02:sp%01')
+
+ def test_example3(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('hp'), product=CPEAttribute('insight_diagnostics'), version=CPEAttribute(r'7\.4\.0\.1570'), update=CPEAttribute(na=True), sw_edition=CPEAttribute('online'), target_sw=CPEAttribute('win2003'), target_hw=CPEAttribute("x64"))
+
+ self.assertEqual(cpe.bind_to_URI(), 'cpe:/a:hp:insight_diagnostics:7.4.0.1570:-:~~online~win2003~x64~')
+
+ def test_example4(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('hp'), product=CPEAttribute('openview_network_manager'), version=CPEAttribute(r'7\.51'), target_sw=CPEAttribute('linux'))
+
+ self.assertEqual(cpe.bind_to_URI(), 'cpe:/a:hp:openview_network_manager:7.51::~~~linux~~')
+
+ def test_example5(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute(r'foo\\bar'), product=CPEAttribute(r'big\$money_manager_2010'), sw_edition=CPEAttribute('special'), target_sw=CPEAttribute('ipod_touch'), target_hw=CPEAttribute("80gb"))
+
+ self.assertEqual(cpe.bind_to_URI(), 'cpe:/a:foo%5cbar:big%24money_manager_2010:::~~special~ipod_touch~80gb~')
+
+class testunbindURI(unittest.TestCase):
+
+ def test_example1(self):
+ cpe = CPE()
+ cpe.unbind_URI('cpe:/a:microsoft:internet_explorer:8.0.6001:beta')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'microsoft')
+ self.assertEqual(cpe.product.value, 'internet_explorer')
+ self.assertEqual(cpe.version.value, r'8\.0\.6001')
+ self.assertEqual(cpe.update.value, 'beta')
+ self.assertTrue(cpe.edition.any)
+ self.assertTrue(cpe.language.any)
+
+ def test_example2(self):
+ cpe = CPE()
+ cpe.unbind_URI('cpe:/a:microsoft:internet_explorer:8.%2a:sp%3f')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'microsoft')
+ self.assertEqual(cpe.product.value, 'internet_explorer')
+ self.assertEqual(cpe.version.value, r'8\.\*')
+ self.assertEqual(cpe.update.value, 'sp\?')
+ self.assertTrue(cpe.edition.any)
+ self.assertTrue(cpe.language.any)
+
+ def test_example3(self):
+ cpe = CPE()
+ cpe.unbind_URI('cpe:/a:microsoft:internet_explorer:8.%02:sp%01')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'microsoft')
+ self.assertEqual(cpe.product.value, 'internet_explorer')
+ self.assertEqual(cpe.version.value, r'8\.*')
+ self.assertEqual(cpe.update.value, 'sp?')
+ self.assertTrue(cpe.edition.any)
+ self.assertTrue(cpe.language.any)
+
+ def test_example4(self):
+ cpe = CPE()
+ cpe.unbind_URI('cpe:/a:hp:insight_diagnostics:7.4.0.1570::~~online~win2003~x64~')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'hp')
+ self.assertEqual(cpe.product.value, 'insight_diagnostics')
+ self.assertEqual(cpe.version.value, '7\.4\.0\.1570')
+ self.assertTrue(cpe.update.any)
+ self.assertTrue(cpe.edition.any)
+ self.assertEqual(cpe.sw_edition.value, 'online')
+ self.assertEqual(cpe.target_sw.value, 'win2003')
+ self.assertEqual(cpe.target_hw.value, 'x64')
+ self.assertTrue(cpe.other.any)
+ self.assertTrue(cpe.language.any)
+
+ def test_example5(self):
+ cpe = CPE()
+ cpe.unbind_URI('cpe:/a:hp:openview_network_manager:7.51:-:~~~linux~~')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'hp')
+ self.assertEqual(cpe.product.value, 'openview_network_manager')
+ self.assertEqual(cpe.version.value, '7\.51')
+ self.assertTrue(cpe.update.na)
+ self.assertTrue(cpe.edition.any)
+ self.assertTrue(cpe.sw_edition.any)
+ self.assertEqual(cpe.target_sw.value, 'linux')
+ self.assertTrue(cpe.target_hw.any)
+ self.assertTrue(cpe.other.any)
+ self.assertTrue(cpe.language.any)
+
+
+ def test_example6(self):
+ cpe = CPE()
+ self.assertRaises(KeyError, cpe.unbind_URI, 'cpe:/a:foo%5cbar:big%24money_2010%07:::~~special~ipod_touch~80gb~')
+
+
+ def test_example7(self):
+ cpe = CPE()
+ cpe.unbind_URI('cpe:/a:foo~bar:big%7emoney_2010')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'foo\~bar')
+ self.assertEqual(cpe.product.value, 'big\~money_2010')
+ self.assertTrue(cpe.version.any)
+ self.assertTrue(cpe.update.any)
+ self.assertTrue(cpe.edition.any)
+ self.assertTrue(cpe.language.any)
+
+ def test_example8(self):
+ cpe = CPE()
+ self.assertRaises(ValueError, cpe.unbind_URI, 'cpe:/a:foo:bar:12.%02.1234')
+
+class testbindFS(unittest.TestCase):
+
+ def test_example1(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('microsoft'), product=CPEAttribute('internet_explorer'), version=CPEAttribute(r'8\.0\.6001'), update=CPEAttribute('beta'), edition=CPEAttribute(any=True))
+
+ self.assertEqual(cpe.bind_to_fs(), 'cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*')
+
+ def test_example2(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('microsoft'), product=CPEAttribute('internet_explorer'), version=CPEAttribute(r'8\.*'), update=CPEAttribute('sp?'), edition=CPEAttribute(any=True))
+
+ self.assertEqual(cpe.bind_to_fs(), 'cpe:2.3:a:microsoft:internet_explorer:8.*:sp?:*:*:*:*:*:*')
+
+ cpe.version = CPEAttribute(r'8\.\*')
+
+ self.assertEqual(cpe.bind_to_fs(), 'cpe:2.3:a:microsoft:internet_explorer:8.\*:sp?:*:*:*:*:*:*')
+
+ def test_example3(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('hp'), product=CPEAttribute('insight'), version=CPEAttribute(r'7\.4\.0\.1570'), update=CPEAttribute(na=True), sw_edition=CPEAttribute("online"), target_sw=CPEAttribute("win2003"), target_hw=CPEAttribute("x64"))
+
+ self.assertEqual(cpe.bind_to_fs(), 'cpe:2.3:a:hp:insight:7.4.0.1570:-:*:*:online:win2003:x64:*')
+
+ def test_example4(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute('hp'), product=CPEAttribute('openview_network_manager'), version=CPEAttribute(r'7\.51'), target_sw=CPEAttribute('linux'))
+
+ self.assertEqual(cpe.bind_to_fs(), 'cpe:2.3:a:hp:openview_network_manager:7.51:*:*:*:*:linux:*:*')
+
+ def test_example5(self):
+ cpe = CPE(part=CPEAttribute('a'), vendor=CPEAttribute(r'foo\\bar'), product=CPEAttribute(r'big\$money_2010'), sw_edition=CPEAttribute('special'), target_sw=CPEAttribute('ipod_touch'), target_hw=CPEAttribute("80gb"))
+
+ self.assertEqual(cpe.bind_to_fs(), r'cpe:2.3:a:foo\\bar:big\$money_2010:*:*:*:*:special:ipod_touch:80gb:*')
+
+class testunbind_fs(unittest.TestCase):
+
+ def test_example1(self):
+ cpe = CPE()
+ cpe.unbind_fs('cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'microsoft')
+ self.assertEqual(cpe.product.value, 'internet_explorer')
+ self.assertEqual(cpe.version.value, '8\.0\.6001')
+ self.assertEqual(cpe.update.value, "beta")
+ self.assertTrue(cpe.edition.any)
+ self.assertTrue(cpe.sw_edition.any)
+ self.assertTrue(cpe.target_sw.any)
+ self.assertTrue(cpe.target_hw.any)
+ self.assertTrue(cpe.other.any)
+ self.assertTrue(cpe.language.any)
+
+ def test_example2(self):
+ cpe = CPE()
+ cpe.unbind_fs('cpe:2.3:a:microsoft:internet_explorer:8.*:sp?:*:*:*:*:*:*')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'microsoft')
+ self.assertEqual(cpe.product.value, 'internet_explorer')
+ self.assertEqual(cpe.version.value, '8\.*')
+ self.assertEqual(cpe.update.value, "sp?")
+ self.assertTrue(cpe.edition.any)
+ self.assertTrue(cpe.sw_edition.any)
+ self.assertTrue(cpe.target_sw.any)
+ self.assertTrue(cpe.target_hw.any)
+ self.assertTrue(cpe.other.any)
+ self.assertTrue(cpe.language.any)
+
+ def test_example3(self):
+ cpe = CPE()
+ cpe.unbind_fs('cpe:2.3:a:hp:insight_diagnostics:7.4.0.1570:-:*:*:online:win2003:x64:*')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, 'hp')
+ self.assertEqual(cpe.product.value, 'insight_diagnostics')
+ self.assertEqual(cpe.version.value, '7\.4\.0\.1570')
+ self.assertTrue(cpe.update.na)
+ self.assertTrue(cpe.edition.any)
+ self.assertEqual(cpe.sw_edition.value, "online")
+ self.assertEqual(cpe.target_sw.value, "win2003")
+ self.assertEqual(cpe.target_hw.value, "x64")
+ self.assertTrue(cpe.other.any)
+ self.assertTrue(cpe.language.any)
+
+ self.assertRaises(ValueError, cpe.unbind_fs, 'cpe:2.3:a:hp:insight_diagnostics:7.4.*.1570:*:*:*:*:*:*')
+
+
+ def test_example4(self):
+ cpe = CPE()
+ cpe.unbind_fs(r'cpe:2.3:a:foo\\bar:big\$money:2010:*:*:*:special:ipod_touch:80gb:*')
+ self.assertEqual(cpe.part.value, 'a')
+ self.assertEqual(cpe.vendor.value, r'foo\\bar')
+ self.assertEqual(cpe.product.value, 'big\$money')
+ self.assertEqual(cpe.version.value, '2010')
+ self.assertTrue(cpe.update.any)
+ self.assertTrue(cpe.edition.any)
+ self.assertEqual(cpe.sw_edition.value, "special")
+ self.assertEqual(cpe.target_sw.value, "ipod_touch")
+ self.assertEqual(cpe.target_hw.value, "80gb")
+ self.assertTrue(cpe.other.any)
+ self.assertTrue(cpe.language.any)
More information about the Farol-commits
mailing list