2121import io .github .jeremylong .openvulnerability .client .nvd .CvssV2Data ;
2222import io .github .jeremylong .openvulnerability .client .nvd .CvssV3 ;
2323import io .github .jeremylong .openvulnerability .client .nvd .CvssV3Data ;
24+
2425import java .util .Arrays ;
2526import java .util .HashMap ;
2627import 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 ;
2732import org .sonatype .ossindex .service .api .cvss .Cvss3Severity ;
2833
2934/**
@@ -36,6 +41,7 @@ public final class CvssUtil {
3641 private CvssUtil () {
3742 //empty constructor for utility class.
3843 }
44+
3945 /**
4046 * The CVSS v3 Base Metrics (that are required by the spec for any CVSS v3
4147 * Vector String)
@@ -221,6 +227,129 @@ public static CvssV3 vectorToCvssV3(String vectorString, Double baseScore) {
221227 baseSeverity , null , null , null , null , null , null , null , null , null , null , null , null , null , null , null , null , null , null );
222228 final CvssV3 cvss = new CvssV3 (null , null , data , null , null );
223229 return cvss ;
230+ }
231+
232+ private static CvssV4Data .SeverityType toSeverityType (double baseScore ) {
233+ if (baseScore == 0.0 ) {
234+ return CvssV4Data .SeverityType .NONE ;
235+ } else if (baseScore >= 0.1 && baseScore <= 3.9 ) {
236+ return CvssV4Data .SeverityType .LOW ;
237+ } else if (baseScore >= 4.0 && baseScore <= 6.9 ) {
238+ return CvssV4Data .SeverityType .MEDIUM ;
239+ } else if (baseScore >= 7.0 && baseScore <= 8.9 ) {
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+ * Convert a CVSSv4 vector String into a CvssV4 Object.
250+ *
251+ * @param source the source of the CVSS data
252+ * @param type the type of CVSS data (primary or secondary)
253+ * @param baseScore the base score
254+ * @param vectorString the vector string
255+ * @return the CVSSv4 object
256+ */
257+ public static CvssV4 vectorToCvssV4 (String source , CvssV4 .Type type , Double baseScore , String vectorString ) {
258+ // Remove "CVSS:" prefix and split by "/"
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 = toSeverityType (baseScore );
304+ // Scores and severities are not present in the vector string, set to null/defaults
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+ );
224352
353+ return new CvssV4 (source , type , cvssData );
225354 }
226355}
0 commit comments