From 25673a3551f2bf15f23afbbfe986947c6a975c91 Mon Sep 17 00:00:00 2001 From: Bartosz Gardziejewski Date: Tue, 15 Dec 2020 09:59:13 +0100 Subject: Add individual artifact validation using common cert. Signed-off-by: Bartosz Gardziejewski Change-Id: I2aa4e862f3d343a3f452e1564dc8a97a34960b83 Issue-ID: VNFSDK-714 --- .../cvc/csar/cc/sol004/VTPValidateCSARR130206.java | 510 +-------------------- 1 file changed, 8 insertions(+), 502 deletions(-) (limited to 'csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java') 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 pathToCsarFolder = workspace.getPathToCsarFolder(); + final Optional 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>> nonMano = manifest.getNonMano(); - final List sources = manifest.getSources(); - - validateNonManoCohesionWithSources(nonMano, sources); - } - - private void validateNonManoCohesionWithSources(final Map>> nonMano, - final List sources) { - - final Collection>> values = nonMano.values(); - final List nonManoSourcePaths = values.stream() - .map(Map::values) - .flatMap(Collection::stream) - .flatMap(List::stream) - .filter(it -> !it.isEmpty()) - .collect(Collectors.toList()); - - final List 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 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 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 data, String newLine) { - final String updatedData = data.stream().map(it -> it + newLine).collect(Collectors.joining()); - return updatedData.getBytes(Charset.defaultCharset()); - } - } - } -- cgit 1.2.3-korg