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) 2019 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.dependency.naming;
19  
20  import org.apache.commons.lang3.builder.CompareToBuilder;
21  import org.apache.commons.lang3.builder.EqualsBuilder;
22  import org.apache.commons.lang3.builder.HashCodeBuilder;
23  import org.apache.hc.core5.net.PercentCodec;
24  import org.jetbrains.annotations.NotNull;
25  import org.owasp.dependencycheck.dependency.Confidence;
26  import us.springett.parsers.cpe.Cpe;
27  import us.springett.parsers.cpe.CpeBuilder;
28  import us.springett.parsers.cpe.exceptions.CpeValidationException;
29  import us.springett.parsers.cpe.values.Part;
30  
31  import static java.nio.charset.StandardCharsets.UTF_8;
32  
33  /**
34   * A CPE Identifier for a dependency object.
35   *
36   * @author Jeremy Long
37   */
38  public class CpeIdentifier implements Identifier {
39  
40      /**
41       * The serial version UID for serialization.
42       */
43      private static final long serialVersionUID = 2901855131887281680L;
44  
45      /**
46       * The CPE identifier.
47       */
48      private final Cpe cpe;
49      /**
50       * The confidence that this is the correct identifier.
51       */
52      private Confidence confidence;
53      /**
54       * The URL for the identifier.
55       */
56      private String url;
57      /**
58       * Notes about the vulnerability. Generally used for suppression
59       * information.
60       */
61      private String notes;
62  
63      /**
64       * Constructs a new CPE Identifier from a CPE object with the given
65       * confidence.
66       *
67       * @param cpe the CPE value
68       * @param confidence the confidence in the identifiers match
69       */
70      public CpeIdentifier(Cpe cpe, Confidence confidence) {
71          this.cpe = cpe;
72          this.confidence = confidence;
73          this.url = null;
74      }
75  
76      /**
77       * Constructs a new CPE Identifier from a CPE object with the given
78       * confidence.
79       *
80       * @param cpe the CPE value
81       * @param url the URL for the identifier
82       * @param confidence the confidence in the identifiers match
83       */
84      public CpeIdentifier(Cpe cpe, String url, Confidence confidence) {
85          this.cpe = cpe;
86          this.confidence = confidence;
87          this.url = url;
88      }
89  
90      /**
91       * Constructs a new CPE Identifier from a CPE object with the given
92       * confidence.
93       *
94       * @param vendor the vendor
95       * @param product the product name
96       * @param version the version
97       * @param confidence the confidence in the identifiers match
98       * @throws CpeValidationException thrown if there is an error converting the
99       * vendor, product, and version into a CPE object
100      */
101     public CpeIdentifier(String vendor, String product, String version, Confidence confidence) throws CpeValidationException {
102         final CpeBuilder builder = new CpeBuilder();
103         this.cpe = builder.part(Part.APPLICATION).vendor(vendor).product(product).version(version).build();
104         this.confidence = confidence;
105     }
106 
107     /**
108      * Returns the CPE object.
109      *
110      * @return the CPE object
111      */
112     public Cpe getCpe() {
113         return cpe;
114     }
115 
116     @Override
117     public Confidence getConfidence() {
118         return confidence;
119     }
120 
121     @Override
122     public String getNotes() {
123         return notes;
124     }
125 
126     @Override
127     public String getUrl() {
128         return url;
129     }
130 
131     /**
132      * {@inheritDoc}
133      */
134     @Override
135     public void setConfidence(Confidence confidence) {
136         this.confidence = confidence;
137     }
138 
139     /**
140      * {@inheritDoc}
141      */
142     @Override
143     public void setUrl(String url) {
144         this.url = url;
145     }
146 
147     @Override
148     public void setNotes(String notes) {
149         this.notes = notes;
150     }
151 
152     @Override
153     public String getValue() {
154         return cpe.toCpe23FS();
155     }
156 
157     /**
158      * Returns the CPE 2.3 formatted string.
159      *
160      * @return the CPE 2.3 formatted string
161      */
162     @Override
163     public String toString() {
164         return cpe.toCpe23FS();
165     }
166 
167     @Override
168     public int hashCode() {
169         return new HashCodeBuilder(95, 183)
170                 .append(this.cpe)
171                 .append(this.confidence)
172                 .append(this.url)
173                 .append(this.notes)
174                 .toHashCode();
175     }
176 
177     @Override
178     public boolean equals(Object obj) {
179         if (obj == null || !(obj instanceof CpeIdentifier)) {
180             return false;
181         }
182         if (this == obj) {
183             return true;
184         }
185         final CpeIdentifier other = (CpeIdentifier) obj;
186         return new EqualsBuilder().append(cpe, other.cpe)
187                 .append(this.confidence, other.confidence)
188                 .append(this.url, other.url)
189                 .append(this.notes, other.notes).isEquals();
190     }
191 
192     @Override
193     public int compareTo(@NotNull Identifier o) {
194         if (o instanceof CpeIdentifier) {
195             final CpeIdentifier other = (CpeIdentifier) o;
196             return new CompareToBuilder()
197                     .append(this.cpe, other.cpe)
198                     .append(this.url, other.getUrl())
199                     .append(this.confidence, other.getConfidence())
200                     .toComparison();
201 
202         }
203         return new CompareToBuilder()
204                 .append(this.toString(), o.toString())
205                 .append(this.url, o.getUrl())
206                 .append(this.confidence, o.getConfidence())
207                 .toComparison();
208     }
209 
210     /**
211      * Produces an NVD search URL for a given CPE to find all applicable vulnerabilities, including all populated parts
212      * of the given CPE.
213      * <p/>
214      * The opened link should be sorted in descending order (sortDirection=2) by publish date (sortOrder=3).
215      */
216     public static String nvdSearchUrlFor(Cpe cpe) {
217         // Use PercentCodec to force `*` to be encoded for CPE strings inside the URL. Technically '*' is not a reserved
218         // character in the fragment of URLs, but not all browsers handle this consistently, so better to encode aggressively.
219         // URlEncoder does not distinguish between parts of URLs appropriately, as well as not forcing encoding of these.
220         return String.format("https://nvd.nist.gov/vuln/search#/nvd/home?sortOrder=3&sortDirection=2&cpeFilterMode=applicability&resultType=records&cpeName=%s",
221                 PercentCodec.encode(cpe.toCpe23FS(), UTF_8));
222     }
223 
224     /**
225      * Produces an NVD search URL for a given application vendor/product/version combination to find all applicable vulnerabilities.
226      * <p/>
227      * The opened link should be sorted in descending order (sortDirection=2) by publish date (sortOrder=3).
228      */
229     public static String nvdSearchUrlFor(String vendor, String product, String version) throws CpeValidationException {
230         return nvdSearchUrlFor(new CpeBuilder().part(Part.APPLICATION).vendor(vendor).product(product).version(version).build());
231     }
232 
233     /**
234      * Produces an NVD search URL for a given CPE to find all applicable vulnerabilities, including only the part, vendor,
235      * and product of the given CPE (if populated). Discards all other parts/discriminators of the CPE in the generated search.
236      * <p/>
237      * The opened link should be sorted in descending order (sortDirection=2) by publish date (sortOrder=3).
238      */
239     public static String nvdProductSearchUrlFor(Cpe cpe) {
240         try {
241             return nvdSearchUrlFor(new CpeBuilder().part(cpe.getPart()).vendor(cpe.getVendor()).product(cpe.getProduct()).build());
242         } catch (CpeValidationException e) {
243             throw new RuntimeException(e);
244         }
245     }
246 }