summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorSalvatore Bonaccorso <carnil@debian.org>2019-10-20 21:21:14 +0200
committerSalvatore Bonaccorso <carnil@debian.org>2019-10-20 22:27:01 +0200
commit966aef0927e2972109ad935b4eb0c65b35d20d43 (patch)
tree453fde1aa4826818bfdc4785357afb3c5a8a9877 /lib
parentce06805d530f6cb1e65c711dd34d7de9e177b5ac (diff)
Reimplement (incompletely) simplistic NVD parser to handle JSON feed
The reimplementation is focused on only the functionality actually strictly required by the security-tracker. This includes fetching the CVE id and corresponding description. All of specific imapct metrics (severity, range, loss attributes) are not implemented. Those will require a database schema version bump and reimplementation as well for the security_db. Closes: #942670 Signed-off-by: Salvatore Bonaccorso <carnil@debian.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/python/nvd.py127
1 files changed, 59 insertions, 68 deletions
diff --git a/lib/python/nvd.py b/lib/python/nvd.py
index 185bfd6559..f53b2f94ac 100644
--- a/lib/python/nvd.py
+++ b/lib/python/nvd.py
@@ -1,82 +1,81 @@
# nvd.py -- simplistic NVD parser
# Copyright (C) 2005 Florian Weimer <fw@deneb.enyo.de>
-#
+# Copyright (C) 2019 Salvatore Bonaccorso <carnil@debian.org>
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-"""This module parses the XML files provided by the
+"""This module parses the JSON files provided by the
National Vulnerability Database (NVD) <https://nvd.nist.gov/>
"""
-import xml.sax
-import xml.sax.handler
+import json
-class _Parser(xml.sax.handler.ContentHandler):
+class _Parser:
"""Parser helper class."""
def __init__(self):
self.result = []
- self.start_dispatcher = {}
- for x in ('entry', 'local', 'network', 'local_network', 'user_init',
- 'avail', 'conf', 'int', 'sec_prot'):
- self.start_dispatcher[x] = getattr(self, 'TAG_' + x)
- self.path = []
-
- def _noop(*args):
- pass
-
- def startElement(self, name, attrs):
- self.path.append((name, attrs))
- self.start_dispatcher.get(name, self._noop)(name, attrs)
-
- def TAG_entry(self, name, attrs):
- self.name = attrs['name'].encode('utf-8')
- self.published = attrs['published'].encode('utf-8')
- self.severity = attrs.get('severity', u'').encode('utf-8')
- self.discovered = attrs.get('discovered', u'').encode('utf-8')
-
- self.cve_desc = ""
- self.range_local = self.range_remote = self.range_user_init = 0
-
- self.loss_avail = self.loss_conf = self.loss_int \
- = self.loss_sec_prot_user = self.loss_sec_prot_admin \
- = self.loss_sec_prot_other = 0
-
- def TAG_local(self, name, attrs):
- self.range_local = 1
- def TAG_network(self, name, attrs):
- self.range_remote = 1
- def TAG_local_network(self, name, attrs):
- self.range_remote = 1
- def TAG_user_init(self, name, attrs):
- self.range_user_init = 1
- def TAG_avail(self, name, attrs):
- self.loss_avail = 1
- def TAG_conf(self, name, attrs):
- self.loss_conf = 1
- def TAG_int(self, name, attrs):
- self.loss_int = 1
- def TAG_sec_prot(self, name, attrs):
- if 'user' in attrs:
- self.loss_sec_prot_user = 1
- if 'admin' in attrs:
- self.loss_sec_prot_admin = 1
- if 'other' in attrs:
- self.loss_sec_prot_other = 1
-
- def endElement(self, name):
- if name == 'entry':
+
+ def parse(self, file):
+ cve_data=json.load(file)
+
+ for entry in cve_data['CVE_Items']:
+ # get CVE ID name
+ if 'cve' not in entry:
+ raise ValueError("No CVE entry present in CVE_Items")
+ if 'CVE_data_meta' not in entry['cve']:
+ raise ValueError("No CVE metadata entry present")
+ if 'ID' not in entry['cve']['CVE_data_meta']:
+ raise VAlueError("No CVE ID present for entry")
+ self.name=entry['cve']['CVE_data_meta']['ID']
+
+ # get CVE description
+ self.cve_desc=""
+ try:
+ self.cve_desc=entry['cve']['description']['description_data'][0].get('value')
+ except KeyError:
+ pass
+
+ # get discovered date
+ # TODO: re-implement or change database schema
+ self.discovered=""
+
+ # get publication date
+ self.published=""
+ try:
+ self.published=entry.get('publishedDate')
+ except KeyError:
+ pass
+
+ # get severity
+ self.severity=""
+ try:
+ self.severity=entry['impact']['baseMetricV2'].get('severity')
+ except KeyError:
+ pass
+
+ # initalize defaults
+ self.range_local = self.range_remote = self.range_user_init = 0
+
+ self.loss_avail = self.loss_conf = self.loss_int \
+ = self.loss_sec_prot_user = self.loss_sec_prot_admin \
+ = self.loss_sec_prot_other = 0
+
+ # get range and loss values
+ # TODO: re-implement or change database schema
+
self.result.append((self.name,
self.cve_desc,
self.discovered,
@@ -91,12 +90,6 @@ class _Parser(xml.sax.handler.ContentHandler):
self.loss_sec_prot_user,
self.loss_sec_prot_admin,
self.loss_sec_prot_other))
- del self.path[-1]
-
- def characters(self, content):
- (name, attrs) = self.path[-1]
- if name == 'descript' and attrs['source'] == 'cve':
- self.cve_desc += content
def parse(file):
"""Parses the indicated file object. Returns a list of tuples,
@@ -116,14 +109,12 @@ def parse(file):
- security protection (admin) loss type flag
- security protection (other) loss type flag
"""
- parser = xml.sax.make_parser()
- parser.setFeature(xml.sax.handler.feature_namespaces, 0)
+
p = _Parser()
- parser.setContentHandler(p)
- parser.parse(file)
+ p.parse(file)
return p.result
-if __name__ == "__main__":
+if __name__ == '__main__':
import sys
for name in sys.argv[1:]:
parse(open(name))

© 2014-2024 Faster IT GmbH | imprint | privacy policy