diff options
8 files changed, 92 insertions, 54 deletions
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 fefe65b..74706c7 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 @@ -148,25 +148,32 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { validateNonManoCohesionWithSources(nonMano, sources); final File manifestMfFile = csar.getManifestMfFile(); + final String absolutePathToEntryCertificate = getAbsolutePathToEntryCertificate(csar, csarRootDirectory); if (manifestMfFile != null) { - validateFileSignature(manifestMfFile); + validateFileSignature(manifestMfFile, absolutePathToEntryCertificate); } } + private String getAbsolutePathToEntryCertificate(CSARArchive csar, Path csarRootDirectory) { + final String entryCertificateFileName = csar.getToscaMeta().getEntryCertificate(); + return String.format("%s/%s", csarRootDirectory.toAbsolutePath(), entryCertificateFileName); + } + + 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()); + .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()); + .map(SourcesParser.Source::getValue) + .collect(Collectors.toList()); if (!sourcePaths.containsAll(nonManoSourcePaths)) { this.errors.add(new CSARErrorContentMismatch()); @@ -174,8 +181,8 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } - private void validateFileSignature(File manifestMfFile) { - final boolean isValid = this.manifestFileSignatureValidator.isValid(manifestMfFile); + private void validateFileSignature(File manifestMfFile, String absolutePathToEntryCertificate) { + final boolean isValid = this.manifestFileSignatureValidator.isValid(manifestMfFile, absolutePathToEntryCertificate); if (!isValid) { this.errors.add(new CSARErrorInvalidSignature()); } @@ -205,7 +212,7 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } private void validateSources(Path csarRootDirectory, CSARArchive.Manifest manifest) - throws NoSuchAlgorithmException, IOException { + throws NoSuchAlgorithmException, IOException { final List<SourcesParser.Source> sources = manifest.getSources(); for (SourcesParser.Source source : sources) { if (!source.getAlgorithm().isEmpty() || !source.getHash().isEmpty()) { @@ -215,7 +222,7 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } private void validateSource(Path csarRootDirectory, SourcesParser.Source source) - throws NoSuchAlgorithmException, IOException { + throws NoSuchAlgorithmException, IOException { final Path sourcePath = csarRootDirectory.resolve(source.getValue()); if (!sourcePath.toFile().exists()) { this.errors.add(new CSARErrorUnableToFindSource(source.getValue())); @@ -229,7 +236,7 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } private void validateSourceHashCode(Path csarRootDirectory, SourcesParser.Source source) - throws NoSuchAlgorithmException, IOException { + throws NoSuchAlgorithmException, IOException { String hashCode = generateHashCode(csarRootDirectory, source); if (!hashCode.equals(source.getHash())) { this.errors.add(new CSARErrorWrongHashCode(source.getValue())); @@ -237,7 +244,7 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } private String generateHashCode(Path csarRootDirectory, SourcesParser.Source source) - throws NoSuchAlgorithmException, IOException { + throws NoSuchAlgorithmException, IOException { final byte[] sourceData = Files.readAllBytes(csarRootDirectory.resolve(source.getValue())); final String algorithm = source.getAlgorithm(); @@ -262,15 +269,19 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { private final ManifestFileSplitter manifestFileSplitter = new ManifestFileSplitter(); private final CmsSignatureValidator cmsSignatureValidator = new CmsSignatureValidator(); - boolean isValid(File manifestFile) { + boolean isValid(File manifestFile, String absolutePathToEntryCertificate) { try { + byte[] entryCertificate = Files.readAllBytes(new File(absolutePathToEntryCertificate).toPath()); ManifestFileModel mf = manifestFileSplitter.split(manifestFile); return cmsSignatureValidator.verifySignedData(toBytes(mf.getCMS(), mf.getNewLine()), - Optional.empty(), - toBytes(mf.getData(), mf.getNewLine())); + Optional.of(entryCertificate), + toBytes(mf.getData(), mf.getNewLine())); } catch (CmsSignatureValidatorException e) { LOG.error("Unable to verify signed data!", e); return false; + } catch (IOException e) { + LOG.error("Unable to read ETSI entry certificate file!", e); + return false; } } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java index 1061480..60bdd47 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java @@ -23,13 +23,15 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.ArrayList; -import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; @@ -115,13 +117,12 @@ public class VTPValidateCSARR972082 extends VTPValidateCSARBase { private static class ValidateNonManoSection { + private static final String ATTRIBUTE_NAME = "onap_pnf_sw_information"; + private final CSARArchive csar; private final String fileName; private final Map<String, Map<String, List<String>>> nonMano; private final List<CSARError> errors = new ArrayList<>(); - private final List<String> attributeNames = Arrays.asList( - "onap_pnf_sw_information" - ); private ValidateNonManoSection(final CSARArchive csar, final String fileName, final Map<String, Map<String, List<String>>> nonMano) { @@ -141,28 +142,20 @@ public class VTPValidateCSARR972082 extends VTPValidateCSARBase { } private List<CSARError> validate() { - if (nonMano.keySet().stream().filter(Objects::nonNull).count() > 0) { - nonMano.keySet().stream().filter(Objects::nonNull).forEach(this::validateAttribute); + List<String> attributesNotNull = nonMano.keySet().stream() + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (!attributesNotNull.isEmpty()) { + attributesNotNull.forEach(this::validateAttribute); } else { - errors.add(new PnfCSARErrorEntryMissing( - attributeNames.toString(), - fileName, - UNKNOWN_LINE_NUMBER) - ); + errors.add(new PnfCSARErrorEntryMissing(ATTRIBUTE_NAME, fileName, UNKNOWN_LINE_NUMBER)); } return errors; } private void validateAttribute(final String nonManoAttributes) { - - if (!attributeNames.contains(nonManoAttributes)) { - errors.add(new PnfCSARErrorEntryMissing( - nonManoAttributes, - fileName, - UNKNOWN_LINE_NUMBER) - ); - } else { + if (ATTRIBUTE_NAME.equals(nonManoAttributes)) { validateSourceElementsUnderAttribute(nonManoAttributes); } } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java index b8b3714..47d4bef 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java @@ -57,13 +57,14 @@ public class CmsSignatureValidator { Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners(); SignerInformation firstSigner = signers.iterator().next(); - Store certificates = signedData.getCertificates(); + Store<X509CertificateHolder> certificates = signedData.getCertificates(); + Collection<X509CertificateHolder> firstSignerCertificates = certificates.getMatches(firstSigner.getSID()); X509Certificate cert; - if (!certificate.isPresent()) { - X509CertificateHolder firstSignerFirstCertificate = getX509CertificateHolder(firstSigner, certificates); + if (!firstSignerCertificates.isEmpty()) { + X509CertificateHolder firstSignerFirstCertificate = getX509CertificateHolder(firstSignerCertificates); cert = loadCertificate(firstSignerFirstCertificate.getEncoded()); } else { - cert = loadCertificate(certificate.get()); + cert = loadCertificate(certificate.orElseThrow(() -> new CmsSignatureValidatorException("No certificate found in cms signature and ETSI-Entry-Certificate doesn't exist"))); } return firstSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert)); @@ -77,8 +78,7 @@ public class CmsSignatureValidator { } } - private X509CertificateHolder getX509CertificateHolder(SignerInformation firstSigner, Store certificates) throws CmsSignatureValidatorException { - Collection<X509CertificateHolder> firstSignerCertificates = certificates.getMatches(firstSigner.getSID()); + private X509CertificateHolder getX509CertificateHolder(Collection<X509CertificateHolder> firstSignerCertificates) throws CmsSignatureValidatorException { if(!firstSignerCertificates.iterator().hasNext()){ throw new CmsSignatureValidatorException("No certificate found in cms signature that should contain one!"); } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java index 036e169..feabe7f 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java @@ -63,6 +63,25 @@ public class VTPValidateCSARR130206IntegrationTest { } @Test + @Ignore("It is impossible to write test which will always pass, because certificate used to sign the file has time validity." + + "To verify signed package please please follow instructions from test/resources/README.txt file and comment @Ignore tag. " + + "Use instructions for option 1. Test was created for manual verification." + ) + public void manual_shouldValidateCsarWithCertificateInEtsiAndMissingInCMS() throws Exception { + + // given + configureTestCase(testCase, "pnf/r130206/csar-with-etsi-cert-without-cert-in-cms.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(0); + } + + + @Test public void shouldReportThatOnlySignatureIsInvalid() throws Exception { // given @@ -122,5 +141,23 @@ public class VTPValidateCSARR130206IntegrationTest { } + @Test + public void shouldReportThanInVnfPackageETSIFileIsMissingAndNoCertificateInCMS() throws Exception { + + // given + configureTestCase(testCase, "pnf/r130206/csar-with-no-certificate.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(convertToMessagesList(errors)).contains( + "Unable to find cert file defined by ETSI-Entry-Certificate!", + "Unable to find CMS section in manifest!" + + ); + } + } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java index 48b2d6e..66937d4 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java @@ -61,28 +61,25 @@ public class VTPValidateCSARR972082IntegrationTest { } @Test - public void shouldReportThatEntryHasInvalidPathWhenYamlFileIsNotPresent() throws Exception { + public void shouldReturnNoErrorWhenOptionalNonManoArtifactSetEntryIsNotPresent() throws Exception { // given - configureTestCase(testCase, PNF_R_972082 + "missingYamlFileReferedInSourceSessionOfManifest.csar", - VTP_VALIDATE_CSAR_R_972082_YAML, - IS_PNF); + configureTestCase(testCase, PNF_R_972082 + "missingOnapPnfSwInformationArtifactSetEntry.csar", + VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); // when testCase.execute(); // then final List<CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(1); - assertThat(convertToMessagesList(errors)).contains( - "Invalid. Entry [Source under onap_pnf_sw_information has invalid 'Files/pnf-sw-information/pnf-sw-information.yaml' path]" - ); + assertThat(errors.size()).isEqualTo(0); } @Test - public void shouldReportThatMandatoryNonManoArtifactSetEntryHasNotAllFields_() throws Exception { + public void shouldReportThatEntryHasInvalidPathWhenYamlFileIsNotPresent() throws Exception { // given - configureTestCase(testCase, PNF_R_972082 + "missingFieldsInNonManoArtifactManifest.csar", - VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); + configureTestCase(testCase, PNF_R_972082 + "missingYamlFileReferedInSourceSessionOfManifest.csar", + VTP_VALIDATE_CSAR_R_972082_YAML, + IS_PNF); // when testCase.execute(); @@ -91,7 +88,7 @@ public class VTPValidateCSARR972082IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(1); assertThat(convertToMessagesList(errors)).contains( - "Missing. Entry [[onap_pnf_sw_information]]" + "Invalid. Entry [Source under onap_pnf_sw_information has invalid 'Files/pnf-sw-information/pnf-sw-information.yaml' path]" ); } diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-with-etsi-cert-without-cert-in-cms.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-with-etsi-cert-without-cert-in-cms.csar Binary files differnew file mode 100644 index 0000000..d359994 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-with-etsi-cert-without-cert-in-cms.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-with-no-certificate.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-with-no-certificate.csar Binary files differnew file mode 100644 index 0000000..624f8fe --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-with-no-certificate.csar diff --git a/csarvalidation/src/test/resources/pnf/r972082/missingOnapPnfSwInformationArtifactSetEntry.csar b/csarvalidation/src/test/resources/pnf/r972082/missingOnapPnfSwInformationArtifactSetEntry.csar Binary files differnew file mode 100644 index 0000000..518aaa8 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r972082/missingOnapPnfSwInformationArtifactSetEntry.csar |