Skip to content

Commit

Permalink
Added cycloneDX core library #2504
Browse files Browse the repository at this point in the history
- added cycloneDX core library
- using cycloneDX core for vulnerability parsing
  • Loading branch information
lorriborri committed Oct 12, 2023
1 parent c984c56 commit a8a83bc
Show file tree
Hide file tree
Showing 15 changed files with 315 additions and 242 deletions.
12 changes: 8 additions & 4 deletions gradle/libraries.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ ext {
thymeleaf_extras_springsecurity5: "3.1.1.RELEASE",

/* SARIF */
sarif_210: "1.1.0"

sarif_210: "1.1.0",

/* cycloneDX core */
cycloneDX_core: "8.0.0"

]

Expand Down Expand Up @@ -165,8 +167,10 @@ ext {
thymeleaf_extras_springsecurity5: "org.thymeleaf.extras:thymeleaf-extras-springsecurity5:${libraryVersion.thymeleaf_extras_springsecurity5}",

/* SARIF */
sarif_210: "de.jcup.sarif.java:sarif-2.1.0:${libraryVersion.sarif_210}"

sarif_210: "de.jcup.sarif.java:sarif-2.1.0:${libraryVersion.sarif_210}",

/* cycloneDX core for Xray and sechub importer */
cycloneDX_core: "org.cyclonedx:cyclonedx-core-java:${libraryVersion.cycloneDX_core}"
]


Expand Down
4 changes: 1 addition & 3 deletions sechub-wrapper-xray/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
* ============================================================================
*/
dependencies {
implementation project(':sechub-commons-model')
implementation project(':sechub-commons-core')
implementation project(':sechub-commons-pds')
testImplementation project(':sechub-testframework')

implementation spring_boot_dependency.slf4j_api
implementation spring_boot_dependency.jackson_core
implementation spring_boot_dependency.jackson_databind
implementation library.jcommander
implementation library.cycloneDX_core

testImplementation spring_boot_dependency.junit_jupiter
testImplementation spring_boot_dependency.junit_jupiter_params
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package com.mercedesbenz.sechub.xraywrapper.cli;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mercedesbenz.sechub.xraywrapper.api.XrayAPIArtifactoryClient;
import com.mercedesbenz.sechub.xraywrapper.config.XrayWrapperArtifact;
import com.mercedesbenz.sechub.xraywrapper.config.XrayWrapperConfiguration;
import com.mercedesbenz.sechub.xraywrapper.report.XrayWrapperReportException;
import com.mercedesbenz.sechub.xraywrapper.report.XrayWrapperReportReader;
import org.cyclonedx.model.Bom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

public class XrayWrapperArtifactoryClientController {

Expand Down Expand Up @@ -63,8 +62,8 @@ public void waitForScansToFinishAndDownloadReport() throws XrayWrapperRuntimeExc
private void manageReports() throws XrayWrapperReportException {
reportReader.getFiles(xrayWrapperConfiguration.getZip_directory(), xrayWrapperConfiguration.getSecHubReport());
reportReader.readSecurityReport();
ObjectNode root = reportReader.mapVulnerabilities();
reportReader.writeReport(root);
Bom cycloneDXBom = reportReader.mapVulnerabilities();
reportReader.writeReport(cycloneDXBom);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public enum XrayWrapperExitCode {

FILE_NOT_FOUND(11),

FILE_NOT_VALID(12),

;

private final int exitCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,145 +1,116 @@
package com.mercedesbenz.sechub.xraywrapper.report;

import java.util.ArrayList;
import java.util.List;

import org.cyclonedx.model.vulnerability.Vulnerability;
import org.cyclonedx.model.vulnerability.Vulnerability.Source;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
* builds a cycloneDX vulnerability according to CycloneDX standard 1.4 @see <a
* href="https://cyclonedx.org/docs/1.4/json/"/a> examples: <a
* href="https://github.com/CycloneDX/bom-examples/blob/7d529848e2f8bd65d03aec9eab16f139fd445ff4/VEX/Use-Cases/Case-10/vex.json#L48"/a>
* <a
* href="https://github.com/CycloneDX/bom-examples/blob/7d529848e2f8bd65d03aec9eab16f139fd445ff4/VEX/CISA-Use-Cases/Case-7/vex.json#L29"/a>
* <a
* href="https://github.com/CycloneDX/bom-examples/blob/7d529848e2f8bd65d03aec9eab16f139fd445ff4/VEX/Use-Cases/Case-5/vex.json#L35"/a>
*/

public class CycloneDXVulnerabilityBuilder {

private String id;

private ObjectNode vulnerability;

private ObjectMapper objectMapper;

public CycloneDXVulnerabilityBuilder(String id) {
this.id = id;
this.objectMapper = new ObjectMapper();
this.vulnerability = objectMapper.createObjectNode();
}

public String getId() {
return id;
}
Vulnerability vulnerability;

public void setId(String id) {
this.id = id;
this.vulnerability.put("id", id);
public CycloneDXVulnerabilityBuilder() {
this.vulnerability = new Vulnerability();
this.vulnerability.setId("default");
}

public ObjectNode getVulnerability() {
public Vulnerability getVulnerability() {
return vulnerability;
}

// adds the bom_ref variable to the CycloneDx vulnerability
public void addBom_ref(String bomref) {
this.vulnerability.put("bom-ref", bomref);
}

public void addCWE(ArrayNode cwe) {
ArrayNode arrayNode = objectMapper.createArrayNode();
for (JsonNode node : cwe) {
public void addCWE(ArrayNode cweArray) {
List<Integer> cwes = new ArrayList<>();
for (JsonNode node : cweArray) {
String s = node.asText();
if (s.contains("noinfo"))
continue;
try {
s = s.split("-")[1];
arrayNode.add(Integer.parseInt(s));
cwes.add(Integer.parseInt(s));
} catch (NumberFormatException e) {
break;
}
}
this.vulnerability.set("cwes", arrayNode);
this.vulnerability.setCwes(cwes);
}

public void addSource(String url_string, String name_string) {
ObjectNode source = objectMapper.createObjectNode();
source.put("url", url_string);
source.put("name", name_string);
this.vulnerability.set("source", source);
public void addSource(String sourceUrl, String sourceName) {
Source source = new Source();
source.setName(sourceName);
source.setUrl(sourceUrl);
this.vulnerability.setSource(source);
}

public void addRating(Float score, String severity, String method, String vector, String source_name) {
ArrayNode arrayRating = objectMapper.createArrayNode();
ObjectNode nestedNode = objectMapper.createObjectNode();
ObjectNode source = objectMapper.createObjectNode();
public void addRating(Double score, String severity, String method, String vector, String sourceName) {
Vulnerability.Rating rating = new Vulnerability.Rating();

String url = "";
if (!this.getId().contains("XRAY")) {
url = "https://nvd.nist.gov/vuln/detail/" + this.getId();
String sourceUrl = "";
String id = this.vulnerability.getId();
if (!id.contains("XRAY")) {
sourceUrl = "https://nvd.nist.gov/vuln/detail/" + id;
}
source.put("name", source_name);
source.put("url", url);
nestedNode.set("source", source);
nestedNode.put("score", score);
nestedNode.put("severity", severity);
nestedNode.put("method", method);
nestedNode.put("vector", vector);

arrayRating.add(nestedNode);
this.vulnerability.set("ratings", arrayRating);
}

public void addDescription(String description) {
this.vulnerability.put("description", description);
}
Source source = new Source();
source.setName(sourceName);
source.setUrl(sourceUrl);
rating.setSource(source);

rating.setScore(score);

rating.setSeverity(Vulnerability.Rating.Severity.fromString(severity));

rating.setMethod(Vulnerability.Rating.Method.fromString(method));

rating.setVector(vector);

this.vulnerability.addRating(rating);

public void addAnalysis(JsonNode analysis) {
this.vulnerability.set("analysis", analysis);
}

public void addAffects(String ref, ArrayNode vulnerableVersions, ArrayNode fixedVersions, String purls) {
ObjectNode component = objectMapper.createObjectNode();
component.put("ref", ref);
ArrayNode versions = objectMapper.createArrayNode();
ArrayNode affects = objectMapper.createArrayNode();

// todo: not correct format ( correct: vers:semver/<1.5.0|>=7.0.) but valid
if (vulnerableVersions != null)
putVersions(vulnerableVersions, versions, "affected", purls);
if (fixedVersions != null)
putVersions(fixedVersions, versions, "unaffected", purls);

component.set("versions", versions);
affects.add(component);
this.vulnerability.set("affects", affects);
public void addAffects(String ref, ArrayNode vulnerableVersions, ArrayNode fixedVersions) {
Vulnerability.Affect affect = new Vulnerability.Affect();
List<Vulnerability.Affect> affects = new ArrayList<>();
List<Vulnerability.Version> versions = new ArrayList<>();
affect.setRef(ref);
String pkg = ref.split(":")[0];
transformVersions(vulnerableVersions, "affected", pkg, versions);
transformVersions(fixedVersions, "unaffected", pkg, versions);
affect.setVersions(versions);
affects.add(affect);
this.vulnerability.setAffects(affects);

}

private void putVersions(ArrayNode arrayNode, ArrayNode versions, String status, String purls) {
boolean isRange = false;
StringBuilder cycloneVersion = new StringBuilder(purls);
for (JsonNode node : arrayNode) {
// only ≤ and < are used in Xray report
String s = node.asText();
// versions are a range
if (s.contains("<") | s.contains("≤") | s.contains("All Versions") | s.contains(">") | s.contains("≥")) {
isRange = true;
s = s.replace(" ", "");
cycloneVersion.append("@").append(s);
} else {
ObjectNode cycloneArrayNode = objectMapper.createObjectNode();
cycloneArrayNode.put("version", s);
cycloneArrayNode.put("status", status);
versions.add(cycloneArrayNode);
private void transformVersions(ArrayNode securityVersions, String status, String pkg, List<Vulnerability.Version> versions) {
// "All Versions", "< 1.19.10", "1.20.0-0 ≤ Version < 1.20.5", "1.2.34"
// cycloneDX using Version Range Spec (vers) vers:npm/1.2.3|>=2.0.0|<5.0.0
pkg = "vers:" + pkg + "/";
if (securityVersions != null) {
for (JsonNode entry : securityVersions) {
String versionString = entry.asText();
Vulnerability.Version version = new Vulnerability.Version();
if (versionString.equals("All Versions")) {
version.setRange(pkg + ">=0.0.0");

} else if (versionString.contains("Version")) {
versionString = versionString.replace(" ", "");
String[] split = versionString.split("Version");
version.setRange(pkg + split[0] + "|" + split[1]);

} else if (versionString.contains("<") | versionString.contains("≤")) {
versionString = versionString.replace(" ", "");
version.setRange(pkg + versionString);

} else {
version.setVersion(versionString);
}
version.setStatus(Vulnerability.Version.Status.fromString(status));
versions.add(version);
}
}
// not single vulnerable or fixed versions but a range
if (isRange) {
ObjectNode cycloneArrayNode = objectMapper.createObjectNode();
cycloneArrayNode.put("range", cycloneVersion.toString());
cycloneArrayNode.put("status", status);
versions.add(cycloneArrayNode);
}
}
}
Loading

0 comments on commit a8a83bc

Please sign in to comment.