1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.utils;
19
20 import io.github.jeremylong.openvulnerability.client.nvd.CvssV2;
21 import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data;
22 import io.github.jeremylong.openvulnerability.client.nvd.CvssV3;
23 import io.github.jeremylong.openvulnerability.client.nvd.CvssV3Data;
24
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import io.github.jeremylong.openvulnerability.client.nvd.CvssV4;
31 import io.github.jeremylong.openvulnerability.client.nvd.CvssV4Data;
32 import org.sonatype.ossindex.service.api.cvss.Cvss3Severity;
33
34
35
36
37
38
39 public final class CvssUtil {
40
41 private CvssUtil() {
42
43 }
44
45
46
47
48
49 private static final List<String> BASE_METRICS_V3 = Arrays.asList("AV", "AC", "PR", "UI", "S", "C", "I", "A");
50
51
52
53
54 private static final List<String> BASE_METRICS_V2 = Arrays.asList("AV", "AC", "Au", "C", "I", "A");
55
56
57
58 private static final Double ZERO = 0.0;
59
60
61
62 private static final Double ONE = 1.0;
63
64
65
66 private static final Double FOUR = 4.0;
67
68
69
70 private static final Double SEVEN = 7.0;
71
72
73
74 private static final Double NINE = 9.0;
75
76
77
78 private static final Double TEN = 10.0;
79
80
81
82 private static final String UNKNOWN = "UNKNOWN";
83
84
85
86 private static final String HIGH = "HIGH";
87
88
89
90 private static final String MEDIUM = "MEDIUM";
91
92
93
94 private static final String LOW = "LOW";
95
96
97
98
99
100
101
102
103 public static CvssV2 vectorToCvssV2(String vectorString, Double baseScore) {
104 if (vectorString.startsWith("CVSS:")) {
105 throw new IllegalArgumentException("Not a valid CVSSv2 vector string: " + vectorString);
106 }
107 final String[] metricStrings = vectorString.substring(vectorString.indexOf('/') + 1).split("/");
108 final HashMap<String, String> metrics = new HashMap<>();
109 for (int i = 0; i < metricStrings.length; i++) {
110 final String[] metricKeyVal = metricStrings[i].split(":");
111 if (metricKeyVal.length != 2) {
112 throw new IllegalArgumentException(
113 String.format("Not a valid CVSSv2 vector string '%s', invalid metric component '%s'",
114 vectorString, metricStrings[i]));
115 }
116 metrics.put(metricKeyVal[0], metricKeyVal[1]);
117 }
118 if (!metrics.keySet().containsAll(BASE_METRICS_V2)) {
119 throw new IllegalArgumentException(
120 String.format("Not a valid CVSSv2 vector string '%s'; missing one or more required Metrics;",
121 vectorString));
122 }
123
124
125 final CvssV2Data.AccessVectorType accessVector = CvssV2Data.AccessVectorType.fromValue(metrics.get("AV"));
126 final CvssV2Data.AccessComplexityType attackComplexity = CvssV2Data.AccessComplexityType.fromValue(metrics.get("AC"));
127 final CvssV2Data.AuthenticationType authentication = CvssV2Data.AuthenticationType.fromValue(metrics.get("Au"));
128 final CvssV2Data.CiaType confidentialityImpact = CvssV2Data.CiaType.fromValue(metrics.get("C"));
129 final CvssV2Data.CiaType integrityImpact = CvssV2Data.CiaType.fromValue(metrics.get("I"));
130 final CvssV2Data.CiaType availabilityImpact = CvssV2Data.CiaType.fromValue(metrics.get("A"));
131
132 final String baseSeverity = cvssV2ScoreToSeverity(baseScore);
133 final CvssV2Data data = new CvssV2Data(CvssV2Data.Version._2_0, vectorString, accessVector, attackComplexity,
134 authentication, confidentialityImpact, integrityImpact, availabilityImpact, baseScore, baseSeverity,
135 null, null, null, null, null, null, null, null, null, null);
136 final CvssV2 cvss = new CvssV2(null, null, data, baseSeverity, null, null, null, null, null, null, null);
137 return cvss;
138
139 }
140
141
142
143
144
145
146
147 public static String cvssV2ScoreToSeverity(Double score) {
148 if (score != null) {
149 if (ZERO.compareTo(score) <= 0 && FOUR.compareTo(score) > 0) {
150 return LOW;
151 } else if (FOUR.compareTo(score) <= 0 && SEVEN.compareTo(score) > 0) {
152 return MEDIUM;
153 } else if (SEVEN.compareTo(score) <= 0 && TEN.compareTo(score) >= 0) {
154 return HIGH;
155 }
156 }
157 return UNKNOWN;
158 }
159
160
161
162
163
164
165
166 public static CvssV3Data.SeverityType cvssV3ScoreToSeverity(Double score) {
167 if (score != null) {
168 if (ZERO.compareTo(score) == 0) {
169 return CvssV3Data.SeverityType.NONE;
170 } else if (ZERO.compareTo(score) <= 0 && FOUR.compareTo(score) > 0) {
171 return CvssV3Data.SeverityType.LOW;
172 } else if (FOUR.compareTo(score) <= 0 && SEVEN.compareTo(score) > 0) {
173 return CvssV3Data.SeverityType.MEDIUM;
174 } else if (SEVEN.compareTo(score) <= 0 && NINE.compareTo(score) > 0) {
175 return CvssV3Data.SeverityType.HIGH;
176 } else if (NINE.compareTo(score) <= 0 && TEN.compareTo(score) >= 0) {
177 return CvssV3Data.SeverityType.CRITICAL;
178 }
179 }
180 return null;
181 }
182
183
184
185
186
187
188
189
190 public static CvssV3 vectorToCvssV3(String vectorString, Double baseScore) {
191 if (!vectorString.startsWith("CVSS:3")) {
192 throw new IllegalArgumentException("Not a valid CVSSv3 vector string: " + vectorString);
193 }
194 final String versionString = vectorString.substring(5, vectorString.indexOf('/'));
195 final String[] metricStrings = vectorString.substring(vectorString.indexOf('/') + 1).split("/");
196 final HashMap<String, String> metrics = new HashMap<>();
197 for (int i = 0; i < metricStrings.length; i++) {
198 final String[] metricKeyVal = metricStrings[i].split(":");
199 if (metricKeyVal.length != 2) {
200 throw new IllegalArgumentException(
201 String.format("Not a valid CVSSv3 vector string '%s', invalid metric component '%s'",
202 vectorString, metricStrings[i]));
203 }
204 metrics.put(metricKeyVal[0], metricKeyVal[1]);
205 }
206 if (!metrics.keySet().containsAll(BASE_METRICS_V3)) {
207 throw new IllegalArgumentException(
208 String.format("Not a valid CVSSv3 vector string '%s'; missing one or more required Base Metrics;",
209 vectorString));
210 }
211
212 final CvssV3Data.Version version = CvssV3Data.Version.fromValue(versionString);
213
214 final CvssV3Data.AttackVectorType attackVector = CvssV3Data.AttackVectorType.fromValue(metrics.get("AV"));
215 final CvssV3Data.AttackComplexityType attackComplexity = CvssV3Data.AttackComplexityType.fromValue(metrics.get("AC"));
216 final CvssV3Data.PrivilegesRequiredType privilegesRequired = CvssV3Data.PrivilegesRequiredType.fromValue(metrics.get("PR"));
217 final CvssV3Data.UserInteractionType userInteraction = CvssV3Data.UserInteractionType.fromValue(metrics.get("UI"));
218 final CvssV3Data.ScopeType scope = CvssV3Data.ScopeType.fromValue(metrics.get("S"));
219 final CvssV3Data.CiaType confidentialityImpact = CvssV3Data.CiaType.fromValue(metrics.get("C"));
220 final CvssV3Data.CiaType integrityImpact = CvssV3Data.CiaType.fromValue(metrics.get("I"));
221 final CvssV3Data.CiaType availabilityImpact = CvssV3Data.CiaType.fromValue(metrics.get("A"));
222
223 final String baseSeverityString = Cvss3Severity.of(baseScore.floatValue()).name();
224 final CvssV3Data.SeverityType baseSeverity = CvssV3Data.SeverityType.fromValue(baseSeverityString);
225 final CvssV3Data data = new CvssV3Data(version, vectorString, attackVector, attackComplexity,
226 privilegesRequired, userInteraction, scope, confidentialityImpact, integrityImpact, availabilityImpact, baseScore,
227 baseSeverity, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
228 final CvssV3 cvss = new CvssV3(null, null, data, null, null);
229 return cvss;
230 }
231
232 public static CvssV4Data.SeverityType cvssV4ScoreToSeverity(double baseScore) {
233 if (baseScore == 0.0) {
234 return CvssV4Data.SeverityType.NONE;
235 } else if (baseScore > 0.0 && baseScore < 4.0) {
236 return CvssV4Data.SeverityType.LOW;
237 } else if (baseScore >= 4.0 && baseScore < 7.0) {
238 return CvssV4Data.SeverityType.MEDIUM;
239 } else if (baseScore >= 7.0 && baseScore < 9.0) {
240 return CvssV4Data.SeverityType.HIGH;
241 } else if (baseScore >= 9.0 && baseScore <= 10.0) {
242 return CvssV4Data.SeverityType.CRITICAL;
243 } else {
244 throw new IllegalArgumentException("Invalid CVSS base score: " + baseScore);
245 }
246 }
247
248
249
250
251
252
253
254
255
256
257 public static CvssV4 vectorToCvssV4(String source, CvssV4.Type type, Double baseScore, String vectorString) {
258
259 String[] parts = vectorString.replaceFirst("^CVSS:", "").split("/");
260 Map<String, String> values = new HashMap<>();
261 for (String part : parts) {
262 String[] kv = part.split(":");
263 if (kv.length == 2) {
264 values.put(kv[0], kv[1]);
265 }
266 }
267
268 CvssV4Data.Version version = CvssV4Data.Version.fromValue(values.getOrDefault("4.0", "4.0"));
269
270 CvssV4Data.AttackVectorType attackVector = values.containsKey("AV") ? CvssV4Data.AttackVectorType.fromValue(values.get("AV")) : null;
271 CvssV4Data.AttackComplexityType attackComplexity = values.containsKey("AC") ? CvssV4Data.AttackComplexityType.fromValue(values.get("AC")) : null;
272 CvssV4Data.AttackRequirementsType attackRequirements = values.containsKey("AT") ? CvssV4Data.AttackRequirementsType.fromValue(values.get("AT")) : null;
273 CvssV4Data.PrivilegesRequiredType privilegesRequired = values.containsKey("PR") ? CvssV4Data.PrivilegesRequiredType.fromValue(values.get("PR")) : null;
274 CvssV4Data.UserInteractionType userInteraction = values.containsKey("UI") ? CvssV4Data.UserInteractionType.fromValue(values.get("UI")) : null;
275 CvssV4Data.CiaType vulnConfidentialityImpact = values.containsKey("VC") ? CvssV4Data.CiaType.fromValue(values.get("VC")) : null;
276 CvssV4Data.CiaType vulnIntegrityImpact = values.containsKey("VI") ? CvssV4Data.CiaType.fromValue(values.get("VI")) : null;
277 CvssV4Data.CiaType vulnAvailabilityImpact = values.containsKey("VA") ? CvssV4Data.CiaType.fromValue(values.get("VA")) : null;
278 CvssV4Data.CiaType subConfidentialityImpact = values.containsKey("SC") ? CvssV4Data.CiaType.fromValue(values.get("SC")) : null;
279 CvssV4Data.CiaType subIntegrityImpact = values.containsKey("SI") ? CvssV4Data.CiaType.fromValue(values.get("SI")) : null;
280 CvssV4Data.CiaType subAvailabilityImpact = values.containsKey("SA") ? CvssV4Data.CiaType.fromValue(values.get("SA")) : null;
281 CvssV4Data.ExploitMaturityType exploitMaturity = values.containsKey("E") ? CvssV4Data.ExploitMaturityType.fromValue(values.get("E")) : CvssV4Data.ExploitMaturityType.NOT_DEFINED;
282 CvssV4Data.CiaRequirementType confidentialityRequirement = values.containsKey("CR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("CR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED;
283 CvssV4Data.CiaRequirementType integrityRequirement = values.containsKey("IR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("IR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED;
284 CvssV4Data.CiaRequirementType availabilityRequirement = values.containsKey("AR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("AR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED;
285 CvssV4Data.ModifiedAttackVectorType modifiedAttackVector = values.containsKey("MAV") ? CvssV4Data.ModifiedAttackVectorType.fromValue(values.get("MAV")) : CvssV4Data.ModifiedAttackVectorType.NOT_DEFINED;
286 CvssV4Data.ModifiedAttackComplexityType modifiedAttackComplexity = values.containsKey("MAC") ? CvssV4Data.ModifiedAttackComplexityType.fromValue(values.get("MAC")) : CvssV4Data.ModifiedAttackComplexityType.NOT_DEFINED;
287 CvssV4Data.ModifiedAttackRequirementsType modifiedAttackRequirements = values.containsKey("MAT") ? CvssV4Data.ModifiedAttackRequirementsType.fromValue(values.get("MAT")) : CvssV4Data.ModifiedAttackRequirementsType.NOT_DEFINED;
288 CvssV4Data.ModifiedPrivilegesRequiredType modifiedPrivilegesRequired = values.containsKey("MPR") ? CvssV4Data.ModifiedPrivilegesRequiredType.fromValue(values.get("MPR")) : CvssV4Data.ModifiedPrivilegesRequiredType.NOT_DEFINED;
289 CvssV4Data.ModifiedUserInteractionType modifiedUserInteraction = values.containsKey("MUI") ? CvssV4Data.ModifiedUserInteractionType.fromValue(values.get("MUI")) : CvssV4Data.ModifiedUserInteractionType.NOT_DEFINED;
290 CvssV4Data.ModifiedCiaType modifiedVulnConfidentialityImpact = values.containsKey("MVC") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVC")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED;
291 CvssV4Data.ModifiedCiaType modifiedVulnIntegrityImpact = values.containsKey("MVI") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVI")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED;
292 CvssV4Data.ModifiedCiaType modifiedVulnAvailabilityImpact = values.containsKey("MVA") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVA")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED;
293 CvssV4Data.ModifiedSubCType modifiedSubConfidentialityImpact = values.containsKey("MSC") ? CvssV4Data.ModifiedSubCType.fromValue(values.get("MSC")) : CvssV4Data.ModifiedSubCType.NOT_DEFINED;
294 CvssV4Data.ModifiedSubIaType modifiedSubIntegrityImpact = values.containsKey("MSI") ? CvssV4Data.ModifiedSubIaType.fromValue(values.get("MSI")) : CvssV4Data.ModifiedSubIaType.NOT_DEFINED;
295 CvssV4Data.ModifiedSubIaType modifiedSubAvailabilityImpact = values.containsKey("MSA") ? CvssV4Data.ModifiedSubIaType.fromValue(values.get("MSA")) : CvssV4Data.ModifiedSubIaType.NOT_DEFINED;
296 CvssV4Data.SafetyType safety = values.containsKey("S") ? CvssV4Data.SafetyType.fromValue(values.get("S")) : CvssV4Data.SafetyType.NOT_DEFINED;
297 CvssV4Data.AutomatableType automatable = values.containsKey("AU") ? CvssV4Data.AutomatableType.fromValue(values.get("AU")) : CvssV4Data.AutomatableType.NOT_DEFINED;
298 CvssV4Data.RecoveryType recovery = values.containsKey("R") ? CvssV4Data.RecoveryType.fromValue(values.get("R")) : CvssV4Data.RecoveryType.NOT_DEFINED;
299 CvssV4Data.ValueDensityType valueDensity = values.containsKey("V") ? CvssV4Data.ValueDensityType.fromValue(values.get("V")) : CvssV4Data.ValueDensityType.NOT_DEFINED;
300 CvssV4Data.VulnerabilityResponseEffortType vulnerabilityResponseEffort = values.containsKey("RE") ? CvssV4Data.VulnerabilityResponseEffortType.fromValue(values.get("RE")) : CvssV4Data.VulnerabilityResponseEffortType.NOT_DEFINED;
301 CvssV4Data.ProviderUrgencyType providerUrgency = values.containsKey("U") ? CvssV4Data.ProviderUrgencyType.fromValue(values.get("U")) : CvssV4Data.ProviderUrgencyType.NOT_DEFINED;
302
303 CvssV4Data.SeverityType baseSeverity = cvssV4ScoreToSeverity(baseScore);
304
305 Double threatScore = null;
306 CvssV4Data.SeverityType threatSeverity = null;
307 Double environmentalScore = null;
308 CvssV4Data.SeverityType environmentalSeverity = null;
309
310 CvssV4Data cvssData = new CvssV4Data(
311 version,
312 vectorString,
313 attackVector,
314 attackComplexity,
315 attackRequirements,
316 privilegesRequired,
317 userInteraction,
318 vulnConfidentialityImpact,
319 vulnIntegrityImpact,
320 vulnAvailabilityImpact,
321 subConfidentialityImpact,
322 subIntegrityImpact,
323 subAvailabilityImpact,
324 exploitMaturity,
325 confidentialityRequirement,
326 integrityRequirement,
327 availabilityRequirement,
328 modifiedAttackVector,
329 modifiedAttackComplexity,
330 modifiedAttackRequirements,
331 modifiedPrivilegesRequired,
332 modifiedUserInteraction,
333 modifiedVulnConfidentialityImpact,
334 modifiedVulnIntegrityImpact,
335 modifiedVulnAvailabilityImpact,
336 modifiedSubConfidentialityImpact,
337 modifiedSubIntegrityImpact,
338 modifiedSubAvailabilityImpact,
339 safety,
340 automatable,
341 recovery,
342 valueDensity,
343 vulnerabilityResponseEffort,
344 providerUrgency,
345 baseScore,
346 baseSeverity,
347 threatScore,
348 threatSeverity,
349 environmentalScore,
350 environmentalSeverity
351 );
352
353 return new CvssV4(source, type, cvssData);
354 }
355 }