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