View Javadoc
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) 2018 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.data.nvdcve;
19  //CSOFF: AvoidStarImport
20  
21  import com.google.common.io.Resources;
22  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
23  import io.github.jeremylong.openvulnerability.client.nvd.Config;
24  import io.github.jeremylong.openvulnerability.client.nvd.CpeMatch;
25  import io.github.jeremylong.openvulnerability.client.nvd.CvssV2;
26  import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data;
27  import io.github.jeremylong.openvulnerability.client.nvd.CvssV3;
28  import io.github.jeremylong.openvulnerability.client.nvd.CvssV3Data;
29  import io.github.jeremylong.openvulnerability.client.nvd.CvssV4;
30  import io.github.jeremylong.openvulnerability.client.nvd.CvssV4Data;
31  import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem;
32  import io.github.jeremylong.openvulnerability.client.nvd.LangString;
33  import io.github.jeremylong.openvulnerability.client.nvd.Node;
34  import io.github.jeremylong.openvulnerability.client.nvd.Reference;
35  import io.github.jeremylong.openvulnerability.client.nvd.Weakness;
36  import org.apache.commons.collections4.map.ReferenceMap;
37  import org.owasp.dependencycheck.analyzer.exception.LambdaExceptionWrapper;
38  import org.owasp.dependencycheck.analyzer.exception.UnexpectedAnalysisException;
39  import org.owasp.dependencycheck.data.update.cpe.CpeEcosystemCache;
40  import org.owasp.dependencycheck.data.update.cpe.CpePlus;
41  import org.owasp.dependencycheck.dependency.Vulnerability;
42  import org.owasp.dependencycheck.dependency.VulnerableSoftware;
43  import org.owasp.dependencycheck.dependency.VulnerableSoftwareBuilder;
44  import org.owasp.dependencycheck.utils.InvalidSettingException;
45  import org.owasp.dependencycheck.utils.Pair;
46  import org.owasp.dependencycheck.utils.Settings;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  import us.springett.parsers.cpe.Cpe;
50  import us.springett.parsers.cpe.CpeBuilder;
51  import us.springett.parsers.cpe.CpeParser;
52  import us.springett.parsers.cpe.exceptions.CpeParsingException;
53  import us.springett.parsers.cpe.exceptions.CpeValidationException;
54  
55  import javax.annotation.concurrent.ThreadSafe;
56  import java.io.IOException;
57  import java.net.URL;
58  import java.nio.charset.StandardCharsets;
59  import java.sql.CallableStatement;
60  import java.sql.Connection;
61  import java.sql.JDBCType;
62  import java.sql.PreparedStatement;
63  import java.sql.ResultSet;
64  import java.sql.SQLException;
65  import java.sql.Statement;
66  import java.util.ArrayList;
67  import java.util.Collections;
68  import java.util.Comparator;
69  import java.util.HashMap;
70  import java.util.HashSet;
71  import java.util.List;
72  import java.util.Map;
73  import java.util.MissingResourceException;
74  import java.util.Optional;
75  import java.util.Properties;
76  import java.util.ResourceBundle;
77  import java.util.Set;
78  import java.util.stream.Collectors;
79  
80  import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.HARD;
81  import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.SOFT;
82  import static org.owasp.dependencycheck.data.nvdcve.CveDB.PreparedStatementCveDb.*;
83  
84  /**
85   * The database holding information about the NVD CVE data. This class is safe
86   * to be accessed from multiple threads in parallel, however internally only one
87   * connection will be used.
88   *
89   * @author Jeremy Long
90   */
91  @ThreadSafe
92  public final class CveDB implements AutoCloseable {
93  
94      /**
95       * The logger.
96       */
97      private static final Logger LOGGER = LoggerFactory.getLogger(CveDB.class);
98  
99      /**
100      * Resource location for SQL file containing updates to the ecosystem cache.
101      */
102     public static final String DB_ECOSYSTEM_CACHE = "data/dbEcosystemCacheUpdates.sql";
103 
104     /**
105      * The database connection manager.
106      */
107     private final DatabaseManager databaseManager;
108 
109     /**
110      * The bundle of statements used when accessing the database.
111      */
112     private ResourceBundle statementBundle;
113     /**
114      * Database properties object containing the 'properties' from the database
115      * table.
116      */
117     private DatabaseProperties databaseProperties;
118     /**
119      * The filter for 2.3 CPEs in the CVEs - we don't import unless we get a
120      * match.
121      */
122     private final String cpeStartsWithFilter;
123     /**
124      * Cache for CVE lookup; used to speed up the vulnerability search process.
125      */
126     @SuppressWarnings("unchecked")
127     private final Map<String, List<Vulnerability>> vulnerabilitiesForCpeCache = Collections.synchronizedMap(new ReferenceMap(HARD, SOFT));
128     /**
129      * The configured settings
130      */
131     private final Settings settings;
132 
133     /**
134      * Utility to extract information from
135      * {@linkplain DefCveItem}.
136      */
137     private final CveItemOperator cveItemConverter;
138     /**
139      * Flag indicating if the database is Oracle.
140      */
141     private boolean isOracle = false;
142     /**
143      * Flag indicating if the database is H2.
144      */
145     private boolean isH2 = false;
146 
147     /**
148      * Updates the EcoSystem Cache.
149      *
150      * @return The number of records updated by the DB_ECOSYSTEM_CACHE update
151      * script.
152      */
153     public int updateEcosystemCache() {
154         LOGGER.debug("Updating the ecosystem cache");
155         int updateCount = 0;
156         try {
157             final URL url = Resources.getResource(DB_ECOSYSTEM_CACHE);
158             final List<String> sql = Resources.readLines(url, StandardCharsets.UTF_8);
159 
160             try (Connection conn = databaseManager.getConnection(); Statement statement = conn.createStatement()) {
161                 for (String single : sql) {
162                     updateCount += statement.executeUpdate(single);
163                 }
164             } catch (SQLException ex) {
165                 LOGGER.debug("", ex);
166                 throw new DatabaseException("Unable to update the ecosystem cache", ex);
167             }
168         } catch (IOException ex) {
169             throw new DatabaseException("Unable to update the ecosystem cache", ex);
170         }
171         return updateCount;
172     }
173 
174     /**
175      * The enumeration value names must match the keys of the statements in the
176      * statement bundles "dbStatements*.properties".
177      */
178     enum PreparedStatementCveDb {
179         /**
180          * Key for SQL Statement.
181          */
182         CLEANUP_ORPHANS,
183         /**
184          * Key for update ecosystem.
185          */
186         UPDATE_ECOSYSTEM,
187         /**
188          * Key for update ecosystem.
189          */
190         UPDATE_ECOSYSTEM2,
191         /**
192          * Key for SQL Statement.
193          */
194         COUNT_CPE,
195         /**
196          * Key for SQL Statement.
197          */
198         DELETE_VULNERABILITY,
199         /**
200          * Key for SQL Statement.
201          */
202         INSERT_PROPERTY,
203         /**
204          * Key for SQL Statement.
205          */
206         INSERT_CWE,
207         /**
208          * Key for SQL Statement.
209          */
210         INSERT_REFERENCE,
211         /**
212          * Key for SQL Statement.
213          */
214         INSERT_SOFTWARE,
215         /**
216          * Key for SQL Statement.
217          */
218         MERGE_PROPERTY,
219         /**
220          * Key for SQL Statement.
221          */
222         SELECT_CPE_ENTRIES,
223         /**
224          * Key for SQL Statement.
225          */
226         SELECT_CVE_FROM_SOFTWARE,
227         /**
228          * Key for SQL Statement.
229          */
230         SELECT_PROPERTIES,
231         /**
232          * Key for SQL Statement.
233          */
234         SELECT_VULNERABILITY_CWE,
235         /**
236          * Key for SQL Statement.
237          */
238         SELECT_REFERENCES,
239         /**
240          * Key for SQL Statement.
241          */
242         SELECT_SOFTWARE,
243         /**
244          * Key for SQL Statement.
245          */
246         SELECT_VENDOR_PRODUCT_LIST,
247         /**
248          * Key for SQL Statement.
249          */
250         SELECT_VENDOR_PRODUCT_LIST_FOR_NODE,
251         /**
252          * Key for SQL Statement.
253          */
254         SELECT_VULNERABILITY,
255         /**
256          * Key for SQL Statement.
257          */
258         UPDATE_PROPERTY,
259         /**
260          * Key for SQL Statement.
261          */
262         UPDATE_VULNERABILITY,
263         /**
264          * Key for SQL Statement.
265          */
266         SELECT_CPE_ECOSYSTEM,
267         /**
268          * Key for SQL Statement.
269          */
270         MERGE_CPE_ECOSYSTEM,
271         /**
272          * Key for SQL Statement.
273          */
274         DELETE_UNUSED_DICT_CPE,
275         /**
276          * Key for SQL Statement.
277          */
278         ADD_DICT_CPE,
279         /**
280          * Key for SQL Statement.
281          */
282         SELECT_KNOWN_EXPLOITED_VULNERABILITIES,
283         /**
284          * Key for SQL Statement.
285          */
286         MERGE_KNOWN_EXPLOITED
287     }
288 
289     /**
290      * Creates a new CveDB object and opens the database connection. Note, the
291      * connection must be closed by the caller by calling the close method.
292      *
293      * @param settings the configured settings
294      * @throws DatabaseException thrown if there is an exception opening the
295      * database.
296      */
297     public CveDB(Settings settings) throws DatabaseException {
298         this.settings = settings;
299         this.cpeStartsWithFilter = settings.getString(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER, "cpe:2.3:a:");
300         this.cveItemConverter = new CveItemOperator(cpeStartsWithFilter);
301         databaseManager = new DatabaseManager(settings);
302         statementBundle = databaseManager.getSqlStatements();
303         isOracle = databaseManager.isOracle();
304         isH2 = databaseManager.isH2Connection();
305     }
306 
307     /**
308      * Opens the database connection pool.
309      */
310     public void open() {
311         databaseManager.open();
312         databaseProperties = new DatabaseProperties(this);
313     }
314 
315     /**
316      * Closes the database connection. Close should be called on this object
317      * when it is done being used.
318      */
319     @Override
320     public void close() {
321         if (isOpen()) {
322             LOGGER.debug("Closing database");
323             clearCache();
324             LOGGER.debug("Cache cleared");
325             try {
326                 databaseManager.close();
327                 LOGGER.debug("Connection closed");
328             } catch (Throwable ex) {
329                 LOGGER.error("There was an exception attempting to close the CveDB, see the log for more details.");
330                 LOGGER.debug("", ex);
331             }
332             releaseResources();
333             LOGGER.debug("Resources released");
334             databaseManager.cleanup();
335         }
336     }
337 
338     /**
339      * Releases the resources used by CveDB.
340      */
341     private void releaseResources() {
342         statementBundle = null;
343         databaseProperties = null;
344     }
345 
346     /**
347      * Returns whether the database connection is open or closed.
348      *
349      * @return whether the database connection is open or closed
350      */
351     public boolean isOpen() {
352         return databaseManager.isOpen();
353     }
354 
355     /**
356      * Creates a prepared statement from the given key. The SQL is stored in a
357      * properties file and the key is used to lookup the specific query.
358      *
359      * @param connection the database connection
360      * @param key the key to select the prepared statement from the properties
361      * file
362      * @param parameter the first parameter to pass into the statement
363      * @return the prepared statement
364      * @throws DatabaseException throw if there is an error generating the
365      * prepared statement
366      */
367     private PreparedStatement getPreparedStatement(Connection connection, PreparedStatementCveDb key, String parameter)
368             throws DatabaseException, SQLException {
369         final PreparedStatement preparedStatement = getPreparedStatement(connection, key);
370         preparedStatement.setString(1, parameter);
371         return preparedStatement;
372     }
373 
374     /**
375      * Creates a prepared statement from the given key. The SQL is stored in a
376      * properties file and the key is used to lookup the specific query.
377      *
378      * @param connection the database connection
379      * @param key the key to select the prepared statement from the properties
380      * file
381      * @param parameter the first parameter to pass into the statement
382      * @return the prepared statement
383      * @throws DatabaseException throw if there is an error generating the
384      * prepared statement
385      */
386     private PreparedStatement getPreparedStatement(Connection connection, PreparedStatementCveDb key, int parameter)
387             throws DatabaseException, SQLException {
388         final PreparedStatement preparedStatement = getPreparedStatement(connection, key);
389         preparedStatement.setInt(1, parameter);
390         return preparedStatement;
391     }
392 
393     /**
394      * Creates a prepared statement from the given key. The SQL is stored in a
395      * properties file and the key is used to lookup the specific query.
396      *
397      * @param connection the database connection
398      * @param key the key to select the prepared statement from the properties
399      * file
400      * @return the prepared statement
401      * @throws DatabaseException throw if there is an error generating the
402      * prepared statement
403      */
404     private PreparedStatement getPreparedStatement(Connection connection, PreparedStatementCveDb key) throws DatabaseException {
405         PreparedStatement preparedStatement = null;
406         try {
407             final String statementString = statementBundle.getString(key.name());
408             if (isOracle && key == UPDATE_VULNERABILITY) {
409                 preparedStatement = connection.prepareCall(statementString);
410 //            } else if (key == INSERT_CPE) {
411 //                final String[] returnedColumns = {"id"};
412 //                preparedStatement = connection.prepareStatement(statementString, returnedColumns);
413             } else {
414                 preparedStatement = connection.prepareStatement(statementString);
415             }
416             if (isOracle) {
417                 // Oracle has a default fetch-size of 10; MariaDB, MySQL, SQLServer and PostgreSQL by default cache the full
418                 // resultset at the client https://venkatsadasivam.com/2009/02/01/jdbc-performance-tuning-with-optimal-fetch-size/
419                 preparedStatement.setFetchSize(10_000);
420             }
421         } catch (SQLException ex) {
422             throw new DatabaseException(ex);
423         } catch (MissingResourceException ex) {
424             if (!ex.getMessage().contains("key MERGE_PROPERTY")) {
425                 throw new DatabaseException(ex);
426             }
427         }
428         return preparedStatement;
429     }
430 
431     /**
432      * Cleans up the object and ensures that "close" has been called.
433      *
434      * @throws Throwable thrown if there is a problem
435      */
436     @Override
437     @SuppressWarnings("FinalizeDeclaration")
438     protected void finalize() throws Throwable {
439         LOGGER.debug("Entering finalize");
440         close();
441         super.finalize();
442     }
443 
444     /**
445      * Get the value of databaseProperties.
446      *
447      * @return the value of databaseProperties
448      */
449     public DatabaseProperties getDatabaseProperties() {
450         return databaseProperties;
451     }
452 
453     /**
454      * Used within the unit tests to reload the database properties.
455      *
456      * @return the database properties
457      */
458     DatabaseProperties reloadProperties() {
459         databaseProperties = new DatabaseProperties(this);
460         return databaseProperties;
461     }
462 
463     /**
464      * Searches the CPE entries in the database and retrieves all entries for a
465      * given vendor and product combination. The returned list will include all
466      * versions of the product that are registered in the NVD CVE data.
467      *
468      * @param vendor the identified vendor name of the dependency being analyzed
469      * @param product the identified name of the product of the dependency being
470      * analyzed
471      * @return a set of vulnerable software
472      */
473     public Set<CpePlus> getCPEs(String vendor, String product) {
474         final Set<CpePlus> cpe = new HashSet<>();
475         try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, SELECT_CPE_ENTRIES)) {
476             //part, vendor, product, version, update_version, edition,
477             //lang, sw_edition, target_sw, target_hw, other, ecosystem
478             ps.setString(1, vendor);
479             ps.setString(2, product);
480             try (ResultSet rs = ps.executeQuery()) {
481                 final CpeBuilder builder = new CpeBuilder();
482                 while (rs.next()) {
483                     final Cpe entry = builder
484                             .part(rs.getString(1))
485                             .vendor(rs.getString(2))
486                             .product(rs.getString(3))
487                             .version(rs.getString(4))
488                             .update(rs.getString(5))
489                             .edition(rs.getString(6))
490                             .language(rs.getString(7))
491                             .swEdition(rs.getString(8))
492                             .targetSw(rs.getString(9))
493                             .targetHw(rs.getString(10))
494                             .other(rs.getString(11)).build();
495                     final CpePlus plus = new CpePlus(entry, rs.getString(12));
496                     cpe.add(plus);
497                 }
498             }
499         } catch (SQLException | CpeParsingException | CpeValidationException ex) {
500             LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
501             LOGGER.debug("", ex);
502         }
503         return cpe;
504     }
505 
506     /**
507      * Returns the entire list of vendor/product combinations.
508      *
509      * @return the entire list of vendor/product combinations
510      * @throws DatabaseException thrown when there is an error retrieving the
511      * data from the DB
512      */
513     public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
514         final Set<Pair<String, String>> data = new HashSet<>();
515         try (Connection conn = databaseManager.getConnection();
516                 PreparedStatement ps = getPreparedStatement(conn, SELECT_VENDOR_PRODUCT_LIST);
517                 ResultSet rs = ps.executeQuery()) {
518             while (rs.next()) {
519                 data.add(new Pair<>(rs.getString(1), rs.getString(2)));
520             }
521         } catch (SQLException ex) {
522             final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
523             throw new DatabaseException(msg, ex);
524         }
525         return data;
526     }
527 
528     /**
529      * Returns the entire list of vendor/product combinations filtered for just
530      * Node JS related products.
531      *
532      * @return the list of vendor/product combinations that are known to be
533      * related to Node JS
534      * @throws DatabaseException thrown when there is an error retrieving the
535      * data from the DB
536      */
537     public Set<Pair<String, String>> getVendorProductListForNode() throws DatabaseException {
538         final Set<Pair<String, String>> data = new HashSet<>();
539         try (Connection conn = databaseManager.getConnection();
540                 PreparedStatement ps = getPreparedStatement(conn, SELECT_VENDOR_PRODUCT_LIST_FOR_NODE);
541                 ResultSet rs = ps.executeQuery()) {
542             while (rs.next()) {
543                 data.add(new Pair<>(rs.getString(1), rs.getString(2)));
544             }
545         } catch (SQLException ex) {
546             final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
547             throw new DatabaseException(msg, ex);
548         }
549         return data;
550     }
551 
552     /**
553      * Returns a set of properties.
554      *
555      * @return the properties from the database
556      */
557     public Properties getProperties() {
558         final Properties prop = new Properties();
559         try (Connection conn = databaseManager.getConnection();
560                 PreparedStatement ps = getPreparedStatement(conn, SELECT_PROPERTIES);
561                 ResultSet rs = ps.executeQuery()) {
562             while (rs.next()) {
563                 prop.setProperty(rs.getString(1), rs.getString(2));
564             }
565         } catch (SQLException ex) {
566             LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
567             LOGGER.debug("", ex);
568         }
569         return prop;
570     }
571 
572     /**
573      * Saves a property to the database.
574      *
575      * @param key the property key
576      * @param value the property value
577      */
578     public void saveProperty(String key, String value) {
579         clearCache();
580         try (Connection conn = databaseManager.getConnection(); PreparedStatement mergeProperty = getPreparedStatement(conn, MERGE_PROPERTY)) {
581             if (mergeProperty != null) {
582                 mergeProperty.setString(1, key);
583                 mergeProperty.setString(2, value);
584                 mergeProperty.execute();
585             } else {
586                 // No Merge statement, so doing an Update/Insert...
587                 try (PreparedStatement updateProperty = getPreparedStatement(conn, UPDATE_PROPERTY)) {
588                     updateProperty.setString(1, value);
589                     updateProperty.setString(2, key);
590                     if (updateProperty.executeUpdate() == 0) {
591                         try (PreparedStatement insertProperty = getPreparedStatement(conn, INSERT_PROPERTY)) {
592                             insertProperty.setString(1, key);
593                             insertProperty.setString(2, value);
594                             insertProperty.executeUpdate();
595                         }
596                     }
597                 }
598             }
599         } catch (SQLException ex) {
600             LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
601             LOGGER.debug("", ex);
602         }
603     }
604 
605     /**
606      * Clears cache. Should be called whenever something is modified. While this
607      * is not the optimal cache eviction strategy, this is good enough for
608      * typical usage (update DB and then only read) and it is easier to maintain
609      * the code.
610      * <p>
611      * It should be also called when DB is closed.
612      * </p>
613      */
614     private void clearCache() {
615         vulnerabilitiesForCpeCache.clear();
616     }
617 
618     /**
619      * Retrieves the vulnerabilities associated with the specified CPE.
620      *
621      * @param cpe the CPE to retrieve vulnerabilities for
622      * @return a list of Vulnerabilities
623      * @throws DatabaseException thrown if there is an exception retrieving data
624      */
625     public List<Vulnerability> getVulnerabilities(Cpe cpe) throws DatabaseException {
626         final List<Vulnerability> cachedVulnerabilities = vulnerabilitiesForCpeCache.get(cpe.toCpe23FS());
627         if (cachedVulnerabilities != null) {
628             LOGGER.debug("Cache hit for {}", cpe.toCpe23FS());
629             return cachedVulnerabilities;
630         } else {
631             LOGGER.debug("Cache miss for {}", cpe.toCpe23FS());
632         }
633 
634         final List<Vulnerability> vulnerabilities = new ArrayList<>();
635         try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, SELECT_CVE_FROM_SOFTWARE)) {
636             ps.setString(1, cpe.getVendor());
637             ps.setString(2, cpe.getProduct());
638             try (ResultSet rs = ps.executeQuery()) {
639                 String currentCVE = "";
640                 final Set<VulnerableSoftware> vulnSoftware = new HashSet<>();
641                 final VulnerableSoftwareBuilder vulnerableSoftwareBuilder = new VulnerableSoftwareBuilder();
642                 while (rs.next()) {
643                     final String cveId = rs.getString(1);
644                     if (currentCVE.isEmpty()) {
645                         //first loop we don't have the cveId
646                         currentCVE = cveId;
647                     }
648                     if (!vulnSoftware.isEmpty() && !currentCVE.equals(cveId)) { //check for match and add
649                         final VulnerableSoftware matchedCPE = getMatchingSoftware(cpe, vulnSoftware);
650                         if (matchedCPE != null) {
651                             final Vulnerability v = getVulnerability(currentCVE, conn);
652                             if (v != null) {
653                                 v.setMatchedVulnerableSoftware(matchedCPE);
654                                 v.setSource(Vulnerability.Source.NVD);
655                                 vulnerabilities.add(v);
656                             }
657                         }
658                         vulnSoftware.clear();
659                         currentCVE = cveId;
660                     }
661                     // 1 cve, 2 part, 3 vendor, 4 product, 5 version, 6 update_version, 7 edition,
662                     // 8 lang, 9 sw_edition, 10 target_sw, 11 target_hw, 12 other, 13 versionEndExcluding,
663                     //14 versionEndIncluding, 15 versionStartExcluding, 16 versionStartIncluding, 17 vulnerable
664                     final VulnerableSoftware vs;
665                     try {
666                         vs = vulnerableSoftwareBuilder.part(rs.getString(2)).vendor(rs.getString(3))
667                                 .product(rs.getString(4)).version(rs.getString(5)).update(rs.getString(6))
668                                 .edition(rs.getString(7)).language(rs.getString(8)).swEdition(rs.getString(9))
669                                 .targetSw(rs.getString(10)).targetHw(rs.getString(11)).other(rs.getString(12))
670                                 .versionEndExcluding(rs.getString(13)).versionEndIncluding(rs.getString(14))
671                                 .versionStartExcluding(rs.getString(15)).versionStartIncluding(rs.getString(16))
672                                 .vulnerable(rs.getBoolean(17)).build();
673                     } catch (CpeParsingException | CpeValidationException ex) {
674                         throw new DatabaseException("Database contains an invalid Vulnerable Software Entry", ex);
675                     }
676                     vulnSoftware.add(vs);
677                 }
678 
679                 //remember to process the last set of CVE/CPE entries
680                 final VulnerableSoftware matchedCPE = getMatchingSoftware(cpe, vulnSoftware);
681                 if (matchedCPE != null) {
682                     final Vulnerability v = getVulnerability(currentCVE, conn);
683                     if (v != null) {
684                         v.setMatchedVulnerableSoftware(matchedCPE);
685                         v.setSource(Vulnerability.Source.NVD);
686                         vulnerabilities.add(v);
687                     }
688                 }
689             }
690         } catch (SQLException ex) {
691             throw new DatabaseException("Exception retrieving vulnerability for " + cpe.toCpe23FS(), ex);
692         }
693         vulnerabilitiesForCpeCache.put(cpe.toCpe23FS(), vulnerabilities);
694         return vulnerabilities;
695     }
696 
697     /**
698      * Gets a vulnerability for the provided CVE.
699      *
700      * @param cve the CVE to lookup
701      * @return a vulnerability object
702      * @throws DatabaseException if an exception occurs
703      */
704     public Vulnerability getVulnerability(String cve) throws DatabaseException {
705         try (Connection conn = databaseManager.getConnection()) {
706             return getVulnerability(cve, conn);
707         } catch (SQLException ex) {
708             throw new DatabaseException("Error retrieving " + cve, ex);
709         }
710     }
711 
712     /**
713      * Gets a vulnerability for the provided CVE.
714      *
715      * @param cve the CVE to lookup
716      * @param conn already active database connection
717      * @return a vulnerability object
718      * @throws DatabaseException if an exception occurs
719      */
720     public Vulnerability getVulnerability(String cve, Connection conn) throws DatabaseException {
721         final int cveId;
722         final VulnerableSoftwareBuilder vulnerableSoftwareBuilder = new VulnerableSoftwareBuilder();
723         Vulnerability vuln = null;
724         try {
725             try (PreparedStatement psV = getPreparedStatement(conn, SELECT_VULNERABILITY, cve); ResultSet rsV = psV.executeQuery()) {
726                 if (rsV.next()) {
727                     //1.id, 2.description,
728                     cveId = rsV.getInt(1);
729                     vuln = new Vulnerability();
730                     vuln.setSource(Vulnerability.Source.NVD);
731                     vuln.setName(cve);
732                     vuln.setDescription(rsV.getString(2));
733 
734                     //3.v2Severity, 4.v2ExploitabilityScore, 5.v2ImpactScore, 6.v2AcInsufInfo, 7.v2ObtainAllPrivilege,
735                     //8.v2ObtainUserPrivilege, 9.v2ObtainOtherPrivilege, 10.v2UserInteractionRequired, 11.v2Score,
736                     //12.v2AccessVector, 13.v2AccessComplexity, 14.v2Authentication, 15.v2ConfidentialityImpact,
737                     //16.v2IntegrityImpact, 17.v2AvailabilityImpact, 18.v2Version,
738                     if (rsV.getObject(11) != null) {
739 
740                         final CvssV2Data.AccessVectorType accessVector = CvssV2Data.AccessVectorType.fromValue(rsV.getString(12));
741                         final CvssV2Data.AccessComplexityType accessComplexity = CvssV2Data.AccessComplexityType.fromValue(rsV.getString(13));
742                         final CvssV2Data.AuthenticationType authentication = CvssV2Data.AuthenticationType.fromValue(rsV.getString(14));
743                         final CvssV2Data.CiaType confidentialityImpact = CvssV2Data.CiaType.fromValue(rsV.getString(15));
744                         final CvssV2Data.CiaType integrityImpact = CvssV2Data.CiaType.fromValue(rsV.getString(16));
745                         final CvssV2Data.CiaType availabilityImpact = CvssV2Data.CiaType.fromValue(rsV.getString(17));
746                         final String vector = String.format("/AV:%s/AC:%s/Au:%s/C:%s/I:%s/A:%s",
747                                 accessVector == null ? "" : accessVector.value().substring(0, 1),
748                                 accessComplexity == null ? "" : accessComplexity.value().substring(0, 1),
749                                 authentication == null ? "" : authentication.value().substring(0, 1),
750                                 confidentialityImpact == null ? "" : confidentialityImpact.value().substring(0, 1),
751                                 integrityImpact == null ? "" : integrityImpact.value().substring(0, 1),
752                                 availabilityImpact == null ? "" : availabilityImpact.value().substring(0, 1));
753 
754                         final CvssV2Data cvssData = new CvssV2Data(CvssV2Data.Version._2_0, vector, accessVector,
755                                 accessComplexity, authentication, confidentialityImpact,
756                                 integrityImpact, availabilityImpact, rsV.getDouble(11), rsV.getString(3),
757                                 null, null, null, null, null, null, null, null, null, null);
758                         final CvssV2 cvss = new CvssV2(null, CvssV2.Type.PRIMARY, cvssData, rsV.getString(3),
759                                 rsV.getDouble(4), rsV.getDouble(5), rsV.getBoolean(6), rsV.getBoolean(7),
760                                 rsV.getBoolean(8), rsV.getBoolean(9), rsV.getBoolean(10));
761                         vuln.setCvssV2(cvss);
762                     }
763                     //19.v3ExploitabilityScore, 20.v3ImpactScore, 21.v3AttackVector, 22.v3AttackComplexity, 23.v3PrivilegesRequired,
764                     //24.v3UserInteraction, 25.v3Scope, 26.v3ConfidentialityImpact, 27.v3IntegrityImpact, 28.v3AvailabilityImpact,
765                     //29.v3BaseScore, 30.v3BaseSeverity, 31.v3Version
766                     if (rsV.getObject(21) != null) {
767                         //some older test data may not correctly have the version set.
768                         String cveVersion = "3.1";
769                         if (rsV.getString(31) != null) {
770                             cveVersion = rsV.getString(31);
771                         }
772                         final CvssV3Data.Version version = CvssV3Data.Version.fromValue(cveVersion);
773                         final CvssV3Data.AttackVectorType attackVector = CvssV3Data.AttackVectorType.fromValue(rsV.getString(21));
774                         final CvssV3Data.AttackComplexityType attackComplexity = CvssV3Data.AttackComplexityType.fromValue(rsV.getString(22));
775                         final CvssV3Data.PrivilegesRequiredType privilegesRequired = CvssV3Data.PrivilegesRequiredType.fromValue(rsV.getString(23));
776                         final CvssV3Data.UserInteractionType userInteraction = CvssV3Data.UserInteractionType.fromValue(rsV.getString(24));
777                         final CvssV3Data.ScopeType scope = CvssV3Data.ScopeType.fromValue(rsV.getString(25));
778                         final CvssV3Data.CiaType confidentialityImpact = CvssV3Data.CiaType.fromValue(rsV.getString(26));
779                         final CvssV3Data.CiaType integrityImpact = CvssV3Data.CiaType.fromValue(rsV.getString(27));
780                         final CvssV3Data.CiaType availabilityImpact = CvssV3Data.CiaType.fromValue(rsV.getString(28));
781                         final CvssV3Data.SeverityType baseSeverity = CvssV3Data.SeverityType.fromValue(rsV.getString(30));
782                         final String vector = String.format("CVSS:%s/AV:%s/AC:%s/PR:%s/UI:%s/S:%s/C:%s/I:%s/A:%s",
783                                 version == null ? "" : version,
784                                 attackVector == null ? "" : attackVector.value().substring(0, 1),
785                                 attackComplexity == null ? "" : attackComplexity.value().substring(0, 1),
786                                 privilegesRequired == null ? "" : privilegesRequired.value().substring(0, 1),
787                                 userInteraction == null ? "" : userInteraction.value().substring(0, 1),
788                                 scope == null ? "" : scope.value().substring(0, 1),
789                                 confidentialityImpact == null ? "" : confidentialityImpact.value().substring(0, 1),
790                                 integrityImpact == null ? "" : integrityImpact.value().substring(0, 1),
791                                 availabilityImpact == null ? "" : availabilityImpact.value().substring(0, 1));
792 
793                         final CvssV3Data cvssData = new CvssV3Data(version, vector, attackVector, attackComplexity, privilegesRequired,
794                                 userInteraction, scope, confidentialityImpact, integrityImpact, availabilityImpact,
795                                 rsV.getDouble(29), baseSeverity, CvssV3Data.ExploitCodeMaturityType.PROOF_OF_CONCEPT,
796                                 CvssV3Data.RemediationLevelType.NOT_DEFINED, CvssV3Data.ConfidenceType.REASONABLE, 0.0,
797                                 CvssV3Data.SeverityType.MEDIUM, CvssV3Data.CiaRequirementType.NOT_DEFINED,
798                                 CvssV3Data.CiaRequirementType.NOT_DEFINED, CvssV3Data.CiaRequirementType.NOT_DEFINED,
799                                 CvssV3Data.ModifiedAttackVectorType.ADJACENT_NETWORK, CvssV3Data.ModifiedAttackComplexityType.NOT_DEFINED,
800                                 CvssV3Data.ModifiedPrivilegesRequiredType.NOT_DEFINED, CvssV3Data.ModifiedUserInteractionType.NOT_DEFINED,
801                                 CvssV3Data.ModifiedScopeType.NOT_DEFINED, CvssV3Data.ModifiedCiaType.NOT_DEFINED,
802                                 CvssV3Data.ModifiedCiaType.NOT_DEFINED, CvssV3Data.ModifiedCiaType.NOT_DEFINED, 1.0,
803                                 CvssV3Data.SeverityType.NONE);
804                         final CvssV3 cvss = new CvssV3(null, null, cvssData, rsV.getDouble(19), rsV.getDouble(20));
805                         vuln.setCvssV3(cvss);
806                     }
807 //                    32.v4version, 33.v4attackVector, 34.v4attackComplexity, 35.v4attackRequirements, 36.v4privilegesRequired,
808 //                    37.v4userInteraction, 38.v4vulnConfidentialityImpact, 39.v4vulnIntegrityImpact, 40.v4vulnAvailabilityImpact,
809 //                    41.v4subConfidentialityImpact, 42.v4subIntegrityImpact, 43.v4subAvailabilityImpact, 44.v4exploitMaturity,
810 //                    45.v4confidentialityRequirement, 46.v4integrityRequirement, 47.v4availabilityRequirement, 48.v4modifiedAttackVector,
811 //                    49.v4modifiedAttackComplexity, 50.v4modifiedAttackRequirements, 51.v4modifiedPrivilegesRequired, 52.v4modifiedUserInteraction,
812 //                    53.v4modifiedVulnConfidentialityImpact, 54.v4modifiedVulnIntegrityImpact, 55.v4modifiedVulnAvailabilityImpact,
813 //                    56.v4modifiedSubConfidentialityImpact, 57.v4modifiedSubIntegrityImpact, 58.v4modifiedSubAvailabilityImpact,
814 //                    59.v4safety, 60.v4automatable, 61.v4recovery, 62.v4valueDensity, 63.v4vulnerabilityResponseEffort, 64.v4providerUrgency,
815 //                    65.v4baseScore, 66.v4baseSeverity, 67.v4threatScore, 68.v4threatSeverity, 69.v4environmentalScore, 70.v4environmentalSeverity
816 //                    71.v4source, 72.v4type
817                     if (rsV.getObject(33) != null) {
818                         String vectorString = null;
819 
820                         String value = rsV.getString(32);
821                         final CvssV4Data.Version version = CvssV4Data.Version.fromValue(value);
822                         CvssV4Data.AttackVectorType attackVector = null;
823                         value = rsV.getString(33);
824                         if (value != null) {
825                             attackVector = CvssV4Data.AttackVectorType.fromValue(value);
826                         }
827                         CvssV4Data.AttackComplexityType attackComplexity = null;
828                         value = rsV.getString(34);
829                         if (value != null) {
830                             attackComplexity = CvssV4Data.AttackComplexityType.fromValue(value);
831                         }
832                         CvssV4Data.AttackRequirementsType attackRequirements = null;
833                         value = rsV.getString(35);
834                         if (value != null) {
835                             attackRequirements = CvssV4Data.AttackRequirementsType.fromValue(value);
836                         }
837                         CvssV4Data.PrivilegesRequiredType privilegesRequired = null;
838                         value = rsV.getString(36);
839                         if (value != null) {
840                             privilegesRequired = CvssV4Data.PrivilegesRequiredType.fromValue(value);
841                         }
842                         CvssV4Data.UserInteractionType userInteraction = null;
843                         value = rsV.getString(37);
844                         if (value != null) {
845                             userInteraction = CvssV4Data.UserInteractionType.fromValue(value);
846                         }
847                         CvssV4Data.CiaType vulnConfidentialityImpact = null;
848                         value = rsV.getString(38);
849                         if (value != null) {
850                             vulnConfidentialityImpact = CvssV4Data.CiaType.fromValue(value);
851                         }
852                         CvssV4Data.CiaType vulnIntegrityImpact = null;
853                         value = rsV.getString(39);
854                         if (value != null) {
855                             vulnIntegrityImpact = CvssV4Data.CiaType.fromValue(value);
856                         }
857                         CvssV4Data.CiaType vulnAvailabilityImpact = null;
858                         value = rsV.getString(40);
859                         if (value != null) {
860                             vulnAvailabilityImpact = CvssV4Data.CiaType.fromValue(value);
861                         }
862                         CvssV4Data.CiaType subConfidentialityImpact = null;
863                         value = rsV.getString(41);
864                         if (value != null) {
865                             subConfidentialityImpact = CvssV4Data.CiaType.fromValue(value);
866                         }
867                         CvssV4Data.CiaType subIntegrityImpact = null;
868                         value = rsV.getString(42);
869                         if (value != null) {
870                             subIntegrityImpact = CvssV4Data.CiaType.fromValue(value);
871                         }
872                         CvssV4Data.CiaType subAvailabilityImpact = null;
873                         value = rsV.getString(43);
874                         if (value != null) {
875                             subAvailabilityImpact = CvssV4Data.CiaType.fromValue(value);
876                         }
877                         CvssV4Data.ExploitMaturityType exploitMaturity = null;
878                         value = rsV.getString(44);
879                         if (value != null) {
880                             exploitMaturity = CvssV4Data.ExploitMaturityType.fromValue(value);
881                         }
882                         CvssV4Data.CiaRequirementType confidentialityRequirement = null;
883                         value = rsV.getString(45);
884                         if (value != null) {
885                             confidentialityRequirement = CvssV4Data.CiaRequirementType.fromValue(value);
886                         }
887                         CvssV4Data.CiaRequirementType integrityRequirement = null;
888                         value = rsV.getString(46);
889                         if (value != null) {
890                             integrityRequirement = CvssV4Data.CiaRequirementType.fromValue(value);
891                         }
892                         CvssV4Data.CiaRequirementType availabilityRequirement = null;
893                         value = rsV.getString(47);
894                         if (value != null) {
895                             availabilityRequirement = CvssV4Data.CiaRequirementType.fromValue(value);
896                         }
897                         CvssV4Data.ModifiedAttackVectorType modifiedAttackVector = null;
898                         value = rsV.getString(48);
899                         if (value != null) {
900                             modifiedAttackVector = CvssV4Data.ModifiedAttackVectorType.fromValue(value);
901                         }
902                         CvssV4Data.ModifiedAttackComplexityType modifiedAttackComplexity = null;
903                         value = rsV.getString(49);
904                         if (value != null) {
905                             modifiedAttackComplexity = CvssV4Data.ModifiedAttackComplexityType.fromValue(value);
906                         }
907                         CvssV4Data.ModifiedAttackRequirementsType modifiedAttackRequirements = null;
908                         value = rsV.getString(50);
909                         if (value != null) {
910                             modifiedAttackRequirements = CvssV4Data.ModifiedAttackRequirementsType.fromValue(value);
911                         }
912                         CvssV4Data.ModifiedPrivilegesRequiredType modifiedPrivilegesRequired = null;
913                         value = rsV.getString(51);
914                         if (value != null) {
915                             modifiedPrivilegesRequired = CvssV4Data.ModifiedPrivilegesRequiredType.fromValue(value);
916                         }
917                         CvssV4Data.ModifiedUserInteractionType modifiedUserInteraction = null;
918                         value = rsV.getString(52);
919                         if (value != null) {
920                             modifiedUserInteraction = CvssV4Data.ModifiedUserInteractionType.fromValue(value);
921                         }
922                         CvssV4Data.ModifiedCiaType modifiedVulnConfidentialityImpact = null;
923                         value = rsV.getString(53);
924                         if (value != null) {
925                             modifiedVulnConfidentialityImpact = CvssV4Data.ModifiedCiaType.fromValue(value);
926                         }
927                         CvssV4Data.ModifiedCiaType modifiedVulnIntegrityImpact = null;
928                         value = rsV.getString(54);
929                         if (value != null) {
930                             modifiedVulnIntegrityImpact = CvssV4Data.ModifiedCiaType.fromValue(value);
931                         }
932                         CvssV4Data.ModifiedCiaType modifiedVulnAvailabilityImpact = null;
933                         value = rsV.getString(55);
934                         if (value != null) {
935                             modifiedVulnAvailabilityImpact = CvssV4Data.ModifiedCiaType.fromValue(value);
936                         }
937                         CvssV4Data.ModifiedSubCType modifiedSubConfidentialityImpact = null;
938                         value = rsV.getString(56);
939                         if (value != null) {
940                             modifiedSubConfidentialityImpact = CvssV4Data.ModifiedSubCType.fromValue(value);
941                         }
942                         CvssV4Data.ModifiedSubIaType modifiedSubIntegrityImpact = null;
943                         value = rsV.getString(57);
944                         if (value != null) {
945                             modifiedSubIntegrityImpact = CvssV4Data.ModifiedSubIaType.fromValue(value);
946                         }
947                         CvssV4Data.ModifiedSubIaType modifiedSubAvailabilityImpact = null;
948                         value = rsV.getString(58);
949                         if (value != null) {
950                             modifiedSubAvailabilityImpact = CvssV4Data.ModifiedSubIaType.fromValue(value);
951                         }
952                         CvssV4Data.SafetyType safety = null;
953                         value = rsV.getString(59);
954                         if (value != null) {
955                             safety = CvssV4Data.SafetyType.fromValue(value);
956                         }
957                         CvssV4Data.AutomatableType automatable = null;
958                         value = rsV.getString(60);
959                         if (value != null) {
960                             automatable = CvssV4Data.AutomatableType.fromValue(value);
961                         }
962                         CvssV4Data.RecoveryType recovery = null;
963                         value = rsV.getString(61);
964                         if (value != null) {
965                             recovery = CvssV4Data.RecoveryType.fromValue(value);
966                         }
967                         CvssV4Data.ValueDensityType valueDensity = null;
968                         value = rsV.getString(62);
969                         if (value != null) {
970                             valueDensity = CvssV4Data.ValueDensityType.fromValue(value);
971                         }
972                         CvssV4Data.VulnerabilityResponseEffortType vulnerabilityResponseEffort = null;
973                         value = rsV.getString(63);
974                         if (value != null) {
975                             vulnerabilityResponseEffort = CvssV4Data.VulnerabilityResponseEffortType.fromValue(value);
976                         }
977                         CvssV4Data.ProviderUrgencyType providerUrgency = null;
978                         value = rsV.getString(64);
979                         if (value != null) {
980                             providerUrgency = CvssV4Data.ProviderUrgencyType.fromValue(value);
981                         }
982                         Double baseScore = null;
983                         if (rsV.getObject(65) != null) {
984                             baseScore = rsV.getDouble(65);
985                         }
986                         CvssV4Data.SeverityType baseSeverity = null;
987                         value = rsV.getString(66);
988                         if (value != null) {
989                             baseSeverity = CvssV4Data.SeverityType.fromValue(value);
990                         }
991                         Double threatScore = null;
992                         if (rsV.getObject(67) != null) {
993                             threatScore = rsV.getDouble(67);
994                         }
995                         CvssV4Data.SeverityType threatSeverity = null;
996                         value = rsV.getString(68);
997                         if (value != null) {
998                             threatSeverity = CvssV4Data.SeverityType.fromValue(value);
999                         }
1000                         Double environmentalScore = null;
1001                         if (rsV.getObject(69) != null) {
1002                             environmentalScore = rsV.getDouble(69);
1003                         }
1004                         CvssV4Data.SeverityType environmentalSeverity = null;
1005                         value = rsV.getString(70);
1006                         if (value != null) {
1007                             environmentalSeverity = CvssV4Data.SeverityType.fromValue(value);
1008                         }
1009                         //initializing data twice to get the vector string. I really should have designed the object better...
1010                         CvssV4Data data = new CvssV4Data(version, vectorString, attackVector, attackComplexity, attackRequirements, privilegesRequired,
1011                                 userInteraction, vulnConfidentialityImpact, vulnIntegrityImpact, vulnAvailabilityImpact, subConfidentialityImpact,
1012                                 subIntegrityImpact, subAvailabilityImpact, exploitMaturity, confidentialityRequirement, integrityRequirement,
1013                                 availabilityRequirement, modifiedAttackVector, modifiedAttackComplexity, modifiedAttackRequirements,
1014                                 modifiedPrivilegesRequired, modifiedUserInteraction, modifiedVulnConfidentialityImpact, modifiedVulnIntegrityImpact,
1015                                 modifiedVulnAvailabilityImpact, modifiedSubConfidentialityImpact, modifiedSubIntegrityImpact,
1016                                 modifiedSubAvailabilityImpact, safety, automatable, recovery, valueDensity, vulnerabilityResponseEffort,
1017                                 providerUrgency, baseScore, baseSeverity, threatScore, threatSeverity, environmentalScore, environmentalSeverity);
1018                         vectorString = data.toString();
1019                         data = new CvssV4Data(version, vectorString, attackVector, attackComplexity, attackRequirements, privilegesRequired,
1020                                 userInteraction, vulnConfidentialityImpact, vulnIntegrityImpact, vulnAvailabilityImpact, subConfidentialityImpact,
1021                                 subIntegrityImpact, subAvailabilityImpact, exploitMaturity, confidentialityRequirement, integrityRequirement,
1022                                 availabilityRequirement, modifiedAttackVector, modifiedAttackComplexity, modifiedAttackRequirements,
1023                                 modifiedPrivilegesRequired, modifiedUserInteraction, modifiedVulnConfidentialityImpact, modifiedVulnIntegrityImpact,
1024                                 modifiedVulnAvailabilityImpact, modifiedSubConfidentialityImpact, modifiedSubIntegrityImpact,
1025                                 modifiedSubAvailabilityImpact, safety, automatable, recovery, valueDensity, vulnerabilityResponseEffort,
1026                                 providerUrgency, baseScore, baseSeverity, threatScore, threatSeverity, environmentalScore, environmentalSeverity);
1027 
1028                         final String source = rsV.getString(71);
1029                         CvssV4.Type cvssType = null;
1030                         value = rsV.getString(72);
1031                         if (value != null) {
1032                             cvssType = CvssV4.Type.fromValue(value);
1033                         }
1034                         final CvssV4 cvssv4 = new CvssV4(source, cvssType, data);
1035                         vuln.setCvssV4(cvssv4);
1036                     }
1037                 } else {
1038                     LOGGER.debug(cve + " does not exist in the database");
1039                     return null;
1040                 }
1041             }
1042             try (PreparedStatement psCWE = getPreparedStatement(conn, SELECT_VULNERABILITY_CWE, cveId); ResultSet rsC = psCWE.executeQuery()) {
1043                 while (rsC.next()) {
1044                     vuln.addCwe(rsC.getString(1));
1045                 }
1046             }
1047             try (PreparedStatement psR = getPreparedStatement(conn, SELECT_REFERENCES, cveId); ResultSet rsR = psR.executeQuery()) {
1048                 while (rsR.next()) {
1049                     vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
1050                 }
1051             }
1052             try (PreparedStatement psS = getPreparedStatement(conn, SELECT_SOFTWARE, cveId); ResultSet rsS = psS.executeQuery()) {
1053                 //1 part, 2 vendor, 3 product, 4 version, 5 update_version, 6 edition, 7 lang,
1054                 //8 sw_edition, 9 target_sw, 10 target_hw, 11 other, 12 versionEndExcluding,
1055                 //13 versionEndIncluding, 14 versionStartExcluding, 15 versionStartIncluding, 16 vulnerable
1056                 while (rsS.next()) {
1057                     vulnerableSoftwareBuilder.part(rsS.getString(1))
1058                             .vendor(rsS.getString(2))
1059                             .product(rsS.getString(3))
1060                             .version(rsS.getString(4))
1061                             .update(rsS.getString(5))
1062                             .edition(rsS.getString(6))
1063                             .language(rsS.getString(7))
1064                             .swEdition(rsS.getString(8))
1065                             .targetSw(rsS.getString(9))
1066                             .targetHw(rsS.getString(10))
1067                             .other(rsS.getString(11))
1068                             .versionEndExcluding(rsS.getString(12))
1069                             .versionEndIncluding(rsS.getString(13))
1070                             .versionStartExcluding(rsS.getString(14))
1071                             .versionStartIncluding(rsS.getString(15))
1072                             .vulnerable(rsS.getBoolean(16));
1073                     vuln.addVulnerableSoftware(vulnerableSoftwareBuilder.build());
1074                 }
1075             }
1076         } catch (SQLException ex) {
1077             throw new DatabaseException("Error retrieving " + cve, ex);
1078         } catch (CpeParsingException | CpeValidationException ex) {
1079             throw new DatabaseException("The database contains an invalid Vulnerable Software Entry", ex);
1080         }
1081         return vuln;
1082     }
1083 
1084     /**
1085      * Updates the vulnerability within the database. If the vulnerability does
1086      * not exist it will be added.
1087      *
1088      * @param cve the vulnerability from the NVD CVE Data Feed to add to the
1089      * database
1090      * @param baseEcosystem the ecosystem the CVE belongs to; this is based off
1091      * of things like the CVE description
1092      * @throws DatabaseException is thrown if the database
1093      */
1094     public void updateVulnerability(DefCveItem cve, String baseEcosystem) {
1095         clearCache();
1096         final String cveId = cve.getCve().getId();
1097         try {
1098             if (cve.getCve().getVulnStatus() != null && cve.getCve().getVulnStatus().toUpperCase().startsWith("REJECT")) {
1099                 deleteVulnerability(cveId);
1100             } else {
1101                 if (cveItemConverter.testCveCpeStartWithFilter(cve)) {
1102                     final String description = cveItemConverter.extractDescription(cve);
1103                     final int vulnerabilityId = updateOrInsertVulnerability(cve, description);
1104                     updateVulnerabilityInsertCwe(vulnerabilityId, cve);
1105                     updateVulnerabilityInsertReferences(vulnerabilityId, cve);
1106 
1107                     final List<VulnerableSoftware> software = parseCpes(cve);
1108                     updateVulnerabilityInsertSoftware(vulnerabilityId, cveId, software, baseEcosystem);
1109                 }
1110             }
1111         } catch (SQLException ex) {
1112             final String msg = String.format("Error updating '%s'; %s", cveId, ex.getMessage());
1113             LOGGER.debug(msg, ex);
1114             throw new DatabaseException(msg);
1115         } catch (CpeValidationException ex) {
1116             final String msg = String.format("Error parsing CPE entry from '%s'; %s", cveId, ex.getMessage());
1117             LOGGER.debug(msg, ex);
1118             throw new DatabaseException(msg);
1119         }
1120     }
1121 
1122     private void loadCpeEcosystemCache() {
1123         final Map<Pair<String, String>, String> map = new HashMap<>();
1124         try (Connection conn = databaseManager.getConnection();
1125                 PreparedStatement ps = getPreparedStatement(conn, SELECT_CPE_ECOSYSTEM);
1126                 ResultSet rs = ps.executeQuery()) {
1127             while (rs.next()) {
1128                 final Pair<String, String> key = new Pair<>(rs.getString(1), rs.getString(2));
1129                 final String value = rs.getString(3);
1130                 map.put(key, value);
1131             }
1132         } catch (SQLException ex) {
1133             final String msg = String.format("Error loading the Cpe Ecosystem Cache: %s", ex.getMessage());
1134             LOGGER.debug(msg, ex);
1135             throw new DatabaseException(msg, ex);
1136         }
1137         CpeEcosystemCache.setCache(map);
1138     }
1139 
1140     private void saveCpeEcosystemCache() {
1141         final Map<Pair<String, String>, String> map = CpeEcosystemCache.getChanged();
1142         if (map != null && !map.isEmpty()) {
1143             try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, MERGE_CPE_ECOSYSTEM)) {
1144                 for (Map.Entry<Pair<String, String>, String> entry : map.entrySet()) {
1145                     ps.setString(1, entry.getKey().getLeft());
1146                     ps.setString(2, entry.getKey().getRight());
1147                     ps.setString(3, entry.getValue());
1148                     if (isBatchInsertEnabled()) {
1149                         ps.addBatch();
1150                     } else {
1151                         ps.execute();
1152                     }
1153                 }
1154                 if (isBatchInsertEnabled()) {
1155                     ps.executeBatch();
1156                 }
1157             } catch (SQLException ex) {
1158                 final String msg = String.format("Error saving the Cpe Ecosystem Cache: %s", ex.getMessage());
1159                 LOGGER.debug(msg, ex);
1160                 throw new DatabaseException(msg, ex);
1161             }
1162         }
1163     }
1164 
1165     /**
1166      * Used when updating a vulnerability - this method inserts the
1167      * vulnerability entry itself.
1168      *
1169      * @param cve the CVE data
1170      * @param description the description of the CVE entry
1171      * @return the vulnerability ID
1172      */
1173     private int updateOrInsertVulnerability(DefCveItem cve, String description) {
1174         if (CpeEcosystemCache.isEmpty()) {
1175             loadCpeEcosystemCache();
1176         }
1177         final int vulnerabilityId;
1178         try (Connection conn = databaseManager.getConnection(); PreparedStatement callUpdate = getPreparedStatement(conn, UPDATE_VULNERABILITY)) {
1179 //            String 1.cve, String 2.description, String 3.v2Severity, Float 4.v2ExploitabilityScore,
1180 //            Float 5.v2ImpactScore, Boolean 6.v2AcInsufInfo, Boolean 7.v2ObtainAllPrivilege,
1181 //            Boolean 8.v2ObtainUserPrivilege, Boolean 9.v2ObtainOtherPrivilege, Boolean 10.v2UserInteractionRequired,
1182 //            Float 11.v2Score, String 12.v2AccessVector, String 13.v2AccessComplexity,
1183 //            String 14.v2Authentication, String 15.v2ConfidentialityImpact, String 16.v2IntegrityImpact,
1184 //            String 17.v2AvailabilityImpact, String 18.v2Version, Float 19.v3ExploitabilityScore,
1185 //            Float 20.v3ImpactScore, String 21.v3AttackVector, String 22.v3AttackComplexity,
1186 //            String 23.v3PrivilegesRequired, String 24.v3UserInteraction, String 25.v3Scope,
1187 //            String 26.v3ConfidentialityImpact, String 27.v3IntegrityImpact, String 28.v3AvailabilityImpact,
1188 //            Float 29.v3BaseScore, String 30.v3BaseSeverity, String 31.v3Version
1189 // .          String 32.v4version, String 33.v4attackVector, String 34.v4attackComplexity, String 35.v4attackRequirements,
1190 //            String 36.v4privilegesRequired, String 37.v4userInteraction, String 38.v4vulnConfidentialityImpact,
1191 //            String 39.v4vulnIntegrityImpact, String 40.v4vulnAvailabilityImpact, String 41.v4subConfidentialityImpact,
1192 //            String 42.v4subIntegrityImpact, String 43.v4subAvailabilityImpact, String 44.v4exploitMaturity,
1193 //            String 45.v4confidentialityRequirement, String 46.v4integrityRequirement, String 47.v4availabilityRequirement,
1194 //            String 48.v4modifiedAttackVector, String 49.v4modifiedAttackComplexity, String 50.v4modifiedAttackRequirements,
1195 //            String 51.v4modifiedPrivilegesRequired, String 52.v4modifiedUserInteraction, String 53.v4modifiedVulnConfidentialityImpact,
1196 //            String 54.v4modifiedVulnIntegrityImpact, String 55.v4modifiedVulnAvailabilityImpact, String 56.v4modifiedSubConfidentialityImpact,
1197 //            String 57.v4modifiedSubIntegrityImpact, String 58.v4modifiedSubAvailabilityImpact, String 59.v4safety,
1198 //            String 60.v4automatable, String 61.v4recovery, String 62.v4valueDensity, String 63.v4vulnerabilityResponseEffort,
1199 //            String 64.v4providerUrgency, Float 65.v4baseScore, String 66.v4baseSeverity, Float 67.v4threatScore,
1200 //            String 68.v4threatSeverity, Float 69.v4environmentalScore, String 70.v4environmentalSeverity
1201 // .          String 71.v4Source, String 72.v4type
1202             callUpdate.setString(1, cve.getCve().getId());
1203             callUpdate.setString(2, description);
1204             Optional<CvssV2> optCvssv2 = null;
1205             if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV2() != null) {
1206                 optCvssv2 = cve.getCve().getMetrics().getCvssMetricV2().stream().sorted(Comparator.comparing(CvssV2::getType)).findFirst();
1207             }
1208             if (optCvssv2 != null && optCvssv2.isPresent()) {
1209                 final CvssV2 cvssv2 = optCvssv2.get();
1210                 setUpdateColumn(callUpdate, 3, cvssv2.getBaseSeverity());
1211                 setUpdateColumn(callUpdate, 4, cvssv2.getExploitabilityScore());
1212                 setUpdateColumn(callUpdate, 5, cvssv2.getImpactScore());
1213                 setUpdateColumn(callUpdate, 6, cvssv2.getAcInsufInfo());
1214                 setUpdateColumn(callUpdate, 7, cvssv2.getObtainAllPrivilege());
1215                 setUpdateColumn(callUpdate, 8, cvssv2.getObtainUserPrivilege());
1216                 setUpdateColumn(callUpdate, 9, cvssv2.getObtainOtherPrivilege());
1217                 setUpdateColumn(callUpdate, 10, cvssv2.getUserInteractionRequired());
1218                 setUpdateColumn(callUpdate, 11, cvssv2.getCvssData().getBaseScore());
1219                 setUpdateColumn(callUpdate, 12, cvssv2.getCvssData().getAccessVector());
1220                 setUpdateColumn(callUpdate, 13, cvssv2.getCvssData().getAccessComplexity());
1221                 setUpdateColumn(callUpdate, 14, cvssv2.getCvssData().getAuthentication());
1222                 setUpdateColumn(callUpdate, 15, cvssv2.getCvssData().getConfidentialityImpact());
1223                 setUpdateColumn(callUpdate, 16, cvssv2.getCvssData().getIntegrityImpact());
1224                 setUpdateColumn(callUpdate, 17, cvssv2.getCvssData().getAvailabilityImpact());
1225                 setUpdateColumn(callUpdate, 18, cvssv2.getCvssData().getVersion());
1226             } else {
1227                 callUpdate.setNull(3, java.sql.Types.VARCHAR);
1228                 callUpdate.setNull(4, java.sql.Types.DOUBLE);
1229                 callUpdate.setNull(5, java.sql.Types.DOUBLE);
1230                 callUpdate.setNull(6, java.sql.Types.VARCHAR);
1231                 //TODO this is may also be an issue for MS SQL, if an issue is created we'll just need
1232                 // to create an isMsSQL flag. See todo below in setUpdateColum
1233                 if (isOracle) {
1234                     callUpdate.setNull(7, java.sql.Types.BIT);
1235                     callUpdate.setNull(8, java.sql.Types.BIT);
1236                     callUpdate.setNull(9, java.sql.Types.BIT);
1237                     callUpdate.setNull(10, java.sql.Types.BIT);
1238                 } else {
1239                     callUpdate.setNull(7, java.sql.Types.BOOLEAN);
1240                     callUpdate.setNull(8, java.sql.Types.BOOLEAN);
1241                     callUpdate.setNull(9, java.sql.Types.BOOLEAN);
1242                     callUpdate.setNull(10, java.sql.Types.BOOLEAN);
1243                 }
1244                 callUpdate.setNull(11, java.sql.Types.DOUBLE);
1245                 callUpdate.setNull(12, java.sql.Types.VARCHAR);
1246                 callUpdate.setNull(13, java.sql.Types.VARCHAR);
1247                 callUpdate.setNull(14, java.sql.Types.VARCHAR);
1248                 callUpdate.setNull(15, java.sql.Types.VARCHAR);
1249                 callUpdate.setNull(16, java.sql.Types.VARCHAR);
1250                 callUpdate.setNull(17, java.sql.Types.VARCHAR);
1251                 callUpdate.setNull(18, java.sql.Types.VARCHAR);
1252             }
1253             Optional<CvssV3> optCvssv30 = Optional.empty();
1254             if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV30() != null) {
1255                 optCvssv30 = cve.getCve().getMetrics().getCvssMetricV30().stream().sorted(Comparator.comparing(CvssV3::getType)).findFirst();
1256             }
1257             Optional<CvssV3> optCvssv31 = Optional.empty();
1258             if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV31() != null) {
1259                 optCvssv31 = cve.getCve().getMetrics().getCvssMetricV31().stream().sorted(Comparator.comparing(CvssV3::getType)).findFirst();
1260             }
1261 
1262             CvssV3 cvssv3 = null;
1263             if (optCvssv31.isPresent()) {
1264                 cvssv3 = optCvssv31.get();
1265             } else if (optCvssv30.isPresent()) {
1266                 cvssv3 = optCvssv30.get();
1267             }
1268             if (cvssv3 != null) {
1269                 setUpdateColumn(callUpdate, 19, cvssv3.getExploitabilityScore());
1270                 setUpdateColumn(callUpdate, 20, cvssv3.getImpactScore());
1271                 setUpdateColumn(callUpdate, 21, cvssv3.getCvssData().getAttackVector());
1272                 setUpdateColumn(callUpdate, 22, cvssv3.getCvssData().getAttackComplexity());
1273                 setUpdateColumn(callUpdate, 23, cvssv3.getCvssData().getPrivilegesRequired());
1274                 setUpdateColumn(callUpdate, 24, cvssv3.getCvssData().getUserInteraction());
1275                 setUpdateColumn(callUpdate, 25, cvssv3.getCvssData().getScope());
1276                 setUpdateColumn(callUpdate, 26, cvssv3.getCvssData().getConfidentialityImpact());
1277                 setUpdateColumn(callUpdate, 27, cvssv3.getCvssData().getIntegrityImpact());
1278                 setUpdateColumn(callUpdate, 28, cvssv3.getCvssData().getAvailabilityImpact());
1279                 setUpdateColumn(callUpdate, 29, cvssv3.getCvssData().getBaseScore());
1280                 setUpdateColumn(callUpdate, 30, cvssv3.getCvssData().getBaseSeverity());
1281                 setUpdateColumn(callUpdate, 31, cvssv3.getCvssData().getVersion());
1282             } else {
1283                 callUpdate.setNull(19, java.sql.Types.DOUBLE);
1284                 callUpdate.setNull(20, java.sql.Types.DOUBLE);
1285                 callUpdate.setNull(21, java.sql.Types.VARCHAR);
1286                 callUpdate.setNull(22, java.sql.Types.VARCHAR);
1287                 callUpdate.setNull(23, java.sql.Types.VARCHAR);
1288                 callUpdate.setNull(24, java.sql.Types.VARCHAR);
1289                 callUpdate.setNull(25, java.sql.Types.VARCHAR);
1290                 callUpdate.setNull(26, java.sql.Types.VARCHAR);
1291                 callUpdate.setNull(27, java.sql.Types.VARCHAR);
1292                 callUpdate.setNull(28, java.sql.Types.VARCHAR);
1293                 callUpdate.setNull(29, java.sql.Types.DOUBLE);
1294                 callUpdate.setNull(30, java.sql.Types.VARCHAR);
1295                 callUpdate.setNull(31, java.sql.Types.VARCHAR);
1296             }
1297 
1298             Optional<CvssV4> optCvssv4 = null;
1299             if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV40() != null) {
1300                 optCvssv4 = cve.getCve().getMetrics().getCvssMetricV40().stream().sorted(Comparator.comparing(CvssV4::getType)).findFirst();
1301             }
1302             if (optCvssv4 != null && optCvssv4.isPresent()) {
1303                 final CvssV4 cvssv4 = optCvssv4.get();
1304                 setUpdateColumn(callUpdate, 32, cvssv4.getCvssData().getVersion());
1305                 setUpdateColumn(callUpdate, 33, cvssv4.getCvssData().getAttackVector());
1306                 setUpdateColumn(callUpdate, 34, cvssv4.getCvssData().getAttackComplexity());
1307                 setUpdateColumn(callUpdate, 35, cvssv4.getCvssData().getAttackRequirements());
1308                 setUpdateColumn(callUpdate, 36, cvssv4.getCvssData().getPrivilegesRequired());
1309                 setUpdateColumn(callUpdate, 37, cvssv4.getCvssData().getUserInteraction());
1310                 setUpdateColumn(callUpdate, 38, cvssv4.getCvssData().getVulnConfidentialityImpact());
1311                 setUpdateColumn(callUpdate, 39, cvssv4.getCvssData().getVulnIntegrityImpact());
1312                 setUpdateColumn(callUpdate, 40, cvssv4.getCvssData().getVulnAvailabilityImpact());
1313                 setUpdateColumn(callUpdate, 41, cvssv4.getCvssData().getSubConfidentialityImpact());
1314                 setUpdateColumn(callUpdate, 42, cvssv4.getCvssData().getSubIntegrityImpact());
1315                 setUpdateColumn(callUpdate, 43, cvssv4.getCvssData().getSubAvailabilityImpact());
1316                 setUpdateColumn(callUpdate, 44, cvssv4.getCvssData().getExploitMaturity());
1317                 setUpdateColumn(callUpdate, 45, cvssv4.getCvssData().getConfidentialityRequirement());
1318                 setUpdateColumn(callUpdate, 46, cvssv4.getCvssData().getIntegrityRequirement());
1319                 setUpdateColumn(callUpdate, 47, cvssv4.getCvssData().getAvailabilityRequirement());
1320                 setUpdateColumn(callUpdate, 48, cvssv4.getCvssData().getModifiedAttackVector());
1321                 setUpdateColumn(callUpdate, 49, cvssv4.getCvssData().getModifiedAttackComplexity());
1322                 setUpdateColumn(callUpdate, 50, cvssv4.getCvssData().getModifiedAttackRequirements());
1323                 setUpdateColumn(callUpdate, 51, cvssv4.getCvssData().getModifiedPrivilegesRequired());
1324                 setUpdateColumn(callUpdate, 52, cvssv4.getCvssData().getModifiedUserInteraction());
1325                 setUpdateColumn(callUpdate, 53, cvssv4.getCvssData().getModifiedVulnConfidentialityImpact());
1326                 setUpdateColumn(callUpdate, 54, cvssv4.getCvssData().getModifiedVulnIntegrityImpact());
1327                 setUpdateColumn(callUpdate, 55, cvssv4.getCvssData().getModifiedVulnAvailabilityImpact());
1328                 setUpdateColumn(callUpdate, 56, cvssv4.getCvssData().getModifiedSubConfidentialityImpact());
1329                 setUpdateColumn(callUpdate, 57, cvssv4.getCvssData().getModifiedSubIntegrityImpact());
1330                 setUpdateColumn(callUpdate, 58, cvssv4.getCvssData().getModifiedSubAvailabilityImpact());
1331                 setUpdateColumn(callUpdate, 59, cvssv4.getCvssData().getSafety());
1332                 setUpdateColumn(callUpdate, 60, cvssv4.getCvssData().getAutomatable());
1333                 setUpdateColumn(callUpdate, 61, cvssv4.getCvssData().getRecovery());
1334                 setUpdateColumn(callUpdate, 62, cvssv4.getCvssData().getValueDensity());
1335                 setUpdateColumn(callUpdate, 63, cvssv4.getCvssData().getVulnerabilityResponseEffort());
1336                 setUpdateColumn(callUpdate, 64, cvssv4.getCvssData().getProviderUrgency());
1337                 setUpdateColumn(callUpdate, 65, cvssv4.getCvssData().getBaseScore());
1338                 setUpdateColumn(callUpdate, 66, cvssv4.getCvssData().getBaseSeverity());
1339                 setUpdateColumn(callUpdate, 67, cvssv4.getCvssData().getThreatScore());
1340                 setUpdateColumn(callUpdate, 68, cvssv4.getCvssData().getThreatSeverity());
1341                 setUpdateColumn(callUpdate, 69, cvssv4.getCvssData().getEnvironmentalScore());
1342                 setUpdateColumn(callUpdate, 70, cvssv4.getCvssData().getEnvironmentalSeverity());
1343                 setUpdateColumn(callUpdate, 71, cvssv4.getSource());
1344                 setUpdateColumn(callUpdate, 72, cvssv4.getType());
1345             } else {
1346                 callUpdate.setNull(32, java.sql.Types.VARCHAR);
1347                 callUpdate.setNull(33, java.sql.Types.VARCHAR);
1348                 callUpdate.setNull(34, java.sql.Types.VARCHAR);
1349                 callUpdate.setNull(35, java.sql.Types.VARCHAR);
1350                 callUpdate.setNull(36, java.sql.Types.VARCHAR);
1351                 callUpdate.setNull(37, java.sql.Types.VARCHAR);
1352                 callUpdate.setNull(38, java.sql.Types.VARCHAR);
1353                 callUpdate.setNull(39, java.sql.Types.VARCHAR);
1354                 callUpdate.setNull(40, java.sql.Types.VARCHAR);
1355                 callUpdate.setNull(41, java.sql.Types.VARCHAR);
1356                 callUpdate.setNull(42, java.sql.Types.VARCHAR);
1357                 callUpdate.setNull(43, java.sql.Types.VARCHAR);
1358                 callUpdate.setNull(44, java.sql.Types.VARCHAR);
1359                 callUpdate.setNull(45, java.sql.Types.VARCHAR);
1360                 callUpdate.setNull(46, java.sql.Types.VARCHAR);
1361                 callUpdate.setNull(47, java.sql.Types.VARCHAR);
1362                 callUpdate.setNull(48, java.sql.Types.VARCHAR);
1363                 callUpdate.setNull(49, java.sql.Types.VARCHAR);
1364                 callUpdate.setNull(50, java.sql.Types.VARCHAR);
1365                 callUpdate.setNull(51, java.sql.Types.VARCHAR);
1366                 callUpdate.setNull(52, java.sql.Types.VARCHAR);
1367                 callUpdate.setNull(53, java.sql.Types.VARCHAR);
1368                 callUpdate.setNull(54, java.sql.Types.VARCHAR);
1369                 callUpdate.setNull(55, java.sql.Types.VARCHAR);
1370                 callUpdate.setNull(56, java.sql.Types.VARCHAR);
1371                 callUpdate.setNull(57, java.sql.Types.VARCHAR);
1372                 callUpdate.setNull(58, java.sql.Types.VARCHAR);
1373                 callUpdate.setNull(59, java.sql.Types.VARCHAR);
1374                 callUpdate.setNull(60, java.sql.Types.VARCHAR);
1375                 callUpdate.setNull(61, java.sql.Types.VARCHAR);
1376                 callUpdate.setNull(62, java.sql.Types.VARCHAR);
1377                 callUpdate.setNull(63, java.sql.Types.VARCHAR);
1378                 callUpdate.setNull(64, java.sql.Types.VARCHAR);
1379                 callUpdate.setNull(65, java.sql.Types.DOUBLE);
1380                 callUpdate.setNull(66, java.sql.Types.VARCHAR);
1381                 callUpdate.setNull(67, java.sql.Types.DOUBLE);
1382                 callUpdate.setNull(68, java.sql.Types.VARCHAR);
1383                 callUpdate.setNull(69, java.sql.Types.DOUBLE);
1384                 callUpdate.setNull(70, java.sql.Types.VARCHAR);
1385                 callUpdate.setNull(71, java.sql.Types.VARCHAR);
1386                 callUpdate.setNull(72, java.sql.Types.VARCHAR);
1387             }
1388             if (isOracle) {
1389                 try {
1390                     final CallableStatement cs = (CallableStatement) callUpdate;
1391                     cs.registerOutParameter(73, JDBCType.INTEGER);
1392                     cs.executeUpdate();
1393                     vulnerabilityId = cs.getInt(73);
1394                 } catch (SQLException ex) {
1395                     final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", cve.getCve().getId());
1396                     throw new DatabaseException(msg, ex);
1397                 }
1398             } else {
1399                 try (ResultSet rs = callUpdate.executeQuery()) {
1400                     rs.next();
1401                     vulnerabilityId = rs.getInt(1);
1402                 } catch (SQLException ex) {
1403                     final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", cve.getCve().getId());
1404                     throw new DatabaseException(msg, ex);
1405                 }
1406             }
1407         } catch (SQLException ex) {
1408             throw new UnexpectedAnalysisException(ex);
1409         }
1410         return vulnerabilityId;
1411     }
1412 
1413     /**
1414      * Used when updating a vulnerability - this method inserts the CWE entries.
1415      *
1416      * @param vulnerabilityId the vulnerability ID
1417      * @param cve the CVE entry that contains the CWE entries to insert
1418      * @throws SQLException thrown if there is an error inserting the data
1419      */
1420     private void updateVulnerabilityInsertCwe(int vulnerabilityId, DefCveItem cve) throws SQLException {
1421         if (cve.getCve() != null && cve.getCve().getWeaknesses() != null) {
1422             try (Connection conn = databaseManager.getConnection();
1423                     PreparedStatement insertCWE = getPreparedStatement(conn, INSERT_CWE, vulnerabilityId)) {
1424                 for (Weakness weakness : cve.getCve().getWeaknesses()) {
1425                     for (LangString desc : weakness.getDescription()) {
1426                         if ("en".equals(desc.getLang())) {
1427                             insertCWE.setString(2, desc.getValue());
1428                             if (isBatchInsertEnabled()) {
1429                                 insertCWE.addBatch();
1430                             } else {
1431                                 insertCWE.execute();
1432                             }
1433                         }
1434                     }
1435                 }
1436                 if (isBatchInsertEnabled()) {
1437                     insertCWE.executeBatch();
1438                 }
1439             }
1440         }
1441     }
1442 
1443     /**
1444      * Used when updating a vulnerability - in some cases a CVE needs to be
1445      * removed.
1446      *
1447      * @param cve the vulnerability CVE
1448      * @throws SQLException thrown if there is an error deleting the
1449      * vulnerability
1450      */
1451     private void deleteVulnerability(String cve) throws SQLException {
1452         try (Connection conn = databaseManager.getConnection();
1453                 PreparedStatement deleteVulnerability = getPreparedStatement(conn, DELETE_VULNERABILITY, cve)) {
1454             deleteVulnerability.executeUpdate();
1455         }
1456     }
1457 
1458     /**
1459      * Merges the list of known exploited vulnerabilities into the database.
1460      *
1461      * @param vulnerabilities the list of known exploited vulnerabilities
1462      * @throws DatabaseException thrown if there is an exception... duh..
1463      * @throws SQLException thrown if there is an exception... duh..
1464      */
1465     public void updateKnownExploitedVulnerabilities(
1466             List<org.owasp.dependencycheck.data.knownexploited.json.Vulnerability> vulnerabilities)
1467             throws DatabaseException, SQLException {
1468         try (Connection conn = databaseManager.getConnection();
1469                 PreparedStatement mergeKnownVulnerability = getPreparedStatement(conn, MERGE_KNOWN_EXPLOITED)) {
1470             int ctr = 0;
1471             for (org.owasp.dependencycheck.data.knownexploited.json.Vulnerability v : vulnerabilities) {
1472                 mergeKnownVulnerability.setString(1, v.getCveID());
1473                 addNullableStringParameter(mergeKnownVulnerability, 2, v.getVendorProject());
1474                 addNullableStringParameter(mergeKnownVulnerability, 3, v.getProduct());
1475                 addNullableStringParameter(mergeKnownVulnerability, 4, v.getVulnerabilityName());
1476                 addNullableStringParameter(mergeKnownVulnerability, 5, v.getDateAdded());
1477                 addNullableStringParameter(mergeKnownVulnerability, 6, v.getShortDescription());
1478                 addNullableStringParameter(mergeKnownVulnerability, 7, v.getRequiredAction());
1479                 addNullableStringParameter(mergeKnownVulnerability, 8, v.getDueDate());
1480                 addNullableStringParameter(mergeKnownVulnerability, 9, v.getNotes());
1481                 if (isBatchInsertEnabled()) {
1482                     mergeKnownVulnerability.addBatch();
1483                     ctr++;
1484                     if (ctr >= getBatchSize()) {
1485                         mergeKnownVulnerability.executeBatch();
1486                         ctr = 0;
1487                     }
1488                 } else {
1489                     try {
1490                         mergeKnownVulnerability.execute();
1491                     } catch (SQLException ex) {
1492                         if (ex.getMessage().contains("Duplicate entry")) {
1493                             final String msg = String.format("Duplicate known exploited vulnerability key identified in '%s'", v.getCveID());
1494                             LOGGER.info(msg, ex);
1495                         } else {
1496                             throw ex;
1497                         }
1498                     }
1499                 }
1500             }
1501             if (isBatchInsertEnabled()) {
1502                 mergeKnownVulnerability.executeBatch();
1503             }
1504         }
1505     }
1506 
1507     /**
1508      * Used when updating a vulnerability - this method inserts the list of
1509      * vulnerable software.
1510      *
1511      * @param vulnerabilityId the vulnerability id
1512      * @param cveId the CVE ID - used for reporting
1513      * @param software the list of vulnerable software
1514      * @param baseEcosystem the ecosystem based off of the vulnerability
1515      * description
1516      * @throws DatabaseException thrown if there is an error inserting the data
1517      * @throws SQLException thrown if there is an error inserting the data
1518      */
1519     private void updateVulnerabilityInsertSoftware(int vulnerabilityId, String cveId,
1520             List<VulnerableSoftware> software, String baseEcosystem)
1521             throws DatabaseException, SQLException {
1522         try (Connection conn = databaseManager.getConnection(); PreparedStatement insertSoftware = getPreparedStatement(conn, INSERT_SOFTWARE)) {
1523             for (VulnerableSoftware parsedCpe : software) {
1524                 insertSoftware.setInt(1, vulnerabilityId);
1525                 insertSoftware.setString(2, parsedCpe.getPart().getAbbreviation());
1526                 insertSoftware.setString(3, parsedCpe.getVendor());
1527                 insertSoftware.setString(4, parsedCpe.getProduct());
1528                 insertSoftware.setString(5, parsedCpe.getVersion());
1529                 insertSoftware.setString(6, parsedCpe.getUpdate());
1530                 insertSoftware.setString(7, parsedCpe.getEdition());
1531                 insertSoftware.setString(8, parsedCpe.getLanguage());
1532                 insertSoftware.setString(9, parsedCpe.getSwEdition());
1533                 insertSoftware.setString(10, parsedCpe.getTargetSw());
1534                 insertSoftware.setString(11, parsedCpe.getTargetHw());
1535                 insertSoftware.setString(12, parsedCpe.getOther());
1536                 final String ecosystem = CpeEcosystemCache.getEcosystem(parsedCpe.getVendor(), parsedCpe.getProduct(),
1537                         cveItemConverter.extractEcosystem(baseEcosystem, parsedCpe));
1538 
1539                 addNullableStringParameter(insertSoftware, 13, ecosystem);
1540                 addNullableStringParameter(insertSoftware, 14, parsedCpe.getVersionEndExcluding());
1541                 addNullableStringParameter(insertSoftware, 15, parsedCpe.getVersionEndIncluding());
1542                 addNullableStringParameter(insertSoftware, 16, parsedCpe.getVersionStartExcluding());
1543                 addNullableStringParameter(insertSoftware, 17, parsedCpe.getVersionStartIncluding());
1544                 insertSoftware.setBoolean(18, parsedCpe.isVulnerable());
1545 
1546                 if (isBatchInsertEnabled()) {
1547                     insertSoftware.addBatch();
1548                 } else {
1549                     try {
1550                         insertSoftware.execute();
1551                     } catch (SQLException ex) {
1552                         if (ex.getMessage().contains("Duplicate entry")) {
1553                             final String msg = String.format("Duplicate software key identified in '%s'", cveId);
1554                             LOGGER.info(msg, ex);
1555                         } else {
1556                             throw ex;
1557                         }
1558                     }
1559                 }
1560             }
1561             if (isBatchInsertEnabled()) {
1562                 executeBatch(cveId, insertSoftware);
1563             }
1564         }
1565     }
1566 
1567     /**
1568      * Used when updating a vulnerability - this method inserts the list of
1569      * references.
1570      *
1571      * @param vulnerabilityId the vulnerability id
1572      * @param cve the CVE entry that contains the list of references
1573      * @throws SQLException thrown if there is an error inserting the data
1574      */
1575     private void updateVulnerabilityInsertReferences(int vulnerabilityId, DefCveItem cve) throws SQLException {
1576         try (Connection conn = databaseManager.getConnection(); PreparedStatement insertReference = getPreparedStatement(conn, INSERT_REFERENCE)) {
1577             if (cve.getCve().getReferences() != null) {
1578                 for (Reference r : cve.getCve().getReferences()) {
1579                     insertReference.setInt(1, vulnerabilityId);
1580                     String name = null;
1581                     if (r.getTags() != null) {
1582                         name = r.getTags().stream().sorted().collect(Collectors.joining(",")).toUpperCase().replaceAll("\\s", "_");
1583                     }
1584                     if (name != null) {
1585                         insertReference.setString(2, name);
1586                     } else {
1587                         insertReference.setNull(2, java.sql.Types.VARCHAR);
1588                     }
1589                     if (r.getUrl() != null && !r.getUrl().isEmpty()) {
1590                         insertReference.setString(3, r.getUrl());
1591                     } else {
1592                         insertReference.setNull(3, java.sql.Types.VARCHAR);
1593                     }
1594                     if (r.getSource() != null && !r.getSource().isEmpty()) {
1595                         insertReference.setString(4, r.getSource());
1596                     } else {
1597                         insertReference.setNull(4, java.sql.Types.VARCHAR);
1598                     }
1599                     if (isBatchInsertEnabled()) {
1600                         insertReference.addBatch();
1601                     } else {
1602                         insertReference.execute();
1603                     }
1604                 }
1605             }
1606             if (isBatchInsertEnabled()) {
1607                 insertReference.executeBatch();
1608             }
1609         }
1610     }
1611 
1612     /**
1613      * Parses the configuration entries from the CVE entry into a list of
1614      * VulnerableSoftware objects.
1615      *
1616      * @param cve the CVE to parse the vulnerable software entries from
1617      * @return the list of vulnerable software
1618      * @throws CpeValidationException if an invalid CPE is present
1619      */
1620     private List<VulnerableSoftware> parseCpes(DefCveItem cve) throws CpeValidationException {
1621         final List<VulnerableSoftware> software = new ArrayList<>();
1622 
1623         final List<CpeMatch> cpeEntries = cve.getCve().getConfigurations().stream()
1624                 .filter(config -> config.getNodes() != null)
1625                 .map(Config::getNodes)
1626                 .flatMap(List::stream)
1627                 .map(Node::getCpeMatch)
1628                 .flatMap(List::stream)
1629                 .filter(predicate -> predicate.getCriteria() != null)
1630                 .filter(predicate -> predicate.getCriteria().startsWith(cpeStartsWithFilter))
1631                 //this single CPE entry causes nearly 100% FP - so filtering it at the source.
1632                 .filter(entry -> !("CVE-2009-0754".equals(cve.getCve().getId())
1633                 && "cpe:2.3:a:apache:apache:*:*:*:*:*:*:*:*".equals(entry.getCriteria())))
1634                 .collect(Collectors.toList());
1635         final VulnerableSoftwareBuilder builder = new VulnerableSoftwareBuilder();
1636 
1637         try {
1638             cpeEntries.forEach(entry -> {
1639                 builder.cpe(parseCpe(entry, cve.getCve().getId()))
1640                         .versionEndExcluding(entry.getVersionEndExcluding())
1641                         .versionStartExcluding(entry.getVersionStartExcluding())
1642                         .versionEndIncluding(entry.getVersionEndIncluding())
1643                         .versionStartIncluding(entry.getVersionStartIncluding())
1644                         .vulnerable(entry.getVulnerable());
1645                 try {
1646                     software.add(builder.build());
1647                 } catch (CpeValidationException ex) {
1648                     throw new LambdaExceptionWrapper(ex);
1649                 }
1650             });
1651         } catch (LambdaExceptionWrapper ex) {
1652             throw (CpeValidationException) ex.getCause();
1653         }
1654         return software;
1655     }
1656 
1657     /**
1658      * Helper method to convert a CpeMatch (generated code used in parsing the
1659      * NVD JSON) into a CPE object.
1660      *
1661      * @param cpe the CPE Match
1662      * @param cveId the CVE associated with the CPEMatch - used for error
1663      * reporting
1664      * @return the resulting CPE object
1665      * @throws DatabaseException thrown if there is an error converting the
1666      * CpeMatch into a CPE object
1667      */
1668     private Cpe parseCpe(CpeMatch cpe, String cveId) throws DatabaseException {
1669         final Cpe parsedCpe;
1670         try {
1671             //the replace is a hack as the NVD does not properly escape backslashes in their JSON
1672             parsedCpe = CpeParser.parse(cpe.getCriteria(), true);
1673         } catch (CpeParsingException ex) {
1674             LOGGER.debug("NVD (" + cveId + ") contain an invalid 2.3 CPE: " + cpe.getCriteria());
1675             throw new DatabaseException("Unable to parse CPE: " + cpe.getCriteria(), ex);
1676         }
1677         return parsedCpe;
1678     }
1679 
1680     /**
1681      * Returns the size of the batch.
1682      *
1683      * @return the size of the batch
1684      */
1685     private int getBatchSize() {
1686         int max;
1687         try {
1688             max = settings.getInt(Settings.KEYS.MAX_BATCH_SIZE);
1689         } catch (InvalidSettingException pE) {
1690             max = 1000;
1691         }
1692         return max;
1693     }
1694 
1695     /**
1696      * Determines whether or not batch insert is enabled.
1697      *
1698      * @return <code>true</code> if batch insert is enabled; otherwise
1699      * <code>false</code>
1700      */
1701     private boolean isBatchInsertEnabled() {
1702         boolean batch;
1703         try {
1704             batch = settings.getBoolean(Settings.KEYS.ENABLE_BATCH_UPDATES);
1705         } catch (InvalidSettingException pE) {
1706             //If there's no configuration, default is to not perform batch inserts
1707             batch = false;
1708         }
1709         return batch;
1710     }
1711 
1712     /**
1713      * Executes batch inserts of vulnerabilities when property
1714      * database.batchinsert.maxsize is reached.
1715      *
1716      * @param vulnId the vulnerability ID
1717      * @param statement the prepared statement to batch execute
1718      * @throws SQLException thrown when the batch cannot be executed
1719      */
1720     private void executeBatch(String vulnId, PreparedStatement statement)
1721             throws SQLException {
1722         try {
1723             statement.executeBatch();
1724         } catch (SQLException ex) {
1725             if (ex.getMessage().contains("Duplicate entry")) {
1726                 final String msg = String.format("Duplicate software key identified in '%s'",
1727                         vulnId);
1728                 LOGGER.info(msg, ex);
1729             } else {
1730                 throw ex;
1731             }
1732         }
1733     }
1734 
1735     /**
1736      * Checks to see if data exists so that analysis can be performed.
1737      *
1738      * @return <code>true</code> if data exists; otherwise <code>false</code>
1739      */
1740     public boolean dataExists() {
1741         try (Connection conn = databaseManager.getConnection();
1742                 PreparedStatement cs = getPreparedStatement(conn, COUNT_CPE);
1743                 ResultSet rs = cs.executeQuery()) {
1744             if (rs.next() && rs.getInt(1) > 0) {
1745                 return true;
1746             }
1747         } catch (Exception ex) {
1748             String dd;
1749             try {
1750                 dd = settings.getDataDirectory().getAbsolutePath();
1751             } catch (IOException ex1) {
1752                 dd = settings.getString(Settings.KEYS.DATA_DIRECTORY);
1753             }
1754             LOGGER.error("Unable to access the local database.\n\nEnsure that '{}' is a writable directory. "
1755                     + "If the problem persist try deleting the files in '{}' and running {} again. If the problem continues, please "
1756                     + "create a log file (see documentation at https://dependency-check.github.io/DependencyCheck/) and open a ticket at "
1757                     + "https://github.com/dependency-check/DependencyCheck/issues and include the log file.\n\n",
1758                     dd, dd, settings.getString(Settings.KEYS.APPLICATION_NAME));
1759             LOGGER.debug("", ex);
1760         }
1761         return false;
1762     }
1763 
1764     /**
1765      * It is possible that orphaned rows may be generated during database
1766      * updates. This should be called after all updates have been completed to
1767      * ensure orphan entries are removed.
1768      */
1769     public void cleanupDatabase() {
1770         LOGGER.info("Begin database maintenance");
1771         final long start = System.currentTimeMillis();
1772         try (Connection conn = databaseManager.getConnection();
1773                 PreparedStatement psOrphans = getPreparedStatement(conn, CLEANUP_ORPHANS);
1774                 PreparedStatement psEcosystem = getPreparedStatement(conn, UPDATE_ECOSYSTEM);
1775                 PreparedStatement psEcosystem2 = getPreparedStatement(conn, UPDATE_ECOSYSTEM2)) {
1776             if (psEcosystem != null) {
1777                 final int count = psEcosystem.executeUpdate();
1778                 if (count > 0) {
1779                     LOGGER.info("Updated the CPE ecosystem on {} NVD records", count);
1780                 }
1781             }
1782             if (psEcosystem2 != null) {
1783                 final int count = psEcosystem2.executeUpdate();
1784                 if (count > 0) {
1785                     LOGGER.info("Removed the CPE ecosystem on {} NVD records", count);
1786                 }
1787             }
1788             if (psOrphans != null) {
1789                 final int count = psOrphans.executeUpdate();
1790                 if (count > 0) {
1791                     LOGGER.info("Cleaned up {} orphaned NVD records", count);
1792                 }
1793             }
1794             final long millis = System.currentTimeMillis() - start;
1795             //final long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
1796             LOGGER.info("End database maintenance ({} ms)", millis);
1797         } catch (SQLException ex) {
1798             LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
1799             LOGGER.debug("", ex);
1800             throw new DatabaseException("Unexpected SQL Exception", ex);
1801         }
1802     }
1803 
1804     /**
1805      * Persist the EcosystemCache into the database.
1806      */
1807     public void persistEcosystemCache() {
1808         saveCpeEcosystemCache();
1809         clearCache();
1810     }
1811 
1812     /**
1813      * If the database is using an H2 file based database calling
1814      * <code>defrag()</code> will de-fragment the database.
1815      */
1816     public void defrag() {
1817         if (isH2) {
1818             final long start = System.currentTimeMillis();
1819             try (Connection conn = databaseManager.getConnection(); CallableStatement psCompaxt = conn.prepareCall("SHUTDOWN DEFRAG")) {
1820                 LOGGER.info("Begin database defrag");
1821                 psCompaxt.execute();
1822                 final long millis = System.currentTimeMillis() - start;
1823                 //final long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
1824                 LOGGER.info("End database defrag ({} ms)", millis);
1825             } catch (SQLException ex) {
1826                 LOGGER.error("An unexpected SQL Exception occurred compacting the database; please see the verbose log for more details.");
1827                 LOGGER.debug("", ex);
1828             }
1829         }
1830     }
1831 
1832     /**
1833      * Determines if the given identifiedVersion is affected by the given cpeId
1834      * and previous version flag. A non-null, non-empty string passed to the
1835      * previous version argument indicates that all previous versions are
1836      * affected.
1837      *
1838      * @param cpe the CPE for the given dependency
1839      * @param vulnerableSoftware a set of the vulnerable software
1840      * @return true if the identified version is affected, otherwise false
1841      */
1842     VulnerableSoftware getMatchingSoftware(Cpe cpe, Set<VulnerableSoftware> vulnerableSoftware) {
1843         VulnerableSoftware matched = null;
1844         for (VulnerableSoftware vs : vulnerableSoftware) {
1845             if (vs.matches(cpe)) {
1846                 if (matched == null) {
1847                     matched = vs;
1848                 } else {
1849                     if ("*".equals(vs.getWellFormedUpdate()) && !"*".equals(matched.getWellFormedUpdate())) {
1850                         matched = vs;
1851                     }
1852                 }
1853             }
1854         }
1855         return matched;
1856     }
1857 
1858     /**
1859      * This method is only referenced in unused code.
1860      * <p>
1861      * Deletes unused dictionary entries from the database.
1862      * </p>
1863      */
1864     public void deleteUnusedCpe() {
1865         clearCache();
1866         try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, DELETE_UNUSED_DICT_CPE)) {
1867             ps.executeUpdate();
1868         } catch (SQLException ex) {
1869             LOGGER.error("Unable to delete CPE dictionary entries", ex);
1870         }
1871     }
1872 
1873     /**
1874      * This method is only referenced in unused code and will likely break on
1875      * MySQL if ever used due to the MERGE statement.
1876      * <p>
1877      * Merges CPE entries into the database.
1878      * </p>
1879      *
1880      * @param cpe the CPE identifier
1881      * @param vendor the CPE vendor
1882      * @param product the CPE product
1883      */
1884     public void addCpe(String cpe, String vendor, String product) {
1885         clearCache();
1886         try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, ADD_DICT_CPE)) {
1887             ps.setString(1, cpe);
1888             ps.setString(2, vendor);
1889             ps.setString(3, product);
1890             ps.executeUpdate();
1891         } catch (SQLException ex) {
1892             LOGGER.error("Unable to add CPE dictionary entry", ex);
1893         }
1894     }
1895 
1896     /**
1897      * Returns a map of known exploited vulnerabilities.
1898      *
1899      * @return a map of known exploited vulnerabilities
1900      */
1901     public Map<String, org.owasp.dependencycheck.data.knownexploited.json.Vulnerability> getknownExploitedVulnerabilities() {
1902         final Map<String, org.owasp.dependencycheck.data.knownexploited.json.Vulnerability> known = new HashMap<>();
1903 
1904         try (Connection conn = databaseManager.getConnection();
1905                 PreparedStatement ps = getPreparedStatement(conn, SELECT_KNOWN_EXPLOITED_VULNERABILITIES);
1906                 ResultSet rs = ps.executeQuery()) {
1907 
1908             while (rs.next()) {
1909                 final org.owasp.dependencycheck.data.knownexploited.json.Vulnerability kev =
1910                         new org.owasp.dependencycheck.data.knownexploited.json.Vulnerability();
1911                 kev.setCveID(rs.getString(1));
1912                 kev.setVendorProject(rs.getString(2));
1913                 kev.setProduct(rs.getString(3));
1914                 kev.setVulnerabilityName(rs.getString(4));
1915                 kev.setDateAdded(rs.getString(5));
1916                 kev.setShortDescription(rs.getString(6));
1917                 kev.setRequiredAction(rs.getString(7));
1918                 kev.setDueDate(rs.getString(8));
1919                 kev.setNotes(rs.getString(9));
1920                 known.put(kev.getCveID(), kev);
1921             }
1922 
1923         } catch (SQLException ex) {
1924             throw new DatabaseException(ex);
1925         }
1926         return known;
1927     }
1928 
1929     /**
1930      * Helper method to add a nullable string parameter.
1931      *
1932      * @param ps the prepared statement
1933      * @param pos the position of the parameter
1934      * @param value the value of the parameter
1935      * @throws SQLException thrown if there is an error setting the parameter.
1936      */
1937     private void addNullableStringParameter(PreparedStatement ps, int pos, String value) throws SQLException {
1938         if (value == null || value.isEmpty()) {
1939             ps.setNull(pos, java.sql.Types.VARCHAR);
1940         } else {
1941             ps.setString(pos, value);
1942         }
1943     }
1944 
1945     private void setUpdateColumn(PreparedStatement ps, int i, Double value) throws SQLException {
1946         if (value == null) {
1947             ps.setNull(i, java.sql.Types.DOUBLE);
1948         } else {
1949             ps.setDouble(i, value);
1950         }
1951     }
1952 
1953     private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.AuthenticationType value) throws SQLException {
1954         if (value == null) {
1955             ps.setNull(i, java.sql.Types.VARCHAR);
1956         } else {
1957             ps.setString(i, value.value());
1958         }
1959     }
1960 
1961     private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.CiaType value) throws SQLException {
1962         if (value == null) {
1963             ps.setNull(i, java.sql.Types.VARCHAR);
1964         } else {
1965             ps.setString(i, value.value());
1966         }
1967     }
1968 
1969     private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.Version value) throws SQLException {
1970         if (value == null) {
1971             ps.setNull(i, java.sql.Types.VARCHAR);
1972         } else {
1973             ps.setString(i, value.value());
1974         }
1975     }
1976 
1977     private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.AccessComplexityType value) throws SQLException {
1978         if (value == null) {
1979             ps.setNull(i, java.sql.Types.VARCHAR);
1980         } else {
1981             ps.setString(i, value.value());
1982         }
1983     }
1984 
1985     private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.AccessVectorType value) throws SQLException {
1986         if (value == null) {
1987             ps.setNull(i, java.sql.Types.VARCHAR);
1988         } else {
1989             ps.setString(i, value.value());
1990         }
1991     }
1992 
1993     private void setUpdateColumn(PreparedStatement ps, int i, String value) throws SQLException {
1994         if (value == null) {
1995             ps.setNull(i, java.sql.Types.VARCHAR);
1996         } else {
1997             ps.setString(i, value);
1998         }
1999     }
2000 
2001     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4.Type value) throws SQLException {
2002         if (value == null) {
2003             ps.setNull(i, java.sql.Types.VARCHAR);
2004         } else {
2005             ps.setString(i, value.value());
2006         }
2007     }
2008 
2009     private void setUpdateColumn(PreparedStatement ps, int i, Boolean value) throws SQLException {
2010         if (value == null) {
2011             //TODO this is may also be an issue for MS SQL, if an issue is created we'll just need
2012             // to create an isMsSQL flag. See todo above in updateOrInsertVulnerability.
2013             if (isOracle) {
2014                 ps.setNull(i, java.sql.Types.BIT);
2015             } else {
2016                 ps.setNull(i, java.sql.Types.BOOLEAN);
2017             }
2018         } else {
2019             ps.setBoolean(i, value);
2020         }
2021     }
2022 
2023     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.AttackVectorType value) throws SQLException {
2024         if (value == null) {
2025             ps.setNull(i, java.sql.Types.VARCHAR);
2026         } else {
2027             ps.setString(i, value.value());
2028         }
2029     }
2030 
2031     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.AttackComplexityType value) throws SQLException {
2032         if (value == null) {
2033             ps.setNull(i, java.sql.Types.VARCHAR);
2034         } else {
2035             ps.setString(i, value.value());
2036         }
2037     }
2038 
2039     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.PrivilegesRequiredType value) throws SQLException {
2040         if (value == null) {
2041             ps.setNull(i, java.sql.Types.VARCHAR);
2042         } else {
2043             ps.setString(i, value.value());
2044         }
2045     }
2046 
2047     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.UserInteractionType value) throws SQLException {
2048         if (value == null) {
2049             ps.setNull(i, java.sql.Types.VARCHAR);
2050         } else {
2051             ps.setString(i, value.value());
2052         }
2053     }
2054 
2055     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.ScopeType value) throws SQLException {
2056         if (value == null) {
2057             ps.setNull(i, java.sql.Types.VARCHAR);
2058         } else {
2059             ps.setString(i, value.value());
2060         }
2061     }
2062 
2063     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.SeverityType value) throws SQLException {
2064         if (value == null) {
2065             ps.setNull(i, java.sql.Types.VARCHAR);
2066         } else {
2067             ps.setString(i, value.value());
2068         }
2069     }
2070 
2071     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.CiaType value) throws SQLException {
2072         if (value == null) {
2073             ps.setNull(i, java.sql.Types.VARCHAR);
2074         } else {
2075             ps.setString(i, value.value());
2076         }
2077     }
2078 
2079     private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.Version value) throws SQLException {
2080         if (value == null) {
2081             ps.setNull(i, java.sql.Types.VARCHAR);
2082         } else {
2083             ps.setString(i, value.value());
2084         }
2085     }
2086 
2087     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.Version value) throws SQLException  {
2088         if (value == null) {
2089             ps.setNull(i, java.sql.Types.VARCHAR);
2090         } else {
2091             ps.setString(i, value.value());
2092         }
2093     }
2094 
2095     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AttackVectorType value) throws SQLException {
2096         if (value == null) {
2097             ps.setNull(i, java.sql.Types.VARCHAR);
2098         } else {
2099             ps.setString(i, value.value());
2100         }
2101     }
2102 
2103     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AttackComplexityType value) throws SQLException  {
2104         if (value == null) {
2105             ps.setNull(i, java.sql.Types.VARCHAR);
2106         } else {
2107             ps.setString(i, value.value());
2108         }
2109     }
2110 
2111     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AttackRequirementsType value) throws SQLException  {
2112         if (value == null) {
2113             ps.setNull(i, java.sql.Types.VARCHAR);
2114         } else {
2115             ps.setString(i, value.value());
2116         }
2117     }
2118 
2119     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.PrivilegesRequiredType value) throws SQLException  {
2120         if (value == null) {
2121             ps.setNull(i, java.sql.Types.VARCHAR);
2122         } else {
2123             ps.setString(i, value.value());
2124         }
2125     }
2126 
2127     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.UserInteractionType value)  throws SQLException {
2128         if (value == null) {
2129             ps.setNull(i, java.sql.Types.VARCHAR);
2130         } else {
2131             ps.setString(i, value.value());
2132         }
2133     }
2134 
2135     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.CiaType value)  throws SQLException {
2136         if (value == null) {
2137             ps.setNull(i, java.sql.Types.VARCHAR);
2138         } else {
2139             ps.setString(i, value.value());
2140         }
2141     }
2142 
2143     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ExploitMaturityType value)  throws SQLException {
2144         if (value == null) {
2145             ps.setNull(i, java.sql.Types.VARCHAR);
2146         } else {
2147             ps.setString(i, value.value());
2148         }
2149     }
2150 
2151     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.CiaRequirementType value) throws SQLException  {
2152         if (value == null) {
2153             ps.setNull(i, java.sql.Types.VARCHAR);
2154         } else {
2155             ps.setString(i, value.value());
2156         }
2157     }
2158 
2159     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedAttackVectorType value) throws SQLException  {
2160         if (value == null) {
2161             ps.setNull(i, java.sql.Types.VARCHAR);
2162         } else {
2163             ps.setString(i, value.value());
2164         }
2165     }
2166 
2167     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedAttackComplexityType value) throws SQLException  {
2168         if (value == null) {
2169             ps.setNull(i, java.sql.Types.VARCHAR);
2170         } else {
2171             ps.setString(i, value.value());
2172         }
2173     }
2174 
2175     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedAttackRequirementsType value)  throws SQLException {
2176         if (value == null) {
2177             ps.setNull(i, java.sql.Types.VARCHAR);
2178         } else {
2179             ps.setString(i, value.value());
2180         }
2181     }
2182 
2183     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedPrivilegesRequiredType value)  throws SQLException {
2184         if (value == null) {
2185             ps.setNull(i, java.sql.Types.VARCHAR);
2186         } else {
2187             ps.setString(i, value.value());
2188         }
2189     }
2190 
2191     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedUserInteractionType value)  throws SQLException {
2192         if (value == null) {
2193             ps.setNull(i, java.sql.Types.VARCHAR);
2194         } else {
2195             ps.setString(i, value.value());
2196         }
2197     }
2198 
2199     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedCiaType value) throws SQLException  {
2200         if (value == null) {
2201             ps.setNull(i, java.sql.Types.VARCHAR);
2202         } else {
2203             ps.setString(i, value.value());
2204         }
2205     }
2206 
2207     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedSubCType value) throws SQLException  {
2208         if (value == null) {
2209             ps.setNull(i, java.sql.Types.VARCHAR);
2210         } else {
2211             ps.setString(i, value.value());
2212         }
2213     }
2214 
2215     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedSubIaType value) throws SQLException  {
2216         if (value == null) {
2217             ps.setNull(i, java.sql.Types.VARCHAR);
2218         } else {
2219             ps.setString(i, value.value());
2220         }
2221     }
2222 
2223     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.SafetyType value) throws SQLException  {
2224         if (value == null) {
2225             ps.setNull(i, java.sql.Types.VARCHAR);
2226         } else {
2227             ps.setString(i, value.value());
2228         }
2229     }
2230 
2231     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AutomatableType value) throws SQLException  {
2232         if (value == null) {
2233             ps.setNull(i, java.sql.Types.VARCHAR);
2234         } else {
2235             ps.setString(i, value.value());
2236         }
2237     }
2238 
2239     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.RecoveryType value)  throws SQLException {
2240         if (value == null) {
2241             ps.setNull(i, java.sql.Types.VARCHAR);
2242         } else {
2243             ps.setString(i, value.value());
2244         }
2245     }
2246 
2247     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ValueDensityType value) throws SQLException  {
2248         if (value == null) {
2249             ps.setNull(i, java.sql.Types.VARCHAR);
2250         } else {
2251             ps.setString(i, value.value());
2252         }
2253     }
2254 
2255     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.VulnerabilityResponseEffortType value) throws SQLException  {
2256         if (value == null) {
2257             ps.setNull(i, java.sql.Types.VARCHAR);
2258         } else {
2259             ps.setString(i, value.value());
2260         }
2261     }
2262 
2263     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ProviderUrgencyType value) throws SQLException  {
2264         if (value == null) {
2265             ps.setNull(i, java.sql.Types.VARCHAR);
2266         } else {
2267             ps.setString(i, value.value());
2268         }
2269     }
2270 
2271     private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.SeverityType value) throws SQLException  {
2272         if (value == null) {
2273             ps.setNull(i, java.sql.Types.VARCHAR);
2274         } else {
2275             ps.setString(i, value.value());
2276         }
2277     }
2278 
2279     /**
2280      * Sets the float parameter on a prepared statement from a properties map.
2281      *
2282      * @param ps a prepared statement
2283      * @param i the index of the property
2284      * @param props the property collection
2285      * @param key the property key
2286      * @throws SQLException thrown if there is an error adding the property
2287      */
2288     private void setFloatValue(PreparedStatement ps, int i, Map<String, Object> props, String key) throws SQLException {
2289         if (props != null && props.containsKey(key)) {
2290             try {
2291                 ps.setFloat(i, Float.parseFloat(props.get(key).toString()));
2292             } catch (NumberFormatException nfe) {
2293                 ps.setNull(i, java.sql.Types.FLOAT);
2294             }
2295         } else {
2296             ps.setNull(i, java.sql.Types.FLOAT);
2297         }
2298     }
2299 
2300     /**
2301      * Sets the string parameter on a prepared statement from a properties map.
2302      *
2303      * @param ps a prepared statement
2304      * @param i the index of the property
2305      * @param props the property collection
2306      * @param key the property key
2307      * @throws SQLException thrown if there is an error adding the property
2308      */
2309     private void setStringValue(PreparedStatement ps, int i, Map<String, Object> props, String key) throws SQLException {
2310         if (props != null && props.containsKey(key)) {
2311             ps.setString(i, props.get(key).toString());
2312         } else {
2313             ps.setNull(i, java.sql.Types.VARCHAR);
2314         }
2315     }
2316 
2317     /**
2318      * Sets the boolean parameter on a prepared statement from a properties map.
2319      *
2320      * @param ps a prepared statement
2321      * @param i the index of the property
2322      * @param props the property collection
2323      * @param key the property key
2324      * @throws SQLException thrown if there is an error adding the property
2325      */
2326     private void setBooleanValue(PreparedStatement ps, int i, Map<String, Object> props, String key) throws SQLException {
2327         if (props != null && props.containsKey(key)) {
2328             ps.setBoolean(i, Boolean.parseBoolean(props.get(key).toString()));
2329         } else {
2330             ps.setNull(i, java.sql.Types.BOOLEAN);
2331         }
2332     }
2333 
2334     /**
2335      * Returns the Boolean value for the given index; if the value is null then
2336      * null is returned.
2337      *
2338      * @param rs the record set
2339      * @param index the parameter index
2340      * @return the Boolean value; or null
2341      * @throws SQLException thrown if there is an error obtaining the value
2342      */
2343     @SuppressFBWarnings("NP_BOOLEAN_RETURN_NULL")
2344     private Boolean getBooleanValue(ResultSet rs, int index) throws SQLException {
2345         if (rs.getObject(index) == null) {
2346             return null;
2347         }
2348         return rs.getBoolean(index);
2349     }
2350 
2351     /**
2352      * Returns the Float value for the given index; if the value is null then
2353      * null is returned.
2354      *
2355      * @param rs the record set
2356      * @param index the parameter index
2357      * @return the Float value; or null
2358      * @throws SQLException thrown if there is an error obtaining the value
2359      */
2360     private Float getFloatValue(ResultSet rs, int index) throws SQLException {
2361         if (rs.getObject(index) == null) {
2362             return null;
2363         }
2364         return rs.getFloat(index);
2365     }
2366 }