aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Legler <alex@a3li.li>2016-06-01 19:56:44 +0200
committerAlex Legler <alex@a3li.li>2016-06-01 19:56:44 +0200
commit1e03a6b7d241a9eaa3f9950613b37d8c100602d1 (patch)
tree9e52b3380bf7ae89cb69c82c11fccaa609063693
parentMark CVE tracker as deprecated (diff)
downloadsecurity-1e03a6b7d241a9eaa3f9950613b37d8c100602d1.tar.gz
security-1e03a6b7d241a9eaa3f9950613b37d8c100602d1.tar.bz2
security-1e03a6b7d241a9eaa3f9950613b37d8c100602d1.zip
Add initial CVETool CLI utility
-rwxr-xr-xbin/cvetool130
1 files changed, 130 insertions, 0 deletions
diff --git a/bin/cvetool b/bin/cvetool
new file mode 100755
index 0000000..8e388e0
--- /dev/null
+++ b/bin/cvetool
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+# Copyright 2016 Alex Legler
+# Distributed under the terms of the GNU General Public License v3
+
+import json
+import re
+import string
+import sys
+import os
+import httplib2
+from base64 import b64encode
+
+URI_BASE = 'https://glsamaker.gentoo.org'
+
+class CVETool:
+ """ Interface to GLSAMaker's CVETool """
+
+ def __init__(self, auth, command, args):
+ self.auth = auth
+
+ if command == 'info':
+ self.info(self.cleanup_cve(sys.argv[2]))
+ elif command == 'assign':
+ if len(args) < 2:
+ print('Usage: assign <bug> <CVE> [<CVE>...]')
+ print('Assigns a set of CVEs to a bug')
+ sys.exit(1)
+
+ self.assign(args[0], [self.cleanup_cve(cve) for cve in args[1:]])
+ elif command == 'nfu':
+ if len(args) != 1:
+ print('Usage: nfu <CVE>')
+ print('Marks a CVE as not-for-us')
+ sys.exit(1)
+
+ self.nfu(self.cleanup_cve(args[0]))
+ elif command == 'pw':
+ if len(sys.argv) != 4:
+ print('Usage: pw <user> <password>')
+ print('Generates a base64-encoded credential for storing')
+ sys.exit(1)
+
+ self.pw(sys.argv[2], sys.argv[3])
+ else:
+ self.usage(sys.argv[0])
+ sys.exit(1)
+
+ def info(self, cve):
+ data = self.json_request('/cve/info/' + cve + '.json')
+
+ print(' CVE ID: ' + data['cve_id'])
+ print(' Summary: ' + data['summary'])
+ print(' Published: ' + data['published_at'])
+ print('-' * 80)
+ print(' State: ' + data['state'])
+ print(' Bugs: ' + ' , '.join(['https://bugs.gentoo.org/' + str(bug) for bug in data['bugs']]))
+
+ def assign(self, bug, cves):
+ cve_ids = [self.get_internal_cve_id(cve) for cve in cves]
+ response = self.request('/cve/assign/?bug=' + str(bug) + '&cves=' + ','.join([str(c) for c in cve_ids]))
+
+ if (response == 'ok'):
+ print('Assigned bug {} to {}'.format(str(bug), ', '.join(cves)))
+ else:
+ print('Assigning likely failed: ' + response)
+ sys.exit(1)
+
+ def nfu(self, cve):
+ cve_id = self.get_internal_cve_id(cve)
+ response = self.request('/cve/nfu/?cves=' + str(cve_id) + '&reason=')
+
+ if (response == 'ok'):
+ print('Marked {} as NFU'.format(cve))
+ else:
+ print('Assigning likely failed: ' + response)
+ sys.exit(1)
+
+
+ def usage(self, programname):
+ """ Print usage information """
+ print('Usage: {} <command> <cve> [args]'.format(programname))
+ print('CLI for CVETool.')
+
+ def pw(self, user, password):
+ print(b64encode(bytes(user + ':' + password, 'utf-8')).decode('ascii'))
+
+ def get_internal_cve_id(self, cve):
+ """ Resolves a CVE id to the internal databse ID """
+ return self.json_request('/cve/info/' + cve + '.json')['id']
+
+ def json_request(self, uri, method='GET'):
+ return json.loads(self.request(uri, method))
+
+ def cleanup_cve(self, str):
+ regex = re.compile('^(CVE-)?\d{4}-\d{4,}$')
+ if not regex.match(str):
+ raise ValueError('Cannot parse CVE: ' + str)
+
+ if not str.startswith('CVE-'):
+ return 'CVE-' + str
+ else:
+ return str
+
+ def request(self, uri, method='GET'):
+ client = httplib2.Http('.cache')
+ full_uri = URI_BASE + uri
+ response, content = client.request(full_uri, method, headers = { 'Authorization': 'Basic ' + self.auth })
+
+ status = response['status']
+ if (status[0] != '2' and status != '304'):
+ raise RuntimeError(full_uri + ': ' + status)
+
+ return content.decode('utf-8')
+
+def main():
+ if not 'CVETOOL_AUTH' in os.environ and not sys.argv[1] == 'pw':
+ print('CVETOOL_AUTH environment variable missing. Generate its contents with the pw subcommand.')
+ sys.exit(1)
+
+ auth = None
+ if 'CVETOOL_AUTH' in os.environ:
+ auth = os.environ['CVETOOL_AUTH']
+
+ CVETool(auth, sys.argv[1], sys.argv[2:])
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ print('\n ! Exiting.')