1 /* 2 * This file is part of dependency-check-core. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * Copyright (c) 2012 Jeremy Long. All Rights Reserved. 17 */ 18 package org.owasp.dependencycheck.data.update.nvd; 19 20 import java.util.ArrayList; 21 import java.util.HashMap; 22 import java.util.List; 23 import java.util.Map; 24 import javax.annotation.concurrent.NotThreadSafe; 25 import org.owasp.dependencycheck.dependency.VulnerableSoftware; 26 import org.xml.sax.Attributes; 27 import org.xml.sax.SAXException; 28 import org.xml.sax.SAXNotSupportedException; 29 import org.xml.sax.helpers.DefaultHandler; 30 31 /** 32 * A SAX Handler that will parse the NVD CVE XML (schema version 1.2). This parses the xml and retrieves a listing of 33 * CPEs that have previous versions specified. The previous version information is not in the 2.0 version of the schema 34 * and is useful to ensure accurate identification (or at least complete). 35 * 36 * @author Jeremy Long 37 */ 38 @NotThreadSafe 39 public class NvdCve12Handler extends DefaultHandler { 40 41 /** 42 * the supported schema version. 43 */ 44 private static final String CURRENT_SCHEMA_VERSION = "1.2"; 45 /** 46 * the current vulnerability. 47 */ 48 private String vulnerability; 49 /** 50 * a list of vulnerable software. 51 */ 52 private List<VulnerableSoftware> software; 53 /** 54 * the vendor name. 55 */ 56 private String vendor; 57 /** 58 * the product name. 59 */ 60 private String product; 61 /** 62 * if the nvd cve should be skipped because it was rejected. 63 */ 64 private boolean skip = false; 65 /** 66 * flag indicating if there is a previous version. 67 */ 68 private boolean hasPreviousVersion = false; 69 /** 70 * The current element. 71 */ 72 private final Element current = new Element(); 73 /** 74 * a map of vulnerabilities. 75 */ 76 private Map<String, List<VulnerableSoftware>> vulnerabilities; 77 78 /** 79 * Get the value of vulnerabilities. 80 * 81 * @return the value of vulnerabilities 82 */ getVulnerabilities()83 public Map<String, List<VulnerableSoftware>> getVulnerabilities() { 84 return vulnerabilities; 85 } 86 87 @Override startElement(String uri, String localName, String qName, Attributes attributes)88 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 89 current.setNode(qName); 90 if (current.isEntryNode()) { 91 vendor = null; 92 product = null; 93 hasPreviousVersion = false; 94 final String reject = attributes.getValue("reject"); 95 skip = "1".equals(reject); 96 if (!skip) { 97 vulnerability = attributes.getValue("name"); 98 software = new ArrayList<>(); 99 } else { 100 vulnerability = null; 101 software = null; 102 } 103 } else if (!skip && current.isProdNode()) { 104 vendor = attributes.getValue("vendor"); 105 product = attributes.getValue("name"); 106 } else if (!skip && current.isVersNode()) { 107 final String prev = attributes.getValue("prev"); 108 if (prev != null && "1".equals(prev)) { 109 hasPreviousVersion = true; 110 final String edition = attributes.getValue("edition"); 111 final String num = attributes.getValue("num"); 112 113 /*yes yes, this may not actually be an "a" - it could be an OS, etc. but for our 114 purposes this is good enough as we won't use this if we don't find a corresponding "a" 115 in the nvd cve 2.0. */ 116 final int cpeLen = 8 + vendor.length() + product.length() 117 + (null != num ? (1 + num.length()) : 0) 118 + (null != edition ? (1 + edition.length()) : 0); 119 final StringBuilder cpe = new StringBuilder(cpeLen); 120 cpe.append("cpe:/a:").append(vendor).append(':').append(product); 121 if (num != null) { 122 cpe.append(':').append(num); 123 } 124 if (edition != null) { 125 cpe.append(':').append(edition); 126 } 127 final VulnerableSoftware vs = new VulnerableSoftware(); 128 vs.setCpe(cpe.toString()); 129 vs.setPreviousVersion(prev); 130 software.add(vs); 131 } 132 } else if (current.isNVDNode()) { 133 final String nvdVer = attributes.getValue("nvd_xml_version"); 134 if (!CURRENT_SCHEMA_VERSION.equals(nvdVer)) { 135 throw new SAXNotSupportedException("Schema version " + nvdVer + " is not supported"); 136 } 137 vulnerabilities = new HashMap<>(); 138 } 139 } 140 141 @Override endElement(String uri, String localName, String qName)142 public void endElement(String uri, String localName, String qName) throws SAXException { 143 current.setNode(qName); 144 if (current.isEntryNode()) { 145 if (!skip && hasPreviousVersion) { 146 vulnerabilities.put(vulnerability, software); 147 } 148 vulnerability = null; 149 software = null; 150 } 151 } 152 153 // <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node"> 154 /** 155 * A simple class to maintain information about the current element while parsing the NVD CVE XML. 156 */ 157 protected static class Element { 158 159 /** 160 * A node type in the NVD CVE Schema 1.2. 161 */ 162 public static final String NVD = "nvd"; 163 /** 164 * A node type in the NVD CVE Schema 1.2. 165 */ 166 public static final String ENTRY = "entry"; 167 /** 168 * A node type in the NVD CVE Schema 1.2. 169 */ 170 public static final String VULN_SOFTWARE = "vuln_soft"; 171 /** 172 * A node type in the NVD CVE Schema 1.2. 173 */ 174 public static final String PROD = "prod"; 175 /** 176 * A node type in the NVD CVE Schema 1.2. 177 */ 178 public static final String VERS = "vers"; 179 /** 180 * The name of the current node. 181 */ 182 private String node; 183 184 /** 185 * Gets the value of node. 186 * 187 * @return the value of node 188 */ getNode()189 public String getNode() { 190 return this.node; 191 } 192 193 /** 194 * Sets the value of node. 195 * 196 * @param node new value of node 197 */ setNode(String node)198 public void setNode(String node) { 199 this.node = node; 200 } 201 202 /** 203 * Checks if the handler is at the NVD node. 204 * 205 * @return true or false 206 */ isNVDNode()207 public boolean isNVDNode() { 208 return NVD.equals(node); 209 } 210 211 /** 212 * Checks if the handler is at the ENTRY node. 213 * 214 * @return true or false 215 */ isEntryNode()216 public boolean isEntryNode() { 217 return ENTRY.equals(node); 218 } 219 220 /** 221 * Checks if the handler is at the VULN_SOFTWARE node. 222 * 223 * @return true or false 224 */ isVulnSoftwareNode()225 public boolean isVulnSoftwareNode() { 226 return VULN_SOFTWARE.equals(node); 227 } 228 229 /** 230 * Checks if the handler is at the PROD node. 231 * 232 * @return true or false 233 */ isProdNode()234 public boolean isProdNode() { 235 return PROD.equals(node); 236 } 237 238 /** 239 * Checks if the handler is at the VERS node. 240 * 241 * @return true or false 242 */ isVersNode()243 public boolean isVersNode() { 244 return VERS.equals(node); 245 } 246 } 247 // </editor-fold> 248 } 249