summaryrefslogtreecommitdiffstats
path: root/csarvalidation/src/main/java/org/onap
diff options
context:
space:
mode:
authorBartosz Gardziejewski <bartosz.gardziejewski@nokia.com>2020-12-15 09:59:13 +0100
committerBartosz Gardziejewski <bartosz.gardziejewski@nokia.com>2020-12-29 11:12:18 +0100
commit25673a3551f2bf15f23afbbfe986947c6a975c91 (patch)
tree548a4fa35f28280a8f49dbb3e28b7636522f764b /csarvalidation/src/main/java/org/onap
parentd2f0552ea27a481bdbe9099ee52422bca8b6b314 (diff)
Add individual artifact validation using common cert.
Signed-off-by: Bartosz Gardziejewski <bartosz.gardziejewski@nokia.com> Change-Id: I2aa4e862f3d343a3f452e1564dc8a97a34960b83 Issue-ID: VNFSDK-714
Diffstat (limited to 'csarvalidation/src/main/java/org/onap')
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java7
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java510
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSecurityValidator.java220
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourceSecurityValidator.java154
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourcesSecurityValidator.java99
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/Error.java226
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileHashValidator.java52
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileSignatureValidator.java76
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidator.java75
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorFactory.java40
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorWithCommonFile.java40
-rw-r--r--csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ValidatedSecurityFile.java46
-rw-r--r--csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java25
13 files changed, 1066 insertions, 504 deletions
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java b/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java
index 05f2070..74b1bac 100644
--- a/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java
@@ -33,6 +33,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.stream.Collectors;
/**
* Verify the CSAR package by following the SOL004 specifications and ONAP VNFREQS for TOSCA.
@@ -782,11 +783,13 @@ public class CSARArchive implements AutoCloseable {
}
public Map<String, Map<String, List<String>>> getNonMano() {
- return nonMano;
+ return Map.copyOf(nonMano);
}
public void setNonMano(Map<String, Map<String, List<String>>> nonMano) {
- this.nonMano = nonMano;
+ this.nonMano = nonMano.entrySet().stream()
+ .filter(mapEntry -> mapEntry.getKey() != null && mapEntry.getValue() != null)
+ .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
this.isNonManoAvailable = true;
}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java
index 6f1ff1f..b14e798 100644
--- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java
@@ -21,228 +21,27 @@ package org.onap.cvc.csar.cc.sol004;
import org.onap.cli.fw.error.OnapCommandException;
import org.onap.cli.fw.schema.OnapCommandSchema;
import org.onap.cvc.csar.CSARArchive;
-import org.onap.cvc.csar.FileArchive;
import org.onap.cvc.csar.cc.VTPValidateCSARBase;
-import org.onap.cvc.csar.parser.ManifestFileModel;
-import org.onap.cvc.csar.parser.ManifestFileSplitter;
-import org.onap.cvc.csar.parser.SourcesParser;
-import org.onap.cvc.csar.security.CertificateLoadingException;
-import org.onap.cvc.csar.security.CmsSignatureData;
-import org.onap.cvc.csar.security.CmsSignatureDataFactory;
-import org.onap.cvc.csar.security.CmsSignatureLoadingException;
-import org.onap.cvc.csar.security.CmsSignatureValidator;
-import org.onap.cvc.csar.security.CmsSignatureValidatorException;
-import org.onap.cvc.csar.security.ShaHashCodeGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.onap.cvc.csar.cc.sol004.r130206.CsarSecurityValidator;
+import org.onap.cvc.csar.cc.sol004.r130206.Error;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
import java.nio.file.Path;
-import java.security.NoSuchAlgorithmException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
@OnapCommandSchema(schema = "vtp-validate-csar-r130206.yaml")
public class VTPValidateCSARR130206 extends VTPValidateCSARBase {
- private static final Logger LOG = LoggerFactory.getLogger(VTPValidateCSARR130206.class);
- private static final String SHA_256 = "SHA-256";
- private static final String SHA_512 = "SHA-512";
- private static final String EMPTY_STRING = "";
-
- private final ShaHashCodeGenerator shaHashCodeGenerator = new ShaHashCodeGenerator();
- private final FileSignatureValidator fileSignatureValidator = new FileSignatureValidator();
-
- public static class CSARErrorUnableToFindCertificate extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindCertificate() {
- super("0x4001");
- this.message = "Unable to find cert file!";
- }
- }
-
- public static class CSARErrorUnableToFindCms extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindCms() {
- super("0x4002");
- this.message = "Unable to find cms signature!";
- }
- }
-
- public static class CSARErrorUnableToLoadCms extends CSARArchive.CSARError {
- CSARErrorUnableToLoadCms() {
- super("0x4002");
- this.message = "Unable to load cms signature!";
- }
- }
-
- public static class CSARErrorUnableToFindCsarContent extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindCsarContent() {
- super("0x4003");
- this.message = "Unable to find csar content!";
- }
- }
-
- public static class CSARErrorWrongHashCode extends CSARArchive.CSARError {
-
- CSARErrorWrongHashCode(String path) {
- super("0x4004");
- this.message = String.format("Source '%s' has wrong hash!", path);
- }
- }
-
- public static class CSARErrorUnableToFindAlgorithm extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindAlgorithm(String path) {
- super("0x4005");
- this.message = String.format("Source '%s' has hash, but unable to find algorithm tag!", path);
- }
- }
-
- public static class CSARErrorUnableToFindSource extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindSource(String path) {
- super("0x4006");
- this.message = String.format("Unable to calculate digest - file missing: %s", path);
- }
- }
-
- public static class CSARErrorInvalidSignature extends CSARArchive.CSARError {
-
- CSARErrorInvalidSignature() {
- super("0x4007");
- this.message = "File has invalid signature!";
- }
- }
-
- public static class CSARErrorContentMismatch extends CSARArchive.CSARError {
-
- CSARErrorContentMismatch() {
- super("0x4008");
- this.message = "Mismatch between contents of non-mano-artifact-sets and source files of the package";
- }
- }
-
- public static class CSARErrorUnableToFindEntryCertificate extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindEntryCertificate() {
- super("0x4009");
- this.message = "Unable to find cert file defined by ETSI-Entry-Certificate!";
- }
- }
-
- public static class CSARErrorEntryCertificateIsDefinedDespiteTheCms extends CSARArchive.CSARError {
-
- CSARErrorEntryCertificateIsDefinedDespiteTheCms() {
- super("0x4011");
- this.message = "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container";
- }
- }
-
- public static class CSARErrorEntryCertificateIsPresentDespiteTheCms extends CSARArchive.CSARError {
-
- CSARErrorEntryCertificateIsPresentDespiteTheCms() {
- super("0x4012");
- this.message = "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container";
- }
- }
-
- public static class CSARErrorRootCertificateIsPresentDespiteTheCms extends CSARArchive.CSARError {
-
- CSARErrorRootCertificateIsPresentDespiteTheCms() {
- super("0x4013");
- this.message = "Certificate present in root catalog despite the certificate is included in the signature container";
- }
- }
-
- public static class CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate extends CSARArchive.CSARError {
-
- CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate() {
- super("0x4013");
- this.message = "Certificate present in root catalog despite the TOSCA.meta file";
- }
- }
-
- public static class CSARErrorUnableToFindCertificateEntryInTosca extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindCertificateEntryInTosca() {
- super("0x4014");
- this.message = "Unable to find ETSI-Entry-Certificate in Tosca file";
- }
- }
-
- public static class CSARErrorUnableToFindArtifactCertificate extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindArtifactCertificate(String path) {
- super("0x4015");
- this.message = String.format("Source '%s' has signature tag, but unable to find certificate tag!", path);
- }
- }
-
- public static class CSARErrorUnableToFindArtifactCertificateFile extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindArtifactCertificateFile(String path) {
- super("0x4016");
- this.message = String.format("Source '%s' has certificate tag, pointing to non existing file!", path);
- }
- }
-
- public static class CSARErrorUnableToFindArtifactSignature extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindArtifactSignature(String path) {
- super("0x4017");
- this.message = String.format("Source '%s' has certificate tag, but unable to find signature tag!", path);
- }
- }
-
- public static class CSARErrorUnableToFindArtifactSignatureFile extends CSARArchive.CSARError {
-
- CSARErrorUnableToFindArtifactSignatureFile(String path) {
- super("0x4018");
- this.message = String.format("Source '%s' has signature tag, pointing to non existing file!", path);
- }
- }
-
- public static class CSARErrorFailToLoadArtifactSignature extends CSARArchive.CSARError {
-
- CSARErrorFailToLoadArtifactSignature(String path, String cms) {
- super("0x4019");
- this.message = String.format("Fail to load signature '%s', for source '%s'!", path, cms);
- }
- }
-
- public static class CSARErrorIncorrectArtifactSignature extends CSARArchive.CSARError {
-
- CSARErrorIncorrectArtifactSignature(String path) {
- super("0x4020");
- this.message = String.format("Source '%s' has incorrect signature!", path);
- }
- }
-
- public static class CSARWarningNoSecurity extends CSARArchive.CSARErrorWarning {
- CSARWarningNoSecurity() {
- super(EMPTY_STRING, EMPTY_STRING, -1, EMPTY_STRING);
- this.message = "Warning. Consider adding package integrity and authenticity assurance according to ETSI NFV-SOL 004 Security Option 1";
- }
- }
@Override
protected void validateCSAR(CSARArchive csar) throws OnapCommandException {
try {
- FileArchive.Workspace workspace = csar.getWorkspace();
- final Optional<Path> pathToCsarFolder = workspace.getPathToCsarFolder();
+ final Optional<Path> pathToCsarFolder = getPathToCsar(csar);
if (pathToCsarFolder.isPresent()) {
- validate(csar, pathToCsarFolder.get());
+ final CsarSecurityValidator csarSecurityValidator = new CsarSecurityValidator(csar, pathToCsarFolder.get());
+ this.errors.addAll(csarSecurityValidator.validate());
} else {
- this.errors.add(new CSARErrorUnableToFindCsarContent());
+ this.errors.add(new Error.CSARErrorUnableToFindCsarContent());
}
} catch (Exception e) {
LOG.error("Internal VTPValidateCSARR130206 command error", e);
@@ -251,263 +50,8 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase {
}
- private void validate(CSARArchive csar, Path csarRootDirectory) throws IOException, NoSuchAlgorithmException {
- if (containsCms(csar.getManifest())) {
- validateCmsSignature(csar, csarRootDirectory);
- } else if (
- (containsToscaMeta(csar) && containsCertificateInTosca(csar.getToscaMeta())) ||
- containsCertificateInRootCatalog(csar) ||
- containsPerArtifactSecurity(csar.getManifest())) {
- this.errors.add(new CSARErrorUnableToFindCms());
- } else {
- this.errors.add(new CSARWarningNoSecurity());
- }
- }
-
- private void validateCmsSignature(CSARArchive csar, Path csarRootDirectory) throws NoSuchAlgorithmException, IOException {
- try {
- CmsSignatureData signatureData = this.fileSignatureValidator.createSignatureDataForManifestFile(csar.getManifestMfFile());
- if (signatureData.getCertificate().isPresent()) {
- validateCertificationUsingCmsCertificate(signatureData, csar, csarRootDirectory);
- } else if (containsToscaMeta(csar)) {
- validateCertificationUsingTosca(signatureData, csar, csarRootDirectory);
- } else if (containsCertificateInRootCatalog(csar)) {
- validateCertificationUsingCertificateFromRootDirectory(signatureData, csar, csarRootDirectory);
- } else {
- this.errors.add(new CSARErrorUnableToFindCertificate());
- }
- } catch (CmsSignatureLoadingException e) {
- LOG.error("Unable to load CMS!", e);
- this.errors.add(new CSARErrorUnableToLoadCms());
- }
- }
-
- private boolean containsCms(CSARArchive.Manifest manifest) {
- String cms = manifest.getCms();
- return cms != null && !cms.equals(EMPTY_STRING);
- }
-
- private boolean containsToscaMeta(CSARArchive archive) {
- return archive.getToscaMetaFile() != null;
- }
-
- private boolean containsCertificateInTosca(CSARArchive.TOSCAMeta toscaMeta) {
- String certificate = toscaMeta.getEntryCertificate();
- return certificate != null && !certificate.equals(EMPTY_STRING);
- }
-
- private boolean containsCertificateInRootCatalog(CSARArchive csar) {
- File potentialCertificateFileInRootDirectory = getCertificateFromRootDirectory(csar);
- return potentialCertificateFileInRootDirectory.exists();
- }
-
- private boolean containsPerArtifactSecurity(CSARArchive.Manifest manifest) {
- return manifest.getSources().stream().anyMatch(
- source ->
- !source.getAlgorithm().equals(EMPTY_STRING) ||
- !source.getHash().equals(EMPTY_STRING) ||
- !source.getCertificate().equals(EMPTY_STRING) ||
- !source.getSignature().equals(EMPTY_STRING)
- );
- }
-
- private void validateCertificationUsingCmsCertificate(CmsSignatureData signatureData, CSARArchive csar, Path csarRootDirectory)
- throws NoSuchAlgorithmException, IOException {
- validateAllSources(csar, csarRootDirectory);
- validateFileSignature(signatureData);
- if (containsCertificateInTosca(csar.getToscaMeta())) {
- errors.add(new CSARErrorEntryCertificateIsDefinedDespiteTheCms());
- if (csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).exists()) {
- errors.add(new CSARErrorEntryCertificateIsPresentDespiteTheCms());
- }
- }
- if (containsCertificateInRootCatalog(csar)) {
- errors.add(new CSARErrorRootCertificateIsPresentDespiteTheCms());
- }
- }
-
- private void validateCertificationUsingTosca(CmsSignatureData signatureData, CSARArchive csar, Path csarRootDirectory)
- throws NoSuchAlgorithmException, IOException {
- validateAllSources(csar, csarRootDirectory);
- if (loadCertificateFromTosca(signatureData, csar)) {
- validateFileSignature(signatureData);
- }
- if (containsCertificateInRootCatalog(csar) && rootCertificateIsNotReferredAsToscaEtsiEntryCertificate(csar)) {
- errors.add(new CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate());
- }
- }
-
- private boolean loadCertificateFromTosca(CmsSignatureData signatureData, CSARArchive csar) {
- if (csar.getToscaMeta().getEntryCertificate() != null) {
- try {
- final Path absolutePathToEntryCertificate = csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).toPath();
- signatureData.loadCertificate(absolutePathToEntryCertificate);
- return true;
- } catch (CertificateLoadingException e) {
- this.errors.add(new CSARErrorUnableToFindEntryCertificate());
- return false;
- }
- } else {
- this.errors.add(new CSARErrorUnableToFindCertificateEntryInTosca());
- return false;
- }
- }
-
- private boolean rootCertificateIsNotReferredAsToscaEtsiEntryCertificate(CSARArchive csar) {
- String pathToRootCertificate = getCertificateFromRootDirectory(csar).getPath();
- String pathToEntryEtsiCertificate = csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).getPath();
- return !pathToRootCertificate.equals(pathToEntryEtsiCertificate);
- }
-
- private void validateCertificationUsingCertificateFromRootDirectory(CmsSignatureData signatureData, CSARArchive csar, Path csarRootDirectory)
- throws NoSuchAlgorithmException, IOException {
- validateAllSources(csar, csarRootDirectory);
- if (loadCertificateFromRootDirectory(signatureData, csar)) {
- validateFileSignature(signatureData);
- }
- }
-
- private boolean loadCertificateFromRootDirectory(CmsSignatureData signatureData, CSARArchive csar) {
- try {
- File certificateFileFromRootDirectory = getCertificateFromRootDirectory(csar);
- signatureData.loadCertificate(certificateFileFromRootDirectory.toPath());
- return true;
- } catch (CertificateLoadingException e) {
- LOG.error("Uable to read ETSI entry certificate file!", e);
- return false;
- }
- }
-
- private File getCertificateFromRootDirectory(CSARArchive csar) {
- String nameOfCertificate =
- csar.getManifestMfFile().getName().split("\\.")[0] +
- ".cert";
- return csar.getFileFromCsar(nameOfCertificate);
- }
-
- private void validateAllSources(CSARArchive csar, Path csarRootDirectory)
- throws NoSuchAlgorithmException, IOException {
- final CSARArchive.Manifest manifest = csar.getManifest();
- validateSources(csarRootDirectory, manifest);
-
- final Map<String, Map<String, List<String>>> nonMano = manifest.getNonMano();
- final List<SourcesParser.Source> sources = manifest.getSources();
-
- validateNonManoCohesionWithSources(nonMano, sources);
- }
-
- private void validateNonManoCohesionWithSources(final Map<String, Map<String, List<String>>> nonMano,
- final List<SourcesParser.Source> sources) {
-
- final Collection<Map<String, List<String>>> values = nonMano.values();
- final List<String> nonManoSourcePaths = values.stream()
- .map(Map::values)
- .flatMap(Collection::stream)
- .flatMap(List::stream)
- .filter(it -> !it.isEmpty())
- .collect(Collectors.toList());
-
- final List<String> sourcePaths = sources.stream()
- .map(SourcesParser.Source::getValue)
- .collect(Collectors.toList());
-
- if (!sourcePaths.containsAll(nonManoSourcePaths)) {
- this.errors.add(new CSARErrorContentMismatch());
- }
-
- }
-
- private void validateFileSignature(CmsSignatureData signatureData) {
- final boolean isValid = this.fileSignatureValidator.isValid(signatureData);
- if (!isValid) {
- this.errors.add(new CSARErrorInvalidSignature());
- }
- }
-
- private void validateSources(Path csarRootDirectory, CSARArchive.Manifest manifest)
- throws NoSuchAlgorithmException, IOException {
- final List<SourcesParser.Source> sources = manifest.getSources();
- for (SourcesParser.Source source : sources) {
- validateSource(csarRootDirectory, source);
- }
- }
-
- private void validateSource(Path csarRootDirectory, SourcesParser.Source source)
- throws NoSuchAlgorithmException, IOException {
- final Path sourcePath = csarRootDirectory.resolve(source.getValue());
- if (sourcePath.toFile().exists()) {
- validateHashIfPresent(csarRootDirectory, source);
- validateArtifactSignatureIfPresent(csarRootDirectory, source);
- } else {
- this.errors.add(new CSARErrorUnableToFindSource(source.getValue()));
- }
- }
-
- private void validateHashIfPresent(Path csarRootDirectory, SourcesParser.Source source)
- throws NoSuchAlgorithmException, IOException {
- if (!source.getAlgorithm().isEmpty()) {
- validateSourceHashCode(csarRootDirectory, source);
- } else if (source.getAlgorithm().isEmpty() && !source.getHash().isEmpty()) {
- this.errors.add(new CSARErrorUnableToFindAlgorithm(source.getValue()));
- }
- }
-
- private void validateSourceHashCode(Path csarRootDirectory, SourcesParser.Source source)
- throws NoSuchAlgorithmException, IOException {
- String hashCode = generateHashCode(csarRootDirectory, source);
- if (!hashCode.equals(source.getHash())) {
- this.errors.add(new CSARErrorWrongHashCode(source.getValue()));
- }
- }
-
- private String generateHashCode(Path csarRootDirectory, SourcesParser.Source source)
- throws NoSuchAlgorithmException, IOException {
- final byte[] sourceData = Files.readAllBytes(csarRootDirectory.resolve(source.getValue()));
- final String algorithm = source.getAlgorithm();
-
- if (algorithm.equalsIgnoreCase(SHA_256)) {
- return this.shaHashCodeGenerator.generateSha256(sourceData);
- } else if (algorithm.equalsIgnoreCase(SHA_512)) {
- return this.shaHashCodeGenerator.generateSha512(sourceData);
- }
-
- throw new UnsupportedOperationException(String.format("Algorithm '%s' is not supported!", algorithm));
- }
-
- private void validateArtifactSignatureIfPresent(Path csarRootDirectory, SourcesParser.Source source)
- throws IOException {
- if (!source.getSignature().isEmpty() && !source.getCertificate().isEmpty()) {
- validateArtifactSignature(csarRootDirectory, source);
- } else if (!source.getSignature().isEmpty()) {
- this.errors.add(new CSARErrorUnableToFindArtifactCertificate(source.getValue()));
- } else if (!source.getCertificate().isEmpty()) {
- this.errors.add(new CSARErrorUnableToFindArtifactSignature(source.getValue()));
- }
- }
-
- private void validateArtifactSignature(Path csarRootDirectory, SourcesParser.Source source)
- throws IOException {
- final Path filePath = csarRootDirectory.resolve(source.getValue());
- final Path signaturePath = csarRootDirectory.resolve(source.getSignature());
- final Path certificatePath = csarRootDirectory.resolve(source.getCertificate());
- if (signaturePath.toFile().exists() && certificatePath.toFile().exists()) {
- try {
- CmsSignatureData signatureData =
- fileSignatureValidator.createSignatureData(filePath, signaturePath, certificatePath);
- if( !fileSignatureValidator.isValid(signatureData) ) {
- this.errors.add(new CSARErrorIncorrectArtifactSignature(source.getValue()));
- }
- } catch (CmsSignatureLoadingException e) {
- this.errors.add(new CSARErrorFailToLoadArtifactSignature(source.getValue(),source.getSignature()));
- }
- } else {
- if (!signaturePath.toFile().exists()) {
- this.errors.add(new CSARErrorUnableToFindArtifactSignatureFile(source.getValue()));
- }
- if (!certificatePath.toFile().exists()) {
- this.errors.add(new CSARErrorUnableToFindArtifactCertificateFile(source.getValue()));
- }
- }
+ private Optional<Path> getPathToCsar(CSARArchive csar) {
+ return csar.getWorkspace().getPathToCsarFolder();
}
@Override
@@ -516,42 +60,4 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase {
}
- static class FileSignatureValidator {
-
- private final ManifestFileSplitter manifestFileSplitter = new ManifestFileSplitter();
- private final CmsSignatureValidator cmsSignatureValidator = new CmsSignatureValidator();
- private final CmsSignatureDataFactory cmsSignatureDataFactory = new CmsSignatureDataFactory();
-
- CmsSignatureData createSignatureDataForManifestFile(File manifestFile) throws CmsSignatureLoadingException {
- ManifestFileModel mf = manifestFileSplitter.split(manifestFile);
- return cmsSignatureDataFactory.createForFirstSigner(
- toBytes(mf.getCMS(), mf.getNewLine()),
- toBytes(mf.getData(), mf.getNewLine())
- );
- }
-
- CmsSignatureData createSignatureData(Path filePath, Path cmsFilePath, Path certFilePath) throws CmsSignatureLoadingException, IOException {
- CmsSignatureData signatureData = cmsSignatureDataFactory.createForFirstSigner(
- Files.readAllBytes(cmsFilePath),
- Files.readAllBytes(filePath)
- );
- signatureData.loadCertificate(certFilePath);
- return signatureData;
- }
-
- boolean isValid(CmsSignatureData signatureData) {
- try {
- return cmsSignatureValidator.verifySignedData(signatureData);
- } catch (CmsSignatureValidatorException e) {
- LOG.error("Unable to verify signed data!", e);
- return false;
- }
- }
-
- private byte[] toBytes(List<String> data, String newLine) {
- final String updatedData = data.stream().map(it -> it + newLine).collect(Collectors.joining());
- return updatedData.getBytes(Charset.defaultCharset());
- }
- }
-
}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSecurityValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSecurityValidator.java
new file mode 100644
index 0000000..4196136
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSecurityValidator.java
@@ -0,0 +1,220 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206;
+
+import org.onap.cvc.csar.CSARArchive;
+import org.onap.cvc.csar.parser.SourcesParser;
+import org.onap.cvc.csar.security.CertificateLoadingException;
+import org.onap.cvc.csar.security.CmsSignatureData;
+import org.onap.cvc.csar.security.CmsSignatureLoadingException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.onap.validation.csar.FileUtil.getFileNameWithoutExtension;
+
+public class CsarSecurityValidator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CsarSecurityValidator.class);
+
+ private static final String EMPTY_STRING = "";
+ public static final String CERTIFICATE_EXTENSION = ".cert";
+ private final FileSignatureValidator fileSignatureValidator = new FileSignatureValidator();
+
+ private final List<CSARArchive.CSARError> errors = new ArrayList<>();
+
+ private final CSARArchive csar;
+ private final Path csarRootDirectory;
+
+ public CsarSecurityValidator(CSARArchive csar, Path csarRootDirectory) {
+ this.csar = csar;
+ this.csarRootDirectory = csarRootDirectory;
+ }
+
+ public List<CSARArchive.CSARError> validate() throws IOException, NoSuchAlgorithmException {
+ this.errors.clear();
+ if (containsCms()) {
+ validateCsarSecurity();
+ } else if (containAnySecurityElements()) {
+ this.errors.add(new Error.CSARErrorUnableToFindCms());
+ } else {
+ this.errors.add(new Error.CSARWarningNoSecurity());
+ }
+ return errors;
+ }
+
+ private boolean containAnySecurityElements() {
+ return (containsToscaMeta() && containsCertificateInTosca()) ||
+ containsCertificateInRootCatalog() ||
+ containsPerArtifactSecurity();
+ }
+
+ private void validateCsarSecurity() throws NoSuchAlgorithmException, IOException {
+ try {
+ CmsSignatureData signatureData = this.fileSignatureValidator.createSignatureDataForManifestFile(csar.getManifestMfFile());
+ if (signatureData.getCertificate().isPresent()) {
+ validateCertificationUsingCmsCertificate(signatureData);
+ } else if (containsToscaMeta()) {
+ validateCertificationUsingTosca(signatureData);
+ } else if (containsCertificateInRootCatalog()) {
+ validateCertificationUsingCertificateFromRootDirectory(signatureData);
+ } else {
+ this.errors.add(new Error.CSARErrorUnableToFindCertificate());
+ }
+ } catch (CmsSignatureLoadingException e) {
+ LOG.error("Unable to load CMS!", e);
+ this.errors.add(new Error.CSARErrorUnableToLoadCms());
+ }
+ }
+
+ private boolean containsCms() {
+ String cms = csar.getManifest().getCms();
+ return cms != null && !cms.equals(EMPTY_STRING);
+ }
+
+ private boolean containsToscaMeta() {
+ return csar.getToscaMetaFile() != null;
+ }
+
+ private boolean containsCertificateInTosca() {
+ String certificate = csar.getToscaMeta().getEntryCertificate();
+ return certificate != null && !certificate.equals(EMPTY_STRING);
+ }
+
+ private boolean containsCertificateInRootCatalog() {
+ File potentialCertificateFileInRootDirectory = getCertificateFromRootDirectory();
+ return potentialCertificateFileInRootDirectory.exists();
+ }
+
+ private boolean containsPerArtifactSecurity() {
+ return csar.getManifest().getSources().stream().anyMatch(
+ source ->
+ !source.getAlgorithm().equals(EMPTY_STRING) ||
+ !source.getHash().equals(EMPTY_STRING) ||
+ !source.getCertificate().equals(EMPTY_STRING) ||
+ !source.getSignature().equals(EMPTY_STRING)
+ );
+ }
+
+ private void validateCertificationUsingCmsCertificate(CmsSignatureData signatureData)
+ throws NoSuchAlgorithmException, IOException {
+ validateAllSources();
+ validateFileSignature(signatureData);
+ if (containsCertificateInTosca()) {
+ this.errors.add(new Error.CSARErrorEntryCertificateIsDefinedDespiteTheCms());
+ if (csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).exists()) {
+ this.errors.add(new Error.CSARErrorEntryCertificateIsPresentDespiteTheCms());
+ }
+ }
+ if (containsCertificateInRootCatalog()) {
+ this.errors.add(new Error.CSARErrorRootCertificateIsPresentDespiteTheCms());
+ }
+ }
+
+ private void validateCertificationUsingTosca(CmsSignatureData signatureData)
+ throws NoSuchAlgorithmException, IOException {
+ Optional<Path> pathToCert = loadCertificateFromTosca();
+ if (pathToCert.isPresent()) {
+ validateAllSources(pathToCert.get());
+ signatureData.loadCertificate(pathToCert.get());
+ validateFileSignature(signatureData);
+ }
+ if (containsCertificateInRootCatalog() && rootCertificateIsNotReferredAsToscaEtsiEntryCertificate()) {
+ this.errors.add(new Error.CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate());
+ }
+ }
+
+ private Optional<Path> loadCertificateFromTosca() {
+ if (csar.getToscaMeta().getEntryCertificate() != null) {
+ final Path absolutePathToEntryCertificate = csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).toPath();
+ if (absolutePathToEntryCertificate.toFile().exists()) {
+ return Optional.of(absolutePathToEntryCertificate);
+ } else {
+ this.errors.add(new Error.CSARErrorUnableToFindEntryCertificate());
+ return Optional.empty();
+ }
+ } else {
+ this.errors.add(new Error.CSARErrorUnableToFindCertificateEntryInTosca());
+ return Optional.empty();
+ }
+ }
+
+ private boolean rootCertificateIsNotReferredAsToscaEtsiEntryCertificate() {
+ String pathToRootCertificate = getCertificateFromRootDirectory().getPath();
+ String pathToEntryEtsiCertificate = csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).getPath();
+ return !pathToRootCertificate.equals(pathToEntryEtsiCertificate);
+ }
+
+ private void validateCertificationUsingCertificateFromRootDirectory(CmsSignatureData signatureData)
+ throws NoSuchAlgorithmException, IOException {
+ Optional<Path> pathToCert = loadCertificateFromRootDirectory();
+ if (pathToCert.isPresent()) {
+ validateAllSources(pathToCert.get());
+ signatureData.loadCertificate(pathToCert.get());
+ validateFileSignature(signatureData);
+ }
+ }
+
+ private void validateFileSignature(CmsSignatureData signatureData) {
+ final boolean isValid = this.fileSignatureValidator.isValid(signatureData);
+ if (!isValid) {
+ this.errors.add(new Error.CSARErrorInvalidSignature());
+ }
+ }
+
+ private Optional<Path> loadCertificateFromRootDirectory() {
+ try {
+ Path pathToCertificateInRootDirectory = getCertificateFromRootDirectory().toPath();
+ return Optional.of(pathToCertificateInRootDirectory);
+ } catch (CertificateLoadingException e) {
+ LOG.error("Unable to read ETSI entry certificate file!", e);
+ return Optional.empty();
+ }
+ }
+
+ private File getCertificateFromRootDirectory() {
+ String nameOfCertificate =
+ getFileNameWithoutExtension(csar.getManifestMfFile().getName()) + CERTIFICATE_EXTENSION;
+ return csar.getFileFromCsar(nameOfCertificate);
+ }
+
+ private void validateAllSources()
+ throws NoSuchAlgorithmException, IOException {
+ this.errors.addAll(createCsarSourcesValidator().validate());
+ }
+
+ private void validateAllSources(Path commonCertificate)
+ throws NoSuchAlgorithmException, IOException {
+ this.errors.addAll(createCsarSourcesValidator().validate(commonCertificate));
+ }
+
+ private CsarSourcesSecurityValidator createCsarSourcesValidator() {
+ final CSARArchive.Manifest manifest = csar.getManifest();
+ final Map<String, Map<String, List<String>>> nonMano = manifest.getNonMano();
+ final List<SourcesParser.Source> sources = manifest.getSources();
+ return new CsarSourcesSecurityValidator(nonMano, sources, csarRootDirectory);
+ }
+
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourceSecurityValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourceSecurityValidator.java
new file mode 100644
index 0000000..282b37d
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourceSecurityValidator.java
@@ -0,0 +1,154 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206;
+
+import org.onap.cvc.csar.CSARArchive;
+import org.onap.cvc.csar.cc.sol004.r130206.artifact.ArtifactSecurityFileValidator;
+import org.onap.cvc.csar.cc.sol004.r130206.artifact.ArtifactSecurityFileValidatorFactory;
+import org.onap.cvc.csar.cc.sol004.r130206.artifact.ValidatedSecurityFile;
+import org.onap.cvc.csar.parser.SourcesParser;
+import org.onap.cvc.csar.security.CmsSignatureData;
+import org.onap.cvc.csar.security.CmsSignatureLoadingException;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CsarSourceSecurityValidator {
+
+ public static final String SIGNATURE_FILE_TYPE = "signature";
+ private static final String[] ARTIFACT_SIGNATURE_EXTENSIONS = {".sig.cms"};
+ public static final String CERTIFICATE_FILE_TYPE = "certificate";
+ private static final String[] ARTIFACT_CERTIFICATE_EXTENSIONS = {".cert"};
+
+ private final FileSignatureValidator fileSignatureValidator = new FileSignatureValidator();
+ private final FileHashValidator fileHashValidator = new FileHashValidator();
+
+ private final SourcesParser.Source source;
+ private final Path csarRootDirectory;
+
+ private final ArtifactSecurityFileValidator signatureValidator;
+ private final ArtifactSecurityFileValidator certificateValidator;
+
+ public CsarSourceSecurityValidator(SourcesParser.Source source, Path csarRootDirectory) {
+ this.source = source;
+ this.csarRootDirectory = csarRootDirectory;
+ ArtifactSecurityFileValidatorFactory fileValidatorFactory =
+ new ArtifactSecurityFileValidatorFactory(csarRootDirectory, source.getValue());
+ signatureValidator = fileValidatorFactory.create(source.getSignature());
+ certificateValidator = fileValidatorFactory.create(source.getCertificate());
+ }
+
+ public CsarSourceSecurityValidator(SourcesParser.Source source, Path csarRootDirectory, Path commonCert) {
+ this.source = source;
+ this.csarRootDirectory = csarRootDirectory;
+ ArtifactSecurityFileValidatorFactory fileValidatorFactory =
+ new ArtifactSecurityFileValidatorFactory(csarRootDirectory, source.getValue());
+ signatureValidator = fileValidatorFactory.create(source.getSignature());
+ certificateValidator = fileValidatorFactory.create(source.getCertificate(), commonCert);
+ }
+
+ public List<CSARArchive.CSARError> validate() throws NoSuchAlgorithmException, IOException {
+ return validateSource();
+ }
+
+ private List<CSARArchive.CSARError> validateSource()
+ throws NoSuchAlgorithmException, IOException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ final Path sourcePath = csarRootDirectory.resolve(source.getValue());
+ if (sourcePath.toFile().exists()) {
+ errors.addAll(validateHashIfPresent());
+ errors.addAll(validateArtifactSignatureIfPresent());
+ } else {
+ errors.add(new Error.CSARErrorUnableToFindSource(source.getValue()));
+ }
+ return errors;
+ }
+
+ private List<CSARArchive.CSARError> validateHashIfPresent()
+ throws NoSuchAlgorithmException, IOException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ if (!source.getAlgorithm().isEmpty()) {
+ errors.addAll(validateSourceHashCode());
+ } else if (source.getAlgorithm().isEmpty() && !source.getHash().isEmpty()) {
+ errors.add(new Error.CSARErrorUnableToFindAlgorithm(source.getValue()));
+ }
+ return errors;
+ }
+
+ private List<CSARArchive.CSARError> validateSourceHashCode()
+ throws NoSuchAlgorithmException, IOException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ if (!fileHashValidator.isValid(
+ source.getHash(), csarRootDirectory.resolve(source.getValue()), source.getAlgorithm())
+ ) {
+ errors.add(new Error.CSARErrorWrongHashCode(source.getValue()));
+ }
+ return errors;
+ }
+
+ private List<CSARArchive.CSARError> validateArtifactSignatureIfPresent()
+ throws IOException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ final boolean containsSignatureTag = !source.getSignature().isEmpty();
+ final boolean containsCertificateTag = !source.getCertificate().isEmpty();
+
+ ValidatedSecurityFile validatedSignature = signatureValidator.getValidatedSecurityFile(
+ source.getValue(), source.getSignature(), ARTIFACT_SIGNATURE_EXTENSIONS, SIGNATURE_FILE_TYPE
+ );
+ errors.addAll(validatedSignature.getErrors());
+ ValidatedSecurityFile validatedCertificate = certificateValidator.getValidatedSecurityFile(
+ source.getValue(), source.getCertificate(), ARTIFACT_CERTIFICATE_EXTENSIONS, CERTIFICATE_FILE_TYPE
+ );
+ errors.addAll(validatedCertificate.getErrors());
+
+ if (containsSignatureTag) {
+ if (validatedCertificate.isValid() && validatedSignature.isValid()) {
+ errors.addAll(
+ validateArtifactSignature(
+ csarRootDirectory.resolve(source.getValue()),
+ validatedSignature.getFilePath(), validatedCertificate.getFilePath()
+ )
+ );
+ } else if (!validatedCertificate.isValid() && !containsCertificateTag) {
+ errors.add(new Error.CSARErrorUnableToFindArtifactCertificateTag(source.getValue()));
+ }
+
+ } else if (containsCertificateTag) {
+ errors.add(new Error.CSARErrorUnableToFindArtifactSignatureTag(source.getValue()));
+ }
+ return errors;
+ }
+
+ private List<CSARArchive.CSARError> validateArtifactSignature(Path filePath, Path signaturePath, Path certificatePath)
+ throws IOException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ try {
+ final CmsSignatureData signatureData =
+ fileSignatureValidator.createSignatureData(filePath, signaturePath, certificatePath);
+ if (!fileSignatureValidator.isValid(signatureData)) {
+ errors.add(new Error.CSARErrorIncorrectArtifactSignature(source.getValue()));
+ }
+ } catch (CmsSignatureLoadingException e) {
+ errors.add(new Error.CSARErrorFailToLoadArtifactSignature(source.getValue(), source.getSignature()));
+ }
+ return errors;
+ }
+
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourcesSecurityValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourcesSecurityValidator.java
new file mode 100644
index 0000000..5db596f
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/CsarSourcesSecurityValidator.java
@@ -0,0 +1,99 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206;
+
+import org.onap.cvc.csar.CSARArchive;
+import org.onap.cvc.csar.parser.SourcesParser;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class CsarSourcesSecurityValidator {
+
+ private final Map<String, Map<String, List<String>>> nonMano;
+ private final List<SourcesParser.Source> sources;
+ private final Path csarRootDirectory;
+
+
+ public CsarSourcesSecurityValidator(
+ Map<String, Map<String, List<String>>> nonMano, List<SourcesParser.Source> sources, Path csarRootDirectory
+ ) {
+ this.nonMano = nonMano;
+ this.sources = List.copyOf(sources);
+ this.csarRootDirectory = csarRootDirectory;
+ }
+
+ public List<CSARArchive.CSARError> validate() throws IOException, NoSuchAlgorithmException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ errors.addAll(validateSources(sources));
+ errors.addAll(validateNonManoCohesionWithSources(nonMano, sources));
+ return errors;
+ }
+
+ public List<CSARArchive.CSARError> validate(Path commonCertificate) throws IOException, NoSuchAlgorithmException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ errors.addAll(validateSources(sources, commonCertificate));
+ errors.addAll(validateNonManoCohesionWithSources(nonMano, sources));
+ return errors;
+ }
+
+ private List<CSARArchive.CSARError> validateNonManoCohesionWithSources(
+ final Map<String, Map<String, List<String>>> nonMano, final List<SourcesParser.Source> sources
+ ) {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ final Collection<Map<String, List<String>>> values = nonMano.values();
+ final List<String> nonManoSourcePaths = values.stream()
+ .map(Map::values)
+ .flatMap(Collection::stream)
+ .flatMap(List::stream)
+ .filter(it -> !it.isEmpty())
+ .collect(Collectors.toList());
+
+ final List<String> sourcePaths = sources.stream()
+ .map(SourcesParser.Source::getValue)
+ .collect(Collectors.toList());
+
+ if (!sourcePaths.containsAll(nonManoSourcePaths)) {
+ errors.add(new Error.CSARErrorContentMismatch());
+ }
+ return errors;
+ }
+
+ private List<CSARArchive.CSARError> validateSources(List<SourcesParser.Source> sources)
+ throws NoSuchAlgorithmException, IOException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ for (SourcesParser.Source source : sources) {
+ errors.addAll(new CsarSourceSecurityValidator(source, csarRootDirectory).validate());
+ }
+ return errors;
+ }
+
+ private List<CSARArchive.CSARError> validateSources(List<SourcesParser.Source> sources, Path commonCertificate)
+ throws NoSuchAlgorithmException, IOException {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ for (SourcesParser.Source source : sources) {
+ errors.addAll(new CsarSourceSecurityValidator(source, csarRootDirectory, commonCertificate).validate());
+ }
+ return errors;
+ }
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/Error.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/Error.java
new file mode 100644
index 0000000..72b036f
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/Error.java
@@ -0,0 +1,226 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206;
+
+import org.onap.cvc.csar.CSARArchive;
+
+public class Error {
+
+ private static final String EMPTY_STRING = "";
+
+ public static class CSARErrorUnableToFindCertificate extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindCertificate() {
+ super("0x4001");
+ this.message = "Unable to find cert file!";
+ }
+ }
+
+ public static class CSARErrorUnableToFindCms extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindCms() {
+ super("0x4002");
+ this.message = "Unable to find cms signature!";
+ }
+ }
+
+ public static class CSARErrorUnableToLoadCms extends CSARArchive.CSARError {
+ public CSARErrorUnableToLoadCms() {
+ super("0x4002");
+ this.message = "Unable to load cms signature!";
+ }
+ }
+
+ public static class CSARErrorUnableToFindCsarContent extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindCsarContent() {
+ super("0x4003");
+ this.message = "Unable to find csar content!";
+ }
+ }
+
+ public static class CSARErrorWrongHashCode extends CSARArchive.CSARError {
+
+ public CSARErrorWrongHashCode(String path) {
+ super("0x4004");
+ this.message = String.format("Source '%s' has wrong hash!", path);
+ }
+ }
+
+ public static class CSARErrorUnableToFindAlgorithm extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindAlgorithm(String path) {
+ super("0x4005");
+ this.message = String.format("Source '%s' has hash, but unable to find algorithm tag!", path);
+ }
+ }
+
+ public static class CSARErrorUnableToFindSource extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindSource(String path) {
+ super("0x4006");
+ this.message = String.format("Unable to calculate digest - file missing: %s", path);
+ }
+ }
+
+ public static class CSARErrorInvalidSignature extends CSARArchive.CSARError {
+
+ public CSARErrorInvalidSignature() {
+ super("0x4007");
+ this.message = "Manifest file has invalid signature!";
+ this.file = "";
+ }
+ }
+
+ public static class CSARErrorContentMismatch extends CSARArchive.CSARError {
+
+ public CSARErrorContentMismatch() {
+ super("0x4008");
+ this.message = "Mismatch between contents of non-mano-artifact-sets and source files of the package";
+ }
+ }
+
+ public static class CSARErrorUnableToFindEntryCertificate extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindEntryCertificate() {
+ super("0x4009");
+ this.message = "Unable to find cert file defined by ETSI-Entry-Certificate!";
+ }
+ }
+
+ public static class CSARErrorEntryCertificateIsDefinedDespiteTheCms extends CSARArchive.CSARError {
+
+ public CSARErrorEntryCertificateIsDefinedDespiteTheCms() {
+ super("0x4011");
+ this.message = "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container";
+ }
+ }
+
+ public static class CSARErrorEntryCertificateIsPresentDespiteTheCms extends CSARArchive.CSARError {
+
+ public CSARErrorEntryCertificateIsPresentDespiteTheCms() {
+ super("0x4012");
+ this.message = "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container";
+ }
+ }
+
+ public static class CSARErrorRootCertificateIsPresentDespiteTheCms extends CSARArchive.CSARError {
+
+ public CSARErrorRootCertificateIsPresentDespiteTheCms() {
+ super("0x4013");
+ this.message = "Certificate present in root catalog despite the certificate is included in the signature container";
+ }
+ }
+
+ public static class CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate extends CSARArchive.CSARError {
+
+ public CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate() {
+ super("0x4013");
+ this.message = "Certificate present in root catalog despite the TOSCA.meta file";
+ }
+ }
+
+ public static class CSARErrorUnableToFindCertificateEntryInTosca extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindCertificateEntryInTosca() {
+ super("0x4014");
+ this.message = "Unable to find ETSI-Entry-Certificate in Tosca file";
+ }
+ }
+
+ public static class CSARErrorUnableToFindArtifactCertificateTag extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindArtifactCertificateTag(String path) {
+ super("0x4015");
+ this.message = String.format("Source '%s' has signature tag, but unable to find certificate tag!", path);
+ }
+ }
+
+ public static class CSARErrorUnableToFindArtifactSignatureTag extends CSARArchive.CSARError {
+
+ public CSARErrorUnableToFindArtifactSignatureTag(String path) {
+ super("0x4017");
+ this.message = String.format("Source '%s' has certificate tag, but unable to find signature tag!", path);
+ }
+ }
+
+ public static class CSARErrorUnableToFindArtifactSecurityFile extends CSARArchive.CSARError {
+ public CSARErrorUnableToFindArtifactSecurityFile(String path, String signatureFile, String type) {
+ super("0x4018");
+ this.message = String.format(
+ "Source '%s' has '%s' tag, pointing to non existing file!. Pointed file '%s'",
+ path, type, signatureFile);
+ }
+
+ }
+
+ public static class CSARErrorFailToLoadArtifactSignature extends CSARArchive.CSARError {
+
+ public CSARErrorFailToLoadArtifactSignature(String path, String cms) {
+ super("0x4019");
+ this.message = String.format("Fail to load signature '%s', for source '%s'!", path, cms);
+ }
+ }
+
+ public static class CSARErrorIncorrectArtifactSignature extends CSARArchive.CSARError {
+
+ public CSARErrorIncorrectArtifactSignature(String path) {
+ super("0x4020");
+ this.message = String.format("Source '%s' has incorrect signature!", path);
+ }
+ }
+
+ public static class CSARErrorWrongSecurityFileExtension extends CSARArchive.CSARError {
+
+ public CSARErrorWrongSecurityFileExtension(String path, String[] expectedExtension, String type) {
+ super("0x4021");
+ this.message = String.format(
+ "Source '%s' has '%s' file with wrong extension, expected extension: '%s'!",
+ path, type, String.join(", ", expectedExtension)
+ );
+ }
+ }
+
+ public static class CSARErrorWrongSecurityFileLocation extends CSARArchive.CSARError {
+
+ public CSARErrorWrongSecurityFileLocation(String path, String filePath, String type) {
+ super("0x4022");
+ this.message = String.format(
+ "Source '%s' has '%s' file located in wrong directory, directory: '%s'." +
+ "Signature should be in same directory as source file!",
+ path, type, filePath);
+ }
+ }
+
+ public static class CSARErrorWrongSecurityFileName extends CSARArchive.CSARError {
+
+ public CSARErrorWrongSecurityFileName(String path, String fileName, String type) {
+ super("0x4023");
+ this.message = String.format(
+ "Source '%s' has '%s' file with wrong name, signature name: '%s'." +
+ "Signature should have same name as source file!",
+ path, type, fileName);
+ }
+ }
+
+ public static class CSARWarningNoSecurity extends CSARArchive.CSARErrorWarning {
+ public CSARWarningNoSecurity() {
+ super(EMPTY_STRING, EMPTY_STRING, -1, EMPTY_STRING);
+ this.message = "Warning. Consider adding package integrity and authenticity assurance according to ETSI NFV-SOL 004 Security Option 1";
+ }
+ }
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileHashValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileHashValidator.java
new file mode 100644
index 0000000..f1412d7
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileHashValidator.java
@@ -0,0 +1,52 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206;
+
+import org.onap.cvc.csar.security.ShaHashCodeGenerator;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.NoSuchAlgorithmException;
+
+public class FileHashValidator {
+
+ private static final String SHA_256 = "SHA-256";
+ private static final String SHA_512 = "SHA-512";
+
+ private final ShaHashCodeGenerator shaHashCodeGenerator = new ShaHashCodeGenerator();
+
+ public boolean isValid(String expectedHash, Path fileToCheck, String algorithm)
+ throws NoSuchAlgorithmException, IOException {
+ String hashCode = generateHashCode(fileToCheck, algorithm);
+ return hashCode.equals(expectedHash);
+ }
+
+ private String generateHashCode(Path fileToCheck, String algorithm)
+ throws NoSuchAlgorithmException, IOException {
+ final byte[] sourceData = Files.readAllBytes(fileToCheck);
+
+ if (algorithm.equalsIgnoreCase(SHA_256)) {
+ return this.shaHashCodeGenerator.generateSha256(sourceData);
+ } else if (algorithm.equalsIgnoreCase(SHA_512)) {
+ return this.shaHashCodeGenerator.generateSha512(sourceData);
+ }
+
+ throw new UnsupportedOperationException(String.format("Algorithm '%s' is not supported!", algorithm));
+ }
+
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileSignatureValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileSignatureValidator.java
new file mode 100644
index 0000000..6e2a0c6
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/FileSignatureValidator.java
@@ -0,0 +1,76 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206;
+
+import org.onap.cvc.csar.parser.ManifestFileModel;
+import org.onap.cvc.csar.parser.ManifestFileSplitter;
+import org.onap.cvc.csar.security.CmsSignatureData;
+import org.onap.cvc.csar.security.CmsSignatureDataFactory;
+import org.onap.cvc.csar.security.CmsSignatureLoadingException;
+import org.onap.cvc.csar.security.CmsSignatureValidator;
+import org.onap.cvc.csar.security.CmsSignatureValidatorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class FileSignatureValidator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(FileSignatureValidator.class);
+
+ private final ManifestFileSplitter manifestFileSplitter = new ManifestFileSplitter();
+ private final CmsSignatureValidator cmsSignatureValidator = new CmsSignatureValidator();
+ private final CmsSignatureDataFactory cmsSignatureDataFactory = new CmsSignatureDataFactory();
+
+ CmsSignatureData createSignatureDataForManifestFile(File manifestFile) throws CmsSignatureLoadingException {
+ ManifestFileModel mf = manifestFileSplitter.split(manifestFile);
+ return cmsSignatureDataFactory.createForFirstSigner(
+ toBytes(mf.getCMS(), mf.getNewLine()),
+ toBytes(mf.getData(), mf.getNewLine())
+ );
+ }
+
+ public CmsSignatureData createSignatureData(Path filePath, Path cmsFilePath, Path certFilePath) throws CmsSignatureLoadingException, IOException {
+ CmsSignatureData signatureData = cmsSignatureDataFactory.createForFirstSigner(
+ Files.readAllBytes(cmsFilePath),
+ Files.readAllBytes(filePath)
+ );
+ signatureData.loadCertificate(certFilePath);
+ return signatureData;
+ }
+
+ public boolean isValid(CmsSignatureData signatureData) {
+ try {
+ return cmsSignatureValidator.verifySignedData(signatureData);
+ } catch (CmsSignatureValidatorException e) {
+ LOG.error("Unable to verify signed data!", e);
+ return false;
+ }
+ }
+
+ private byte[] toBytes(List<String> data, String newLine) {
+ final String updatedData = data.stream().map(it -> it + newLine).collect(Collectors.joining());
+ return updatedData.getBytes(Charset.defaultCharset());
+ }
+
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidator.java
new file mode 100644
index 0000000..53e697d
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidator.java
@@ -0,0 +1,75 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206.artifact;
+
+import org.onap.cvc.csar.CSARArchive;
+import org.onap.cvc.csar.cc.sol004.r130206.Error;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.onap.validation.csar.FileUtil.fileHaveOneOfExtensions;
+import static org.onap.validation.csar.FileUtil.filesAreInSameDirectory;
+import static org.onap.validation.csar.FileUtil.filesHaveSameNamesIgnoringExtensions;
+
+public class ArtifactSecurityFileValidator {
+
+ private final Path rootDirectory;
+ private final String artifactRelativeFilePath;
+ private final String securityRelativeFilePath;
+
+ ArtifactSecurityFileValidator(Path rootDirectory, String artifactRelativeFilePath, String securityRelativeFilePath) {
+ this.rootDirectory = rootDirectory;
+ this.artifactRelativeFilePath = artifactRelativeFilePath;
+ this.securityRelativeFilePath = securityRelativeFilePath;
+ }
+
+ public ValidatedSecurityFile getValidatedSecurityFile(
+ String pathToSourceFile, String pathToSecurityFile,
+ String[] securityFileExtensions, String securityFileType
+ ) {
+ final List<CSARArchive.CSARError> errors = new ArrayList<>();
+ Path validatedSecurityFilePath = null;
+ if(!securityRelativeFilePath.isEmpty()) {
+ final Path artifactFilePath = rootDirectory.resolve(artifactRelativeFilePath);
+ final Path securityFilePath = rootDirectory.resolve(securityRelativeFilePath);
+ if (!filesAreInSameDirectory(artifactFilePath, securityFilePath)) {
+ errors.add(
+ new Error.CSARErrorWrongSecurityFileLocation(pathToSourceFile, pathToSecurityFile, securityFileType)
+ );
+ } else if (!filesHaveSameNamesIgnoringExtensions(artifactFilePath, securityFilePath)) {
+ errors.add(
+ new Error.CSARErrorWrongSecurityFileName(pathToSourceFile, securityFilePath.getFileName().toString(), securityFileType)
+ );
+ } else if (!fileHaveOneOfExtensions(securityFilePath, securityFileExtensions)) {
+ errors.add(
+ new Error.CSARErrorWrongSecurityFileExtension(pathToSourceFile, securityFileExtensions, securityFileType)
+ );
+ } else if (!securityFilePath.toFile().exists()) {
+ errors.add(
+ new Error.CSARErrorUnableToFindArtifactSecurityFile(pathToSourceFile, pathToSecurityFile, securityFileType)
+ );
+ } else {
+ validatedSecurityFilePath = securityFilePath;
+ }
+ }
+ return new ValidatedSecurityFile(validatedSecurityFilePath,errors);
+ }
+
+
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorFactory.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorFactory.java
new file mode 100644
index 0000000..9355100
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorFactory.java
@@ -0,0 +1,40 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206.artifact;
+
+import java.nio.file.Path;
+
+public class ArtifactSecurityFileValidatorFactory {
+
+ private final Path rootDirectory;
+ private final String artifactRelativeFilePath;
+
+ public ArtifactSecurityFileValidatorFactory(Path rootDirectory, String artifactRelativeFilePath) {
+ this.rootDirectory = rootDirectory;
+ this.artifactRelativeFilePath = artifactRelativeFilePath;
+ }
+
+ public ArtifactSecurityFileValidator create(String securityRelativeFilePath) {
+ return new ArtifactSecurityFileValidator
+ (rootDirectory, artifactRelativeFilePath, securityRelativeFilePath);
+ }
+
+ public ArtifactSecurityFileValidator create(String securityRelativeFilePath, Path commonCertificate) {
+ return new ArtifactSecurityFileValidatorWithCommonFile
+ (rootDirectory, artifactRelativeFilePath, securityRelativeFilePath, commonCertificate);
+ }
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorWithCommonFile.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorWithCommonFile.java
new file mode 100644
index 0000000..ff09d5c
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ArtifactSecurityFileValidatorWithCommonFile.java
@@ -0,0 +1,40 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206.artifact;
+
+import java.nio.file.Path;
+
+public class ArtifactSecurityFileValidatorWithCommonFile extends ArtifactSecurityFileValidator {
+
+ private final Path commonSecurityFilePath;
+
+ ArtifactSecurityFileValidatorWithCommonFile(Path rootDirectory, String artifactRelativeFilePath, String securityRelativeFilePath, Path commonSecurityFilePath) {
+ super(rootDirectory, artifactRelativeFilePath, securityRelativeFilePath);
+ this.commonSecurityFilePath = commonSecurityFilePath;
+ }
+
+ @Override
+ public ValidatedSecurityFile getValidatedSecurityFile(String pathToSourceFile, String pathToSecurityFile, String[] securityFileExtensions, String securityFileType) {
+ ValidatedSecurityFile baseValidationResult =
+ super.getValidatedSecurityFile(pathToSourceFile, pathToSecurityFile, securityFileExtensions, securityFileType);
+ if(baseValidationResult.getFilePath() == null) {
+ return new ValidatedSecurityFile(commonSecurityFilePath,baseValidationResult.getErrors());
+ } else {
+ return baseValidationResult;
+ }
+ }
+}
diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ValidatedSecurityFile.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ValidatedSecurityFile.java
new file mode 100644
index 0000000..8071cad
--- /dev/null
+++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/r130206/artifact/ValidatedSecurityFile.java
@@ -0,0 +1,46 @@
+/*
+ Copyright 2020 Nokia
+ <p>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+package org.onap.cvc.csar.cc.sol004.r130206.artifact;
+
+import org.onap.cvc.csar.CSARArchive;
+
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+
+public class ValidatedSecurityFile {
+
+ private final Path filePath;
+ private final List<CSARArchive.CSARError> errors;
+
+ public ValidatedSecurityFile(Path filePath, List<CSARArchive.CSARError> errors) {
+ this.filePath = filePath;
+ this.errors = List.copyOf(errors);
+ }
+
+ public Path getFilePath() {
+ return filePath;
+ }
+
+ public List<CSARArchive.CSARError> getErrors() {
+ return Collections.unmodifiableList(errors);
+ }
+
+ public boolean isValid() {
+ return filePath != null && errors.isEmpty();
+ }
+}
diff --git a/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java b/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java
index ccf1c71..45c8db1 100644
--- a/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java
+++ b/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java
@@ -22,6 +22,8 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Path;
+import java.util.Arrays;
import java.util.zip.ZipFile;
import java.nio.file.Files;
import java.nio.file.Paths;
@@ -186,4 +188,27 @@ public final class FileUtil {
}
return isFileDeleted;
}
+
+ public static boolean filesAreInSameDirectory(Path firstFile, Path secondFile) {
+ return firstFile.getParent().equals(secondFile.getParent());
+ }
+
+ public static boolean filesHaveSameNamesIgnoringExtensions(Path firstFile, Path secondFile) {
+ return getFileNameWithoutExtension(firstFile).equals(getFileNameWithoutExtension(secondFile));
+ }
+
+ public static String getFileNameWithoutExtension(Path file){
+ String fileName = file.getFileName().toString();
+ return getFileNameWithoutExtension(fileName);
+ }
+
+ public static String getFileNameWithoutExtension(String fileName){
+ int firstDotPosition = fileName.indexOf(".");
+ return fileName.substring(0, firstDotPosition);
+ }
+
+ public static boolean fileHaveOneOfExtensions(Path file, String[] extensions) {
+ return Arrays.stream(extensions).anyMatch(extension -> file.toString().endsWith(extension));
+ }
+
}