#! /usr/bin/python # # Convert our XML file to a HTML file for the web page # let's replace vulnerabilities.xsl # from xml.dom import minidom import simplejson as json import codecs import re from optparse import OptionParser import datetime import sys # Versions of OpenSSL we never released, to allow us to display ranges, it's not a big deal if they # are not included here, it just makes things look better if they are. neverreleased = "1.0.0h,"; def merge_affects(issue,base): # let's merge the affects into a nice list which is better for Mitre text but we have to take into account our stange lettering scheme prev = "" anext = "" alist = list() vlist = list() for affects in issue.getElementsByTagName('affects'): # so we can sort them version = affects.getAttribute("version") if (not base or base in version): vlist.append(version) for ver in sorted(vlist): # print "version %s (last was %s, next was %s)" %(ver,prev,anext) if (ver != anext): alist.append([ver]) elif len(alist[-1]) > 1: alist[-1][-1] = ver else: alist[-1].append(ver) prev = ver if (unicode.isdigit(ver[-1])): # First version after 1.0.1 is 1.0.1a anext = ver + "a" elif (ver[-1] == "y"): anext = ver[:-1] + "za" # We ran out of letters once so y->za->zb.... else: anext = ver[:-1]+chr(ord(ver[-1])+1) # otherwise after 1.0.1a is 1.0.1b while (anext in neverreleased): # skip unreleased versions anext = anext[:-1]+chr(ord(anext[-1])+1) return ",".join(['-'.join(map(str,aff)) for aff in alist]) def allyourbase(issues): allbase = [] # find all the major versions of OpenSSL we have vulnerabilities fixed in for affects in issues.getElementsByTagName('fixed'): if (affects.getAttribute("base") not in allbase): if ("fips" not in affects.getAttribute("base")): # temporary hack allbase.append(affects.getAttribute("base")) return sorted(allbase, reverse=True) parser = OptionParser() parser.add_option("-i", "--input", help="input vulnerability file live openssl-web/news/vulnerabilities.xml", dest="input") parser.add_option("-b", "--base", help="only include vulnerabilities for this major version (i.e. 1.0.1)", dest="base") (options, args) = parser.parse_args() # We need an output directory not stdout because we might write multiple files if not options.input: print "needs input file" parser.print_help() exit(); cvej = list() with codecs.open(options.input,"r","utf-8") as vulnfile: vulns = vulnfile.read() dom = minidom.parseString(vulns.encode("utf-8")) issues = dom.getElementsByTagName('issue') thisyear = "" allyears = [] # Display issues latest by date first, if same date then by highest CVE allissues = "" for issue in sorted(issues, key=lambda x: (x.getAttribute('public'), x.getElementsByTagName('cve')[0].getAttribute('name')),reverse=True): if options.base: include = 0 for affects in issue.getElementsByTagName('fixed'): if (affects.getAttribute("base") in options.base): include = 1 if (include == 0): continue date = issue.getAttribute('public') year = date[:-4] if (year != thisyear): if (thisyear != ""): allissues += ""; allissues += "

%s

" %(year,year) allyears.append(year) thisyear = year cve = issue.getElementsByTagName('cve')[0].getAttribute('name') allissues += "
" if cve: allissues += "CVE-%s " %(cve,cve,cve) for adv in issue.getElementsByTagName('advisory'): allissues += "(OpenSSL advisory) " %(adv.getAttribute("url")) for sev in issue.getElementsByTagName('impact'): allissues += "[%s severity] " %(sev.getAttribute('severity').lower(),sev.getAttribute('severity')) t = datetime.datetime(int(date[:4]), int(date[4:6]), int(date[6:8]), 0, 0) allissues += t.strftime("%d %B %Y: ") allissues += "
" allissues += issue.getElementsByTagName('description')[0].childNodes[0].nodeValue.strip() for reported in issue.getElementsByTagName('reported'): allissues += " Reported by %s. " %(reported.getAttribute("source")) allissues += "
" preface = "" bases = [] for base in allyourbase(dom): if (options.base and base in options.base): bases.append("%s" %(base)) else: bases.append( "%s" %(base,base)) preface += "

Show issues fixed only in OpenSSL " + ", ".join(bases) if options.base: preface += ", or all versions

" preface += "

Fixed in OpenSSL %s

" %(options.base) else: preface += "

" for statement in dom.getElementsByTagName('statement'): if (statement.getAttribute("base") in (options.base or "none")): preface += "

"+statement.firstChild.data.strip()+"

" if len(allyears)>1: # If only vulns in this year no need for the year table of contents preface += "

Jump to year: " + ", ".join( "%s" %(year,year) for year in allyears) preface += "

" if allissues != "": preface += allissues + "
" else: preface += "No vulnerabilities fixed" sys.stdout.write(preface.encode('utf-8'))