Validate SOL004 manifest signature order

SOL004 Manifest signature must be the last entry of the manifest.

Change-Id: Ie3835f7140ccdf92ef5518ca2d7571930de81971
Issue-ID: SDC-2587
Signed-off-by: andre.schmid <andre.schmid@est.tech>
diff --git a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java
index 2e30126..7163dbe 100644
--- a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java
+++ b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java
@@ -47,7 +47,8 @@
   MANIFEST_EXPECTED_SOURCE_PATH("Expected Source entry path"),
   MANIFEST_EXPECTED_ALGORITHM_VALUE("Expected Algorithm entry value"),
   MANIFEST_EXPECTED_ALGORITHM_BEFORE_HASH("Expected 'Algorithm' entry before 'Hash' entry"),
-  MANIFEST_DUPLICATED_CMS_SIGNATURE("Duplicated CMS signature"),
+  MANIFEST_SIGNATURE_DUPLICATED("Duplicated manifest signature"),
+  MANIFEST_SIGNATURE_LAST_ENTRY("The manifest signature must be the last entry of the manifest."),
   MANIFEST_METADATA_DOES_NOT_MATCH_LIMIT("Manifest metadata must only have the required number [%s] of entries"),
   MANIFEST_EMPTY("The manifest is empty"),
   MANIFEST_ERROR_WITH_LINE("%s;%nAt line %s: '%s'."),
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/AbstractOnboardingManifest.java b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/AbstractOnboardingManifest.java
index 7cc11e5..326eb6a 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/AbstractOnboardingManifest.java
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/AbstractOnboardingManifest.java
@@ -372,6 +372,11 @@
     }
 
     @Override
+    public boolean isSigned() {
+        return getCmsSignature().isPresent();
+    }
+
+    @Override
     public Optional<String> getCmsSignature() {
         return Optional.ofNullable(cmsSignature);
     }
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/Manifest.java b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/Manifest.java
index c0ccbbc..31b04f0 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/Manifest.java
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/Manifest.java
@@ -71,6 +71,8 @@
      */
     Optional<ResourceTypeEnum> getType();
 
+    boolean isSigned();
+
     /**
      * Gets the CMS manifest signature if present in manifest
      * @return
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboarding.java b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboarding.java
index bb0b07a..8e67d7b 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboarding.java
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboarding.java
@@ -80,7 +80,6 @@
                     break;
                 case NON_MANO_ARTIFACT_SETS:
                     processNonManoArtifactEntry();
-                    continueToProcess = false;
                     break;
                 case SOURCE:
                     processSource();
@@ -100,6 +99,9 @@
         Optional<String> currentLine = readNextNonEmptyLine();
         while (currentLine.isPresent()) {
             final ManifestTokenType manifestTokenType = detectLineEntry().orElse(null);
+            if (manifestTokenType == ManifestTokenType.CMS_BEGIN) {
+                return;
+            }
             if (manifestTokenType != null) {
                 reportError(Messages.MANIFEST_INVALID_NON_MANO_KEY, manifestTokenType.getToken());
                 continueToProcess = false;
@@ -162,25 +164,35 @@
      */
     private void readCmsSignature() {
         if (cmsSignature != null) {
-            reportError(Messages.MANIFEST_DUPLICATED_CMS_SIGNATURE);
+            reportError(Messages.MANIFEST_SIGNATURE_DUPLICATED);
             continueToProcess = false;
             return;
         }
+        final StringBuilder cmsSignatureBuilder = new StringBuilder();
+
+        cmsSignatureBuilder.append(currentLine).append("\n");
         Optional<String> currentLine = readNextNonEmptyLine();
         if(!getCurrentLine().isPresent()) {
             return;
         }
-        StringBuilder stringBuilder = new StringBuilder();
-        while (currentLine.isPresent() && detectLineEntry().orElse(null) != ManifestTokenType.CMS_END) {
-            stringBuilder.append(currentLine.get());
-            stringBuilder.append("\n");
+        while (currentLine.isPresent()) {
+            if (detectLineEntry().orElse(null) == ManifestTokenType.CMS_END) {
+                cmsSignatureBuilder.append(currentLine.get());
+                break;
+            }
+            cmsSignatureBuilder.append(currentLine.get()).append("\n");
             currentLine = readNextNonEmptyLine();
         }
 
         if (currentLine.isPresent()) {
-            cmsSignature = stringBuilder.toString();
+            cmsSignature = cmsSignatureBuilder.toString();
             readNextNonEmptyLine();
         }
+
+        if (getCurrentLine().isPresent()) {
+            reportError(Messages.MANIFEST_SIGNATURE_LAST_ENTRY);
+            continueToProcess = false;
+        }
     }
 
     /**
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboardingTest.java b/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboardingTest.java
index 7cb1511..d582163 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboardingTest.java
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/test/java/org/openecomp/sdc/tosca/csar/SOL004ManifestOnboardingTest.java
@@ -28,6 +28,7 @@
 import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
@@ -56,7 +57,7 @@
         try (final InputStream manifestAsStream =
             getClass().getResourceAsStream("/vspmanager.csar/manifest/ValidTosca.mf")) {
             manifest.parse(manifestAsStream);
-            assertValidManifest(4, 5, Collections.emptyMap(), ResourceTypeEnum.VF);
+            assertValidManifest(4, 5, Collections.emptyMap(), ResourceTypeEnum.VF, false);
         }
     }
 
@@ -104,7 +105,7 @@
             .getResourceAsStream("/vspmanager.csar/manifest/ValidNonManoTosca.mf")) {
             manifest.parse(manifestAsStream);
             assertValidManifest(4, 5,
-                ImmutableMap.of("foo_bar", 3, "prv.happy-nfv.cool", 3), ResourceTypeEnum.VF);
+                ImmutableMap.of("foo_bar", 3, "prv.happy-nfv.cool", 3), ResourceTypeEnum.VF, false);
         }
     }
 
@@ -154,7 +155,7 @@
         try (final InputStream manifestAsStream = getClass()
             .getResourceAsStream("/vspmanager.csar/manifest/valid/signed.mf")) {
             manifest.parse(manifestAsStream);
-            assertValidManifest(4, 3, Collections.emptyMap(), ResourceTypeEnum.VF);
+            assertValidManifest(4, 3, Collections.emptyMap(), ResourceTypeEnum.VF, true);
         }
     }
 
@@ -163,7 +164,7 @@
         try (final InputStream manifestAsStream = getClass()
             .getResourceAsStream("/vspmanager.csar/manifest/valid/signed-with-non-mano.mf")) {
             manifest.parse(manifestAsStream);
-            assertValidManifest(4, 3, ImmutableMap.of("foo_bar", 3), ResourceTypeEnum.VF);
+            assertValidManifest(4, 3, ImmutableMap.of("foo_bar", 3), ResourceTypeEnum.VF, true);
             manifest.getType().ifPresent(typeEnum -> assertSame(typeEnum, ResourceTypeEnum.VF));
         }
     }
@@ -173,7 +174,7 @@
         try (final InputStream manifestAsStream = getClass()
             .getResourceAsStream("/vspmanager.csar/manifest/valid/metadata-pnfd.mf")) {
             manifest.parse(manifestAsStream);
-            assertValidManifest(4, 3, new HashMap<>(), ResourceTypeEnum.PNF);
+            assertValidManifest(4, 3, new HashMap<>(), ResourceTypeEnum.PNF, true);
         }
     }
 
@@ -338,18 +339,23 @@
     }
 
     @Test
-    public void testManifestWithDuplicatedCmsSignature() throws IOException {
+    public void testManifestWithDuplicatedCmsSignature()
+        throws IOException, NoSuchFieldException, IllegalAccessException {
         try (final InputStream manifestAsStream =
-            getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/double-signed.mf")) {
+                getClass().getResourceAsStream("/vspmanager.csar/manifest/valid/signed.mf")) {
+            //forcing an existing signature
+            final Field cmsSignatureField = AbstractOnboardingManifest.class.getDeclaredField("cmsSignature");
+            cmsSignatureField.setAccessible(true);
+            cmsSignatureField.set(manifest, "any value");
             manifest.parse(manifestAsStream);
+
             final List<String> expectedErrorList = new ArrayList<>();
             expectedErrorList
-                .add(buildErrorMessage(26, "-----BEGIN CMS-----", Messages.MANIFEST_DUPLICATED_CMS_SIGNATURE));
+                .add(buildErrorMessage(18, "-----BEGIN CMS-----", Messages.MANIFEST_SIGNATURE_DUPLICATED));
             assertInvalidManifest(expectedErrorList);
         }
     }
 
-
     @Test
     public void testGetEntry() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         final Method getEntryMethod = AbstractOnboardingManifest.class.getDeclaredMethod("readEntryName", String.class);
@@ -408,7 +414,7 @@
 
     private void assertValidManifest(final int expectedMetadataSize, final int expectedSourcesSize,
                                      final Map<String, Integer> expectedNonManoKeySize,
-                                     final ResourceTypeEnum resourceType) {
+                                     final ResourceTypeEnum resourceType, final boolean isSigned) {
         assertThat("Should have no errors", manifest.getErrors(), is(empty()));
         assertThat("Should be valid", manifest.isValid(), is(true));
         assertThat("Metadata should have the expected size",
@@ -425,6 +431,7 @@
         }
         assertThat("Should have a type", manifest.getType().isPresent(), is(true));
         assertThat("Type should be as expected", manifest.getType().get(), equalTo(resourceType));
+        assertThat("Signature status should be as expected", manifest.isSigned(), is(isSigned));
     }
 
     private void assertInvalidManifest(final List<String> expectedErrorList) {
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/vspmanager.csar/manifest/invalid/double-signed.mf b/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/vspmanager.csar/manifest/invalid/double-signed.mf
deleted file mode 100644
index 88098a1..0000000
--- a/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/vspmanager.csar/manifest/invalid/double-signed.mf
+++ /dev/null
@@ -1,35 +0,0 @@
-metadata:
-  vnf_product_name: vPP
-  vnf_provider_id: Ericsson
-  vnf_package_version: R24A583
-  vnf_release_date_time: 2019-08-29T22:17:39.275281
-
-Source: scripts/userdata.file
-Algorithm: md5
-Hash: 3b119b37da5b76ec7c933168b21cedd8
-
------BEGIN CMS-----
-MIIBcwYJKoZIhvcNAQcCoIIBZDCCAWACAQMxDTALBglghkgBZQMEAgEwCwYJKoZI
-hvcNAQcBMYIBPTCCATkCAQOAFGOGMKMvLSRzUBjkgZipSoZm1U/UMAsGCWCGSAFl
-AwQCATANBgkqhkiG9w0BAQEFAASCAQBNHXz1p5NBM9Nlvp8RPoVjszzh9UfQ/OCp
-mB926MTLexWOiawjPRKuoiXn4y4dQFZBXauunCOyXYfPASUMFnhL/7gvhajPH25/
-MwEyEsUqsCyJ63tAeYxZAqTZWA2pZi9ejCPoRnt6xl7EhEyogXiSBgc2P89hxhe6
-0/MP6Mtw9D8Ks7M1LxH6ntxGApPTNRlmMtQkrx/ZUtAcKKZJoNpofzdmd+O60PMT
-igNsuwzMNy5LfSjvp8xgWoxhWr4/zLRIZ5F5Z5qhz7lia9xDSGYMfPitDCVqI9XE
-O58S/FoHu+z3Tig7vauTFFbiJjIu9SkG0c33ayEUCKejuVQPjuY9
------END CMS-----
-
-Source: scripts/userdata.file.sm
-Algorithm: md5
-Hash: 3b119b37da5b76ec7c933168b21cedd7
-
------BEGIN CMS-----
-MIIBcwYJKoZIhvcNAQcCoIIBZDCCAWACAQMxDTALBglghkgBZQMEAgEwCwYJKoZI
-hvcNAQcBMYIBPTCCATkCAQOAFGOGMKMvLSRzUBjkgZipSoZm1U/UMAsGCWCGSAFl
-AwQCATANBgkqhkiG9w0BAQEFAASCAQBNHXz1p5NBM9Nlvp8RPoVjszzh9UfQ/OCp
-mB926MTLexWOiawjPRKuoiXn4y4dQFZBXauunCOyXYfPASUMFnhL/7gvhajPH25/
-MwEyEsUqsCyJ63tAeYxZAqTZWA2pZi9ejCPoRnt6xl7EhEyogXiSBgc2P89hxhe6
-0/MP6Mtw9D8Ks7M1LxH6ntxGApPTNRlmMtQkrx/ZUtAcKKZJoNpofzdmd+O60PMT
-igNsuwzMNy5LfSjvp8xgWoxhWr4/zLRIZ5F5Z5qhz7lia9xDSGYMfPitDCVqI9XE
-O58S/FoHu+z3Tig7vauTFFbiJjIu9SkG0c33ayEUCKejuVQPjuY9
------END CMS-----
diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/vspmanager.csar/manifest/valid/signed-with-non-mano.mf b/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/vspmanager.csar/manifest/valid/signed-with-non-mano.mf
index dee6384..d6669bc 100644
--- a/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/vspmanager.csar/manifest/valid/signed-with-non-mano.mf
+++ b/openecomp-be/lib/openecomp-tosca-lib/src/test/resources/vspmanager.csar/manifest/valid/signed-with-non-mano.mf
@@ -12,6 +12,12 @@
 
 Source: scripts/userdata.file.sm
 
+non_mano_artifact_sets:
+  foo_bar:
+    Source: foobar/foo/foo.yaml
+    Source: foobar/foo/foo.script
+    Source: foobar/bar/descriptor.xml
+
 -----BEGIN CMS-----
 MIIBcwYJKoZIhvcNAQcCoIIBZDCCAWACAQMxDTALBglghkgBZQMEAgEwCwYJKoZI
 hvcNAQcBMYIBPTCCATkCAQOAFGOGMKMvLSRzUBjkgZipSoZm1U/UMAsGCWCGSAFl
@@ -22,9 +28,3 @@
 igNsuwzMNy5LfSjvp8xgWoxhWr4/zLRIZ5F5Z5qhz7lia9xDSGYMfPitDCVqI9XE
 O58S/FoHu+z3Tig7vauTFFbiJjIu9SkG0c33ayEUCKejuVQPjuY9
 -----END CMS-----
-
-non_mano_artifact_sets:
-  foo_bar:
-    Source: foobar/foo/foo.yaml
-    Source: foobar/foo/foo.script
-    Source: foobar/bar/descriptor.xml