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 Steve Springett. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.data.update.nvd;
19  
20  import com.fasterxml.jackson.core.JsonParser;
21  import com.fasterxml.jackson.core.JsonToken;
22  import com.fasterxml.jackson.databind.DeserializationFeature;
23  import com.fasterxml.jackson.databind.Module;
24  import com.fasterxml.jackson.databind.ObjectMapper;
25  import com.fasterxml.jackson.databind.ObjectReader;
26  import com.fasterxml.jackson.databind.json.JsonMapper;
27  import com.fasterxml.jackson.module.blackbird.BlackbirdModule;
28  import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
29  
30  import java.io.EOFException;
31  import java.io.File;
32  import java.io.FileInputStream;
33  import java.io.FileNotFoundException;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.InputStreamReader;
37  import static java.nio.charset.StandardCharsets.UTF_8;
38  import java.util.zip.GZIPInputStream;
39  import java.util.zip.ZipException;
40  
41  import org.owasp.dependencycheck.data.nvdcve.CveDB;
42  import org.owasp.dependencycheck.data.update.exception.CorruptedDatastreamException;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  import org.owasp.dependencycheck.data.nvd.json.DefCveItem;
46  import org.owasp.dependencycheck.data.nvd.ecosystem.CveEcosystemMapper;
47  import org.owasp.dependencycheck.data.update.exception.UpdateException;
48  import org.owasp.dependencycheck.utils.Settings;
49  import org.owasp.dependencycheck.utils.Utils;
50  
51  /**
52   * Parser and processor of NVD CVE JSON data feeds.
53   *
54   * @author Jeremy Long
55   */
56  public final class NvdCveParser {
57  
58      /**
59       * The logger.
60       */
61      private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveParser.class);
62      /**
63       * A reference to the CVE DB.
64       */
65      private final CveDB cveDB;
66      /**
67       * A reference to the ODC settings.
68       */
69      private final Settings settings;
70  
71      /**
72       * Creates a new NVD CVE JSON Parser.
73       *
74       * @param settings the dependency-check settings
75       * @param db a reference to the database
76       */
77      public NvdCveParser(Settings settings, CveDB db) {
78          this.settings = settings;
79          this.cveDB = db;
80      }
81  
82      /**
83       * Parses the NVD JSON file and inserts/updates data into the database.
84       *
85       * @param file the NVD JSON file to parse
86       * @throws UpdateException thrown if the file could not be read
87       * @throws CorruptedDatastreamException thrown if the file was found to be a
88       * corrupted download (ZipException or premature EOF)
89       */
90      public void parse(File file) throws UpdateException, CorruptedDatastreamException {
91          LOGGER.debug("Parsing " + file.getName());
92  
93          final Module module;
94          if (Utils.getJavaVersion() <= 8) {
95              module = new AfterburnerModule();
96          } else {
97              module = new BlackbirdModule();
98          }
99          final ObjectMapper objectMapper = JsonMapper.builder()
100                 .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
101                 .addModule(module)
102                 .build();
103 
104         final ObjectReader objectReader = objectMapper.readerFor(DefCveItem.class);
105 
106         try (InputStream fin = new FileInputStream(file);
107                 InputStream in = new GZIPInputStream(fin);
108                 InputStreamReader isr = new InputStreamReader(in, UTF_8);
109                 JsonParser parser = objectReader.getFactory().createParser(isr)) {
110 
111             final CveEcosystemMapper mapper = new CveEcosystemMapper();
112             init(parser);
113             while (parser.nextToken() == JsonToken.START_OBJECT) {
114                 final DefCveItem cve = objectReader.readValue(parser);
115                 cveDB.updateVulnerability(cve, mapper.getEcosystem(cve));
116             }
117         } catch (FileNotFoundException ex) {
118             LOGGER.error(ex.getMessage());
119             throw new UpdateException("Unable to find the NVD CVE file, `" + file + "`, to parse", ex);
120         } catch (ZipException | EOFException ex) {
121             throw new CorruptedDatastreamException("Error parsing NVD CVE file", ex);
122         } catch (IOException ex) {
123             LOGGER.error("Error reading NVD JSON data: {}", file);
124             LOGGER.debug("Error extracting the NVD JSON data from: " + file, ex);
125             throw new UpdateException("Unable to find the NVD CVE file to parse", ex);
126         }
127     }
128 
129     void init(JsonParser parser) throws IOException {
130         JsonToken nextToken = parser.nextToken();
131         if (nextToken != JsonToken.START_OBJECT) {
132             throw new IOException("Expected " + JsonToken.START_OBJECT + ", got " + nextToken);
133         }
134 
135         do {
136             nextToken = parser.nextToken();
137             if (nextToken == null) {
138                 break;
139             }
140 
141             if (nextToken.isStructStart()) {
142                 if (nextToken == JsonToken.START_ARRAY) {
143                     break;
144                 } else {
145                     parser.skipChildren();
146                 }
147             }
148         } while (true);
149     }
150 }