Verify signature 47/83847/3
authorkooper <sergey.sachkov@est.tech>
Tue, 2 Apr 2019 09:22:01 +0000 (09:22 +0000)
committerkooper <sergey.sachkov@est.tech>
Tue, 2 Apr 2019 09:22:01 +0000 (09:22 +0000)
Change-Id: I8fc5d50d74d3dd8031c96ee16708489dc7c789b8
Issue-ID: SDC-2163
Signed-off-by: kooper <sergey.sachkov@est.tech>
28 files changed:
onboarding/pom.xml
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/pom.xml
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchive.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateException.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchiveTest.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/notCsar.txt [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-directories-in-root.zip [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-directory-with-contents-in-root.zip [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-empty-directory-in-root.zip [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-files-in-root.zip [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/csar-and-cms-in-root.zip [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package-tampered-data.zip [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package.zip [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/pom.xml
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/security/SecurityManager.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/security/SecurityManagerException.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/security/SecurityManagerTest.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/dummyPnfv3.cms [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/dummyPnfv3.csar [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.cert [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.cms [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.csar [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/root.cert [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/tampered-signed-package/dummyPnfv3.cms [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/tampered-signed-package/dummyPnfv3.csar [new file with mode: 0644]
openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java

index 25db1ac..35be744 100644 (file)
         <zusammen-index-store.version>1.0.0</zusammen-index-store.version>
         <build.tools.version>${project.version}</build.tools.version>
         <togglz.version>2.4.1.Final</togglz.version>
+        <bouncycastle.version>1.61</bouncycastle.version>
     </properties>
 
     <dependencyManagement>
index 26a7c15..b1cee44 100644 (file)
             <artifactId>unique-type-rest-types</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4-common</artifactId>
+            <version>${powermock.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito2</artifactId>
+            <version>${powermock.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>${powermock.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchive.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchive.java
new file mode 100644 (file)
index 0000000..bf029fb
--- /dev/null
@@ -0,0 +1,160 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2019, Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdcrests.vsp.rest.data;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.cxf.jaxrs.ext.multipart.Attachment;
+import org.openecomp.core.utilities.file.FileContentHandler;
+import org.openecomp.sdc.common.utils.CommonUtil;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
+import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
+
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Class responsible for processing zip archive and verify if this package corresponds
+ * SOL004 option 2 signed package format, verifies the cms signature if package is signed
+ */
+public class PackageArchive {
+    private static final Logger LOG = LoggerFactory.getLogger(PackageArchive.class);
+    private static final String[] ALLOWED_ARCHIVE_EXTENSIONS = {"csar", "zip"};
+    private static final String[] ALLOWED_SIGNATURE_EXTENSIONS = {"cms"};
+    private static final String[] ALLOWED_CERTIFICATE_EXTENSIONS = {"cert"};
+    private static final int NUMBER_OF_FILES_FOR_SIGNATURE_WITH_CERT_INSIDE = 2;
+    private static final int NUMBER_OF_FILES_FOR_SIGNATURE_WITHOUT_CERT_INSIDE = 3;
+    private final SecurityManager securityManager;
+    private final byte[] outerPackageFileBytes;
+    private Pair<FileContentHandler, List<String>> handlerPair;
+
+    public PackageArchive(Attachment uploadedFile) {
+        this(uploadedFile.getObject(byte[].class));
+    }
+
+    public PackageArchive(byte[] outerPackageFileBytes) {
+        this.outerPackageFileBytes = outerPackageFileBytes;
+        this.securityManager = SecurityManager.getInstance();
+        try {
+            handlerPair = CommonUtil.getFileContentMapFromOrchestrationCandidateZip(
+                    outerPackageFileBytes);
+        } catch (IOException exception) {
+            LOG.error("Error reading files inside archive", exception);
+        }
+    }
+
+    /**
+     * Checks if package matches required format {package.csar/zip, package.cms, package.cert(optional)}
+     *
+     * @return true if structure matches sol004 option 2 structure
+     */
+    public boolean isSigned() {
+        return isPackageSizeMatches() && getSignatureFileName().isPresent();
+    }
+
+    /**
+     * Gets csar/zip package name with extension only if package is signed
+     *
+     * @return csar package name
+     */
+    public Optional<String> getArchiveFileName() {
+        if (isSigned()) {
+            return getFileByExtension(ALLOWED_ARCHIVE_EXTENSIONS);
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Gets csar/zip package content from zip archive
+     * @return csar package content
+     * @throws SecurityManagerException
+     */
+    public byte[] getPackageFileContents() throws SecurityManagerException {
+        try {
+            if (isSignatureValid()) {
+                return handlerPair.getKey().getFiles().get(getArchiveFileName().orElseThrow(CertificateException::new));
+            }
+        } catch (CertificateException exception) {
+            LOG.info("Error verifying signature " + exception);
+        }
+        return outerPackageFileBytes;
+    }
+
+    /**
+     * Validates package signature against trusted certificates
+     * @return true if signature verified
+     * @throws SecurityManagerException
+     */
+    public boolean isSignatureValid() throws SecurityManagerException {
+        Map<String, byte[]> files = handlerPair.getLeft().getFiles();
+        Optional<String> signatureFileName = getSignatureFileName();
+        Optional<String> archiveFileName = getArchiveFileName();
+        if (files.isEmpty() || !signatureFileName.isPresent() || !archiveFileName.isPresent()) {
+            return false;
+        }
+        Optional<String> certificateFile = getCertificateFileName();
+        if(certificateFile.isPresent()){
+            return securityManager.verifySignedData(files.get(signatureFileName.get()),
+                    files.get(certificateFile.get()), files.get(archiveFileName.get()));
+        }else {
+            return securityManager.verifySignedData(files.get(signatureFileName.get()),
+                    null, files.get(archiveFileName.get()));
+        }
+    }
+
+    private boolean isPackageSizeMatches() {
+        return handlerPair.getRight().isEmpty()
+                && (handlerPair.getLeft().getFiles().size() == NUMBER_OF_FILES_FOR_SIGNATURE_WITH_CERT_INSIDE
+                || handlerPair.getLeft().getFiles().size() == NUMBER_OF_FILES_FOR_SIGNATURE_WITHOUT_CERT_INSIDE);
+    }
+
+    private Optional<String> getSignatureFileName() {
+        return getFileByExtension(ALLOWED_SIGNATURE_EXTENSIONS);
+    }
+
+    private Optional<String> getFileByExtension(String[] extensions) {
+        for (String fileName : handlerPair.getLeft().getFileList()) {
+            for (String extension : extensions) {
+                if (extension.equalsIgnoreCase(FilenameUtils.getExtension(fileName))) {
+                    return Optional.of(fileName);
+                }
+            }
+        }
+        return Optional.empty();
+    }
+
+    private Optional<String> getCertificateFileName() {
+        Optional<String> certFileName = getFileByExtension(ALLOWED_CERTIFICATE_EXTENSIONS);
+        if(!certFileName.isPresent()){
+            return Optional.empty();
+        }
+        String certNameWithoutExtension = FilenameUtils.removeExtension(certFileName.get());
+        if (certNameWithoutExtension.equals(FilenameUtils.removeExtension(getArchiveFileName().orElse("")))) {
+            return certFileName;
+        }
+        //cert file name should be the same as package name, e.g. vnfpackage.scar-->vnfpackage.cert
+        return Optional.empty();
+    }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateException.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateException.java
new file mode 100644 (file)
index 0000000..a7e65a7
--- /dev/null
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2019, Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.openecomp.sdcrests.vsp.rest.services;
+
+public class OrchestrationTemplateCandidateException extends Exception{
+
+    public OrchestrationTemplateCandidateException(String message, Throwable t){
+        super(message, t);
+    }
+}
index bdc422d..4978b3f 100644 (file)
@@ -25,6 +25,7 @@ import org.openecomp.sdc.activitylog.ActivityLogManagerFactory;
 import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity;
 import org.openecomp.sdc.activitylog.dao.type.ActivityType;
 import org.openecomp.sdc.common.errors.Messages;
+import org.openecomp.sdc.common.utils.SdcCommon;
 import org.openecomp.sdc.datatypes.error.ErrorLevel;
 import org.openecomp.sdc.datatypes.error.ErrorMessage;
 import org.openecomp.sdc.logging.api.Logger;
@@ -33,6 +34,7 @@ import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateMan
 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory;
 import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
 import org.openecomp.sdc.vendorsoftwareproduct.VspManagerFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
 import org.openecomp.sdc.vendorsoftwareproduct.types.OrchestrationTemplateActionResponse;
 import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse;
 import org.openecomp.sdc.vendorsoftwareproduct.types.ValidationResponse;
@@ -43,6 +45,7 @@ import org.openecomp.sdcrests.vendorsoftwareproducts.types.OrchestrationTemplate
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
 import org.openecomp.sdcrests.vendorsoftwareproducts.types.ValidationResponseDto;
 import org.openecomp.sdcrests.vsp.rest.OrchestrationTemplateCandidate;
+import org.openecomp.sdcrests.vsp.rest.data.PackageArchive;
 import org.openecomp.sdcrests.vsp.rest.mapping.MapFilesDataStructureToDto;
 import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto;
 import org.openecomp.sdcrests.vsp.rest.mapping.MapValidationResponseToDto;
@@ -51,9 +54,13 @@ import org.springframework.stereotype.Service;
 
 import javax.inject.Named;
 import javax.ws.rs.core.Response;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 import static org.openecomp.core.utilities.file.FileUtils.getFileExtension;
@@ -75,18 +82,46 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
 
   @Override
   public Response upload(String vspId, String versionId, Attachment fileToUpload, String user) {
+    PackageArchive archive = new PackageArchive(fileToUpload.getObject(byte[].class));
+    UploadFileResponseDto uploadFileResponseDto;
+    try {
+      if (archive.isSigned() && !archive.isSignatureValid()) {
+        ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR,
+                getErrorWithParameters(Messages.FAILED_TO_VERIFY_SIGNATURE.getErrorMessage(), ""));
+        LOGGER.error(errorMessage.getMessage());
+        uploadFileResponseDto = buildUploadResponseWithError(errorMessage);
+        //returning OK as SDC UI won't show error message if NOT OK error code.
+        return Response.ok(uploadFileResponseDto).build();
+      }
 
-    String filename = fileToUpload.getContentDisposition().getParameter("filename");
-    UploadFileResponse uploadFileResponse = candidateManager
-        .upload(vspId, new Version(versionId), fileToUpload.getObject(InputStream.class),
-            getFileExtension(filename), getNetworkPackageName(filename));
-
-    UploadFileResponseDto uploadFileResponseDto = new MapUploadFileResponseToUploadFileResponseDto()
-        .applyMapping(uploadFileResponse, UploadFileResponseDto.class);
-
+      String filename = archive.getArchiveFileName().orElse(fileToUpload.getContentDisposition().getFilename());
+      UploadFileResponse uploadFileResponse = candidateManager
+              .upload(vspId, new Version(versionId), new ByteArrayInputStream(archive.getPackageFileContents()),
+                      getFileExtension(filename), getNetworkPackageName(filename));
+
+      uploadFileResponseDto = new MapUploadFileResponseToUploadFileResponseDto()
+              .applyMapping(uploadFileResponse, UploadFileResponseDto.class);
+    } catch (SecurityManagerException e) {
+      ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR,
+              getErrorWithParameters(e.getMessage(), ""));
+      LOGGER.error(errorMessage.getMessage(), e);
+      uploadFileResponseDto = buildUploadResponseWithError(errorMessage);
+      //returning OK as SDC UI won't show error message if NOT OK error code.
+      return Response.ok(uploadFileResponseDto).build();
+    }
     return Response.ok(uploadFileResponseDto).build();
   }
 
+  private UploadFileResponseDto buildUploadResponseWithError(ErrorMessage errorMessage) {
+    UploadFileResponseDto uploadFileResponseDto = new UploadFileResponseDto();
+    Map<String, List<ErrorMessage>> errorMap = new HashMap<>();
+    List<ErrorMessage> errorMessages = new ArrayList<>();
+    errorMessages.add(errorMessage);
+    errorMap.put(SdcCommon.UPLOAD_FILE, errorMessages);
+    uploadFileResponseDto.setErrors(errorMap);
+    return uploadFileResponseDto;
+  }
+
   @Override
   public Response get(String vspId, String versionId, String user) throws IOException {
     Optional<Pair<String, byte[]>> zipFile = candidateManager.get(vspId, new Version(versionId));
@@ -146,7 +181,7 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
       String errorWithParameters = ErrorMessagesFormatBuilder
           .getErrorWithParameters(Messages.MAPPING_OBJECTS_FAILURE.getErrorMessage(),
               fileDataStructureDto.toString(), fileDataStructure.toString());
-      throw new Exception(errorWithParameters, exception);
+      throw new OrchestrationTemplateCandidateException(errorWithParameters, exception);
     }
     ValidationResponse response = candidateManager
         .updateFilesDataStructure(vspId, new Version(versionId), fileDataStructure);
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchiveTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchiveTest.java
new file mode 100644 (file)
index 0000000..6458a65
--- /dev/null
@@ -0,0 +1,99 @@
+package org.openecomp.sdcrests.vsp.rest.data;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
+import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
+import org.powermock.reflect.Whitebox;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+public class PackageArchiveTest {
+    private static final String BASE_DIR = "/vspmanager.csar/";
+
+    @Mock
+    SecurityManager manager;
+
+    @Before
+    public void setUp(){
+        initMocks(this);
+    }
+
+
+    @Test
+    public void isSignedTestCheckingWrongFile() throws IOException,
+            URISyntaxException {
+        PackageArchive packageArchive = getArchive("notCsar.txt");
+        assertFalse("2 or 3 files expected for signed package present or signature valid for " +
+                "empty file", packageArchive.isSigned());
+    }
+
+    @Test
+    public void isSignedTestWrongPackageStructure2EmptyDirInRoot() throws IOException,
+            URISyntaxException {
+        PackageArchive packageArchive = getArchive("signing/2-empty-directories-in-root.zip");
+        assertFalse(packageArchive.isSigned());
+    }
+
+    @Test
+    public void isSignedTestWrongPackageStructure2EmptyFilesAndEmptyDirInRoot() throws IOException,
+            URISyntaxException {
+        PackageArchive packageArchive = getArchive("signing/2-empty-files-1-empty-directory-in-root.zip");
+        assertFalse(packageArchive.isSigned());
+    }
+
+    @Test
+    public void isSignedTestWrongPackageStructure2EmptyFilesAndDirWithContentInRoot() throws IOException,
+            URISyntaxException {
+        PackageArchive packageArchive = getArchive("signing/2-empty-files-1-directory-with-contents-in-root.zip");
+        assertFalse(packageArchive.isSigned());
+    }
+
+    @Test
+    public void isSignedTestCorrectStructureNoSignature() throws IOException,
+            URISyntaxException {
+        PackageArchive packageArchive = getArchive("signing/2-files-in-root.zip");
+        assertFalse(packageArchive.isSigned());
+    }
+
+    @Test
+    public void isSignedTestCorrectStructureAndSignatureExists() throws IOException,
+            URISyntaxException {
+        PackageArchive packageArchive = getArchive("signing/csar-and-cms-in-root.zip");
+        assertTrue(packageArchive.isSigned());
+    }
+
+    @Test
+    public void isSignatureValidTestCorrectStructureAndValidSignatureExists() throws IOException,
+            URISyntaxException, SecurityManagerException {
+        PackageArchive packageArchive = getArchive("signing/signed-package.zip");
+        Whitebox.setInternalState(packageArchive, "securityManager", manager);
+        when(manager.verifySignedData(any(), any(), any())).thenReturn(true);
+        assertTrue("Signature invalid for signed package",
+                packageArchive.isSignatureValid());
+    }
+
+    @Test(expected = SecurityManagerException.class)
+    public void isSignatureValidTestCorrectStructureAndNotValidSignatureExists() throws IOException,
+            URISyntaxException, SecurityManagerException {
+        PackageArchive packageArchive = getArchive("signing/signed-package-tampered-data.zip");
+        Whitebox.setInternalState(packageArchive, "securityManager", manager);
+        when(manager.verifySignedData(any(), any(), any())).thenThrow(new SecurityManagerException("error!"));
+        packageArchive.isSignatureValid();
+    }
+
+    private PackageArchive getArchive(String path) throws URISyntaxException, IOException {
+        return new PackageArchive(Files.readAllBytes(Paths.get(
+                PackageArchiveTest.class.getResource(BASE_DIR + path).toURI())));
+    }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java
new file mode 100644 (file)
index 0000000..2dc6cd7
--- /dev/null
@@ -0,0 +1,121 @@
+package org.openecomp.sdcrests.vsp.rest.services;
+
+import org.apache.cxf.jaxrs.ext.multipart.Attachment;
+import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
+import org.openecomp.sdc.activitylog.ActivityLogManager;
+import org.openecomp.sdc.activitylog.ActivityLogManagerFactory;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager;
+import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
+import org.openecomp.sdc.vendorsoftwareproduct.VspManagerFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
+import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
+import org.openecomp.sdcrests.vsp.rest.data.PackageArchive;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import javax.ws.rs.core.Response;
+
+import java.util.Optional;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.powermock.api.mockito.PowerMockito.mock;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.when;
+import static org.powermock.api.mockito.PowerMockito.whenNew;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({VspManagerFactory.class, ActivityLogManagerFactory.class,
+        OrchestrationTemplateCandidateManagerFactory.class, OrchestrationTemplateCandidateImpl.class})
+public class OrchestrationTemplateCandidateImplTest {
+
+    Logger logger = LoggerFactory.getLogger(OrchestrationTemplateCandidateImplTest.class);
+    @Mock
+    private OrchestrationTemplateCandidateManager candidateManager;
+    @Mock
+    private VendorSoftwareProductManager vendorSoftwareProductManager;
+    @Mock
+    private PackageArchive packageArchive;
+    @Mock
+    private VspManagerFactory vspManagerFactory;
+    @Mock
+    private ActivityLogManager activityLogManager;
+    @Mock
+    private ActivityLogManagerFactory activityLogManagerFactory;
+    @Mock
+    OrchestrationTemplateCandidateManagerFactory orchestrationTemplateCandidateManagerFactory;
+
+    private OrchestrationTemplateCandidateImpl orchestrationTemplateCandidate;
+
+    @Before
+    public void setUp(){
+        try {
+            initMocks(this);
+            packageArchive = mock(PackageArchive.class);
+            mockStatic(VspManagerFactory.class);
+            when(VspManagerFactory.getInstance()).thenReturn(vspManagerFactory);
+            when(vspManagerFactory.createInterface()).thenReturn(vendorSoftwareProductManager);
+            mockStatic(ActivityLogManagerFactory.class);
+            when(ActivityLogManagerFactory.getInstance()).thenReturn(activityLogManagerFactory);
+            when(activityLogManagerFactory.createInterface()).thenReturn(activityLogManager);
+            whenNew(PackageArchive.class).withAnyArguments().thenReturn(packageArchive);
+            mockStatic(OrchestrationTemplateCandidateManagerFactory.class);
+            when(OrchestrationTemplateCandidateManagerFactory.getInstance()).thenReturn(orchestrationTemplateCandidateManagerFactory);
+            when(orchestrationTemplateCandidateManagerFactory.createInterface()).thenReturn(candidateManager);
+            when(packageArchive.getArchiveFileName()).thenReturn(Optional.of("test"));
+            when(packageArchive.getPackageFileContents()).thenReturn(new byte[0]);
+            UploadFileResponse uploadFileResponse = new UploadFileResponse();
+            uploadFileResponse.setOnboardingType(OnboardingTypesEnum.ZIP);
+            uploadFileResponse.setNetworkPackageName("test");
+            when(candidateManager.upload(any(), any(), any(), any(), any())).thenReturn(uploadFileResponse);
+        }catch (Exception e){
+           logger.error(e.getMessage(), e);
+        }
+    }
+
+    @Test
+    public void uploadSignedTest() throws SecurityManagerException {
+        when(packageArchive.isSigned()).thenReturn(true);
+        when(packageArchive.isSignatureValid()).thenReturn(true);
+        orchestrationTemplateCandidate = new OrchestrationTemplateCandidateImpl();
+        Attachment attachment = mock(Attachment.class);
+        when(attachment.getContentDisposition()).thenReturn(new ContentDisposition("test"));
+        Response response = orchestrationTemplateCandidate.upload("1", "1", attachment, "1");
+        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+
+    }
+
+    @Test
+    public void uploadNotSignedTest(){
+        when(packageArchive.isSigned()).thenReturn(false);
+        orchestrationTemplateCandidate = new OrchestrationTemplateCandidateImpl();
+        Attachment attachment = mock(Attachment.class);
+        when(attachment.getContentDisposition()).thenReturn(new ContentDisposition("test"));
+        Response response = orchestrationTemplateCandidate.upload("1", "1", attachment, "1");
+        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+
+    }
+
+    @Test
+    public void uploadSignNotValidTest() throws SecurityManagerException {
+        when(packageArchive.isSigned()).thenReturn(true);
+        when(packageArchive.isSignatureValid()).thenReturn(false);
+        orchestrationTemplateCandidate = new OrchestrationTemplateCandidateImpl();
+        Attachment attachment = mock(Attachment.class);
+        when(attachment.getContentDisposition()).thenReturn(new ContentDisposition("test"));
+        Response response = orchestrationTemplateCandidate.upload("1", "1", attachment, "1");
+        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+        assertFalse(((UploadFileResponseDto)response.getEntity()).getErrors().isEmpty());
+
+    }
+}
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/notCsar.txt b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/notCsar.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-directories-in-root.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-directories-in-root.zip
new file mode 100644 (file)
index 0000000..d0f1fd0
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-directories-in-root.zip differ
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-directory-with-contents-in-root.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-directory-with-contents-in-root.zip
new file mode 100644 (file)
index 0000000..0f10af2
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-directory-with-contents-in-root.zip differ
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-empty-directory-in-root.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-empty-directory-in-root.zip
new file mode 100644 (file)
index 0000000..6ded8b1
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-empty-files-1-empty-directory-in-root.zip differ
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-files-in-root.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-files-in-root.zip
new file mode 100644 (file)
index 0000000..d1e80ae
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/2-files-in-root.zip differ
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/csar-and-cms-in-root.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/csar-and-cms-in-root.zip
new file mode 100644 (file)
index 0000000..0733146
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/csar-and-cms-in-root.zip differ
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package-tampered-data.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package-tampered-data.zip
new file mode 100644 (file)
index 0000000..0cfb9e0
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package-tampered-data.zip differ
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package.zip
new file mode 100644 (file)
index 0000000..a64ddd9
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/vspmanager.csar/signing/signed-package.zip differ
index 66f04f1..74a691b 100644 (file)
             <artifactId>openecomp-tosca-converter-core</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+            <version>${bouncycastle.version}</version>
+        </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
index d2da7ef..7b1890d 100644 (file)
 package org.openecomp.sdc.vendorsoftwareproduct.security;
 
 import com.google.common.collect.ImmutableSet;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.util.Store;
 import org.openecomp.sdc.logging.api.Logger;
 import org.openecomp.sdc.logging.api.LoggerFactory;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertStore;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
 import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathBuilderResult;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
 /**
- * This is temporary solution. When AAF provides functionality for verifying certificates, this class should be reviewed
- * Class is responsible for providing root certificates from configured location in onboarding container.
+ * This is temporary solution. When AAF provides functionality for verifying trustedCertificates, this class should be reviewed
+ * Class is responsible for providing root trustedCertificates from configured location in onboarding container.
  */
 public class SecurityManager {
-    private static final String CERTIFICATE_DEFAULT_LOCATION = "/root/cert";
+    private static final String CERTIFICATE_DEFAULT_LOCATION = "cert";
+    private static final SecurityManager INSTANCE = new SecurityManager();
 
     private Logger logger = LoggerFactory.getLogger(SecurityManager.class);
-    private Set<Certificate> certificates = new HashSet<>();
+    private Set<X509Certificate> trustedCertificates = new HashSet<>();
     private File certificateDirectory;
 
+    static {
+        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+            Security.addProvider(new BouncyCastleProvider());
+        }
+    }
 
-    public SecurityManager(){
+    private SecurityManager() {
         certificateDirectory = this.getcertDirectory();
     }
 
-    private void processCertificateDir() {
-        if(!certificateDirectory.exists() || !certificateDirectory.isDirectory()){
+    public static SecurityManager getInstance(){
+        return INSTANCE;
+    }
+
+    /**
+     *
+     * Checks the configured location for available trustedCertificates
+     *
+     * @return set of trustedCertificates
+     * @throws SecurityManagerException
+     */
+    public Set<X509Certificate> getTrustedCertificates() throws SecurityManagerException {
+        //if file number in certificate directory changed reload certs
+        String[] certFiles = certificateDirectory.list();
+        if (certFiles == null) {
+            logger.error("Certificate directory is empty!");
+            return ImmutableSet.copyOf(new HashSet<>());
+        }
+        if (trustedCertificates.size() != certFiles.length) {
+            trustedCertificates = new HashSet<>();
+            processCertificateDir();
+        }
+        return ImmutableSet.copyOf(trustedCertificates);
+    }
+
+    /**
+     * Cleans certificate collection
+     */
+    public void cleanTrustedCertificates(){
+        trustedCertificates.clear();
+    }
+
+    /**
+     *
+     * Verifies if packaged signed with trusted certificate
+     *
+     * @param messageSyntaxSignature - signature data in cms format
+     * @param packageCert            - package certificate if not part of cms signature, can be null
+     * @param innerPackageFile       data package signed with cms signature
+     * @return true if signature verified
+     * @throws SecurityManagerException
+     */
+    public boolean verifySignedData(final byte[] messageSyntaxSignature, final byte[] packageCert,
+                                    final byte[] innerPackageFile) throws SecurityManagerException{
+        try (ByteArrayInputStream signatureStream = new ByteArrayInputStream(messageSyntaxSignature)) {
+            Object parsedObject = new PEMParser(new InputStreamReader(signatureStream)).readObject();
+            if (!(parsedObject instanceof ContentInfo)) {
+                throw new SecurityManagerException("Signature is not recognized");
+            }
+            ContentInfo signature = ContentInfo.getInstance(parsedObject);
+            CMSTypedData signedContent = new CMSProcessableByteArray(innerPackageFile);
+            CMSSignedData signedData = new CMSSignedData(signedContent, signature);
+
+            Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
+            SignerInformation firstSigner = signers.iterator().next();
+            Store certificates = signedData.getCertificates();
+            X509Certificate cert;
+            if (packageCert == null) {
+                Collection<X509CertificateHolder> firstSignerCertificates = certificates.getMatches(firstSigner.getSID());
+                if(!firstSignerCertificates.iterator().hasNext()){
+                    throw new SecurityManagerException("No certificate found in cms signature that should contain one!");
+                }
+                X509CertificateHolder firstSignerFirstCertificate = firstSignerCertificates.iterator().next();
+                cert = loadCertificate(firstSignerFirstCertificate.getEncoded());
+            } else {
+                cert = loadCertificate(packageCert);
+            }
+
+            PKIXCertPathBuilderResult result = verifyCertificate(cert, getTrustedCertificates());
+
+            if (result == null) {
+                return false;
+            }
+
+            return firstSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert));
+        } catch (OperatorCreationException | IOException | CMSException e) {
+            logger.error(e.getMessage(), e);
+            throw new SecurityManagerException("Unexpected error occurred during signature validation!", e);
+        } catch (GeneralSecurityException e){
+            throw new SecurityManagerException("Could not verify signature!", e);
+        }
+    }
+
+    private void processCertificateDir() throws SecurityManagerException {
+        if (!certificateDirectory.exists() || !certificateDirectory.isDirectory()) {
             logger.error("Issue with certificate directory, check if exists!");
             return;
         }
 
-        File [] files = certificateDirectory.listFiles();
-        if(files == null){
+        File[] files = certificateDirectory.listFiles();
+        if (files == null) {
             logger.error("Certificate directory is empty!");
             return;
         }
-        for(File f : files) {
-            certificates.add(loadCertificate(f));
+        for (File f : files) {
+            trustedCertificates.add(loadCertificate(f));
         }
     }
 
     private File getcertDirectory() {
         String certDirLocation = System.getenv("SDC_CERT_DIR");
-        if(certDirLocation == null){
+        if (certDirLocation == null) {
             certDirLocation = CERTIFICATE_DEFAULT_LOCATION;
         }
         return new File(certDirLocation);
     }
 
-    private Certificate loadCertificate(File certFile){
-        try (InputStream fileInputStream = new FileInputStream(certFile)){
+    private X509Certificate loadCertificate(File certFile) throws SecurityManagerException {
+        try (InputStream fileInputStream = new FileInputStream(certFile)) {
             CertificateFactory factory = CertificateFactory.getInstance("X.509");
-            return factory.generateCertificate(fileInputStream);
-        } catch (CertificateException|IOException e) {
+            return (X509Certificate) factory.generateCertificate(fileInputStream);
+        } catch (CertificateException | IOException e) {
             throw new SecurityManagerException("Error during loading Certificate file!", e);
         }
     }
 
-    /**
-     * Checks the configured location for available certificates
-     * @return set of certificates
-     */
-    public Set<Certificate> getCertificates() {
-        //if file number in certificate directory changed reload certs
-        String[] certFiles = certificateDirectory.list();
-        if(certFiles == null){
-            logger.error("Certificate directory is empty!");
-            return ImmutableSet.copyOf(new HashSet<>());
+    private X509Certificate loadCertificate(byte[] certFile) throws SecurityManagerException {
+        try (InputStream in = new ByteArrayInputStream(certFile)) {
+            CertificateFactory factory = CertificateFactory.getInstance("X.509");
+            return (X509Certificate) factory.generateCertificate(in);
+        } catch (CertificateException | IOException e) {
+            throw new SecurityManagerException("Error during loading Certificate from bytes!", e);
         }
-        if(certificates.size() != certFiles.length){
-            certificates = new HashSet<>();
-            processCertificateDir();
+    }
+
+    private PKIXCertPathBuilderResult verifyCertificate(X509Certificate cert,
+                                                        Set<X509Certificate> additionalCerts) throws GeneralSecurityException, SecurityManagerException {
+            if (null == cert) {
+                throw new SecurityManagerException("The certificate is empty!");
+            }
+
+            if (isExpired(cert)) {
+                throw new SecurityManagerException("The certificate expired on: " + cert.getNotAfter());
+            }
+
+            if (isSelfSigned(cert)) {
+                throw new SecurityManagerException("The certificate is self-signed.");
+            }
+
+            Set<X509Certificate> trustedRootCerts = new HashSet<>();
+            Set<X509Certificate> intermediateCerts = new HashSet<>();
+            for (X509Certificate additionalCert : additionalCerts) {
+                if (isSelfSigned(additionalCert)) {
+                    trustedRootCerts.add(additionalCert);
+                } else {
+                    intermediateCerts.add(additionalCert);
+                }
+            }
+
+            return verifyCertificate(cert, trustedRootCerts, intermediateCerts);
+    }
+
+    private PKIXCertPathBuilderResult verifyCertificate(X509Certificate cert,
+                                                        Set<X509Certificate> allTrustedRootCerts,
+                                                        Set<X509Certificate> allIntermediateCerts)
+            throws GeneralSecurityException {
+
+        // Create the selector that specifies the starting certificate
+        X509CertSelector selector = new X509CertSelector();
+        selector.setCertificate(cert);
+
+        // Create the trust anchors (set of root CA certificates)
+        Set<TrustAnchor> trustAnchors = new HashSet<>();
+        for (X509Certificate trustedRootCert : allTrustedRootCerts) {
+            trustAnchors.add(new TrustAnchor(trustedRootCert, null));
+        }
+
+        // Configure the PKIX certificate builder algorithm parameters
+        PKIXBuilderParameters pkixParams;
+        try {
+            pkixParams = new PKIXBuilderParameters(trustAnchors, selector);
+        } catch (InvalidAlgorithmParameterException ex) {
+            throw new InvalidAlgorithmParameterException("No root CA has been found for this certificate", ex);
+        }
+
+        // Not supporting CRL checks for now
+        pkixParams.setRevocationEnabled(false);
+
+        Set<X509Certificate> certSet = new HashSet<>();
+        certSet.add(cert);
+        pkixParams.addCertStore(createCertStore(certSet));
+        pkixParams.addCertStore(createCertStore(allIntermediateCerts));
+        pkixParams.addCertStore(createCertStore(allTrustedRootCerts));
+
+        CertPathBuilder builder = CertPathBuilder.getInstance(CertPathBuilder.getDefaultType(), BouncyCastleProvider.PROVIDER_NAME);
+        return (PKIXCertPathBuilderResult) builder.build(pkixParams);
+    }
+
+    private CertStore createCertStore(Set<X509Certificate> certificateSet) throws InvalidAlgorithmParameterException,
+            NoSuchAlgorithmException, NoSuchProviderException {
+        return CertStore.getInstance("Collection", new CollectionCertStoreParameters(certificateSet), BouncyCastleProvider.PROVIDER_NAME);
+    }
+
+    private boolean isExpired(X509Certificate cert) {
+        try {
+            cert.checkValidity();
+        } catch (CertificateExpiredException e) {
+            logger.error(e.getMessage(), e);
+            return true;
+        } catch (CertificateNotYetValidException e) {
+            logger.error(e.getMessage(), e);
+            return false;
+        }
+        return false;
+    }
+
+    private boolean isSelfSigned(Certificate cert)
+            throws CertificateException, NoSuchAlgorithmException,
+            NoSuchProviderException {
+        try {
+            // Try to verify certificate signature with its own public key
+            PublicKey key = cert.getPublicKey();
+            cert.verify(key);
+            return true;
+        } catch (SignatureException | InvalidKeyException e) {
+            logger.error(e.getMessage(), e);
+            //not self-signed
+            return false;
         }
-        return ImmutableSet.copyOf(certificates);
     }
 }
index 5c5a23a..cdba2f8 100644 (file)
@@ -1,8 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2019, Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
 package org.openecomp.sdc.vendorsoftwareproduct.security;
 
-public class SecurityManagerException extends RuntimeException {
+public class SecurityManagerException extends Exception {
 
-    public SecurityManagerException(String s, Throwable t) {
+    public SecurityManagerException(String s) {
         super(s);
     }
+
+    public SecurityManagerException(String s, Throwable t) {
+        super(s, t);
+    }
 }
index c693015..eea8a3a 100644 (file)
@@ -6,11 +6,15 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
@@ -18,67 +22,129 @@ import static org.mockito.ArgumentMatchers.eq;
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest(SecurityManager.class)
+@PowerMockIgnore("javax.security.auth.x500.X500Principal")
 public class SecurityManagerTest {
-    File certDir;
+    private File certDir;
+    private SecurityManager securityManager;
 
     @Before
-    public void setUp(){
+    public void setUp() throws IOException {
         certDir = new File("/tmp/cert");
+        if(certDir.exists()){
+            tearDown();
+        }
         certDir.mkdirs();
         PowerMockito.mockStatic(System.class);
         PowerMockito.when(System.getenv(eq("SDC_CERT_DIR"))).thenReturn(certDir.getPath());
+        securityManager = SecurityManager.getInstance();
     }
 
     @After
-    public void tearDown(){
-        certDir.delete();
+    public void tearDown() throws IOException {
+        if(certDir.exists()) {
+            FileUtils.deleteDirectory(certDir);
+        }
+        securityManager.cleanTrustedCertificates();
     }
 
     @Test
-    public void testGetCertificates() throws IOException {
+    public void testGetCertificates() throws IOException, SecurityManagerException {
         File origFile = new File("src/test/resources/cert/root-certificate.pem");
         File newFile = new File("/tmp/cert/root-certificate.pem");
         newFile.createNewFile();
         FileUtils.copyFile(origFile, newFile);
-        SecurityManager securityManager = new SecurityManager();
-        assertEquals(1, securityManager.getCertificates().size());
+        assertEquals(1, securityManager.getTrustedCertificates().size());
         newFile.delete();
-        assertEquals(0, securityManager.getCertificates().size());
+        assertEquals(0, securityManager.getTrustedCertificates().size());
     }
 
     @Test
-    public void testGetCertificatesNoDirectory() throws IOException {
+    public void testGetCertificatesNoDirectory() throws IOException, SecurityManagerException {
         certDir.delete();
-        SecurityManager securityManager = new SecurityManager();
-        assertEquals(0, securityManager.getCertificates().size());
+        assertEquals(0, securityManager.getTrustedCertificates().size());
     }
 
     @Test(expected = SecurityManagerException.class)
-    public void testGetCertificatesException() throws IOException {
+    public void testGetCertificatesException() throws IOException, SecurityManagerException {
         File newFile = new File("/tmp/cert/root-certificate.pem");
         newFile.createNewFile();
-        SecurityManager securityManager = new SecurityManager();
-        assertEquals(1, securityManager.getCertificates().size());
+        assertEquals(1, securityManager.getTrustedCertificates().size());
         newFile.delete();
-        assertEquals(0, securityManager.getCertificates().size());
+        assertEquals(0, securityManager.getTrustedCertificates().size());
     }
 
     @Test
-    public void testGetCertificatesUpdated() throws IOException {
+    public void testGetCertificatesUpdated() throws IOException, SecurityManagerException {
         File origFile = new File("src/test/resources/cert/root-certificate.pem");
         File newFile = new File("/tmp/cert/root-certificate.pem");
         newFile.createNewFile();
         FileUtils.copyFile(origFile, newFile);
-        SecurityManager securityManager = new SecurityManager();
-        assertTrue(securityManager.getCertificates().size() == 1);
+        assertTrue(securityManager.getTrustedCertificates().size() == 1);
         File otherOrigFile = new File("src/test/resources/cert/package-certificate.pem");
         File otherNewFile = new File("/tmp/cert/package-certificate.pem");
         newFile.createNewFile();
         FileUtils.copyFile(otherOrigFile, otherNewFile);
-        assertEquals(2, securityManager.getCertificates().size());
+        assertEquals(2, securityManager.getTrustedCertificates().size());
         otherNewFile.delete();
-        assertEquals(1, securityManager.getCertificates().size());
+        assertEquals(1, securityManager.getTrustedCertificates().size());
         newFile.delete();
-        assertEquals(0, securityManager.getCertificates().size());
+        assertEquals(0, securityManager.getTrustedCertificates().size());
+    }
+
+    @Test
+    public void verifySignedDataTestCertIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
+        File origFile = new File("src/test/resources/cert/root.cert");
+        File newFile = new File("/tmp/cert/root.cert");
+        newFile.createNewFile();
+        FileUtils.copyFile(origFile, newFile);
+        byte[] signature = Files.readAllBytes(Paths.get(getClass().getResource("/cert/2-file-signed-package/dummyPnfv3.cms").toURI()));
+        byte[] archive = Files.readAllBytes(Paths.get(getClass().getResource("/cert/2-file-signed-package/dummyPnfv3.csar").toURI()));
+        assertTrue(securityManager.verifySignedData(signature, null, archive));
+    }
+
+    @Test(expected = SecurityManagerException.class)
+    public void verifySignedDataTestCertNotIncludedIntoSignatureButExpected() throws IOException, URISyntaxException, SecurityManagerException {
+        File origFile = new File("src/test/resources/cert/root.cert");
+        File newFile = new File("/tmp/cert/root.cert");
+        newFile.createNewFile();
+        FileUtils.copyFile(origFile, newFile);
+        byte[] signature = Files.readAllBytes(Paths.get(getClass().getResource("/cert/3-file-signed-package/dummyPnfv3.cms").toURI()));
+        byte[] archive = Files.readAllBytes(Paths.get(getClass().getResource("/cert/2-file-signed-package/dummyPnfv3.csar").toURI()));
+        securityManager.verifySignedData(signature, null, archive);
+    }
+
+    @Test
+    public void verifySignedDataTestCertNotIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
+        File origFile = new File("src/test/resources/cert/root.cert");
+        File newFile = new File("/tmp/cert/root.cert");
+        newFile.createNewFile();
+        FileUtils.copyFile(origFile, newFile);
+        byte[] signature = Files.readAllBytes(Paths.get(getClass().getResource("/cert/3-file-signed-package/dummyPnfv3.cms").toURI()));
+        byte[] archive = Files.readAllBytes(Paths.get(getClass().getResource("/cert/3-file-signed-package/dummyPnfv3.csar").toURI()));
+        byte[] cert = Files.readAllBytes(Paths.get(getClass().getResource("/cert/3-file-signed-package/dummyPnfv3.cert").toURI()));
+        assertTrue(securityManager.verifySignedData(signature, cert, archive));
+    }
+
+    @Test(expected = SecurityManagerException.class)
+    public void verifySignedDataTestWrongCertificate() throws IOException, URISyntaxException, SecurityManagerException {
+        File origFile = new File("src/test/resources/cert/root-certificate.pem");
+        File newFile = new File("/tmp/cert/root-certificate.cert");
+        newFile.createNewFile();
+        FileUtils.copyFile(origFile, newFile);
+        byte[] signature = Files.readAllBytes(Paths.get(getClass().getResource("/cert/3-file-signed-package/dummyPnfv3.cms").toURI()));
+        byte[] archive = Files.readAllBytes(Paths.get(getClass().getResource("/cert/3-file-signed-package/dummyPnfv3.csar").toURI()));
+        byte[] cert = Files.readAllBytes(Paths.get(getClass().getResource("/cert/3-file-signed-package/dummyPnfv3.cert").toURI()));
+        securityManager.verifySignedData(signature, cert, archive);
+    }
+
+    @Test(expected = SecurityManagerException.class)
+    public void verifySignedDataTestChangedArchive() throws IOException, URISyntaxException, SecurityManagerException {
+        File origFile = new File("src/test/resources/cert/root.cert");
+        File newFile = new File("/tmp/cert/root.cert");
+        newFile.createNewFile();
+        FileUtils.copyFile(origFile, newFile);
+        byte[] signature = Files.readAllBytes(Paths.get(getClass().getResource("/cert/tampered-signed-package/dummyPnfv3.cms").toURI()));
+        byte[] archive = Files.readAllBytes(Paths.get(getClass().getResource("/cert/tampered-signed-package/dummyPnfv3.csar").toURI()));
+        securityManager.verifySignedData(signature, null, archive);
     }
 }
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/dummyPnfv3.cms b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/dummyPnfv3.cms
new file mode 100644 (file)
index 0000000..fca5fac
--- /dev/null
@@ -0,0 +1,34 @@
+-----BEGIN CMS-----
+MIIF9AYJKoZIhvcNAQcCoIIF5TCCBeECAQExDTALBglghkgBZQMEAgEwCwYJKoZI
+hvcNAQcBoIIDPjCCAzowggIiAgkAmTZc6pj8rWYwDQYJKoZIhvcNAQELBQAwXzEL
+MAkGA1UEBhMCSUUxEjAQBgNVBAgMCVdlc3RtZWF0aDEQMA4GA1UEBwwHQXRobG9u
+ZTEMMAoGA1UECgwDRVNZMQ8wDQYDVQQLDAZUZWNobm8xCzAJBgNVBAMMAlNTMB4X
+DTE5MDMyODEzMDQ0NloXDTE5MDQyNzEzMDQ0NlowXzELMAkGA1UEBhMCSUUxEjAQ
+BgNVBAgMCVdlc3RtZWF0aDEQMA4GA1UEBwwHQXRobG9uZTEMMAoGA1UECgwDRVNZ
+MQ8wDQYDVQQLDAZUZWNobm8xCzAJBgNVBAMMAlNTMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAqzpc/mRJZe5fxh9yo2ZmFCrNCynrbtLujp2GJwW40Nh0
+89jUBb49zFRwHrUUTlmIZRMrW8XDopX1LDajE+pzNxv+skdpZaPHhEjYcqbFIL1I
+KiWxo1PTBi/9KgSFlzc5eewolrwV+NX76p2+xkLDwt6rnZy8UiubVH7U4mUnPtxy
+Wx/W7uVGaZDKo0g2PNcFayRcL5skbm0Una2TjjAunwGP3FkxKigw+LukLE+w2fvE
+C7b8ndIk10WER9rCIeMCf1571Ub8WJzR/80PfhJxbxoroRaiGESFh3kNNfqanLcS
+Q4I9KHWeijOhSW0pHkqL2KPAee35FtfEUpL5aN0OcwIDAQABMA0GCSqGSIb3DQEB
+CwUAA4IBAQBlm8RMspc6cwcktqJXDLZLZiHSoapQqcq3TI3dkhU2uEFTstnxnXa3
+r4eTVF8tre2BjvxJtgmM7qMnoDTFo+uUjkvuBBalLARbQM+gF6PAeRLYRHMLSkN/
+yOfnyQ3ypYAQMpEHVG0Er6B5+KbQwFr2G0XBW0zE8au9oGzqBUNg7e0O22AyXqQk
+uhHzXXVhz6sWxJVv51gjPoWtr/1YbsGmJPimFIuz9GvrZD1MKGQ4sotZvRkfofHz
+ePg0y8taAcdXHJwfmAeiJdc0S9SsYxKLAz1OB+n4oQTsk+31cnKflp+wVfeNyaRP
+sdFf4KLicluzbwIRJ/x0h2r/lTorGGUcMYICfDCCAngCAQEwbDBfMQswCQYDVQQG
+EwJJRTESMBAGA1UECAwJV2VzdG1lYXRoMRAwDgYDVQQHDAdBdGhsb25lMQwwCgYD
+VQQKDANFU1kxDzANBgNVBAsMBlRlY2hubzELMAkGA1UEAwwCU1MCCQCZNlzqmPyt
+ZjALBglghkgBZQMEAgGggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkq
+hkiG9w0BCQUxDxcNMTkwMzI4MTMwODUwWjAvBgkqhkiG9w0BCQQxIgQg9ya6QcX9
+J6hp+zfK1gceoLlpApp92mfxGoX3eZ1dMUwweQYJKoZIhvcNAQkPMWwwajALBglg
+hkgBZQMEASowCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAO
+BggqhkiG9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcN
+AwICASgwDQYJKoZIhvcNAQEBBQAEggEAAmmSdu8W5zr8DVrkASlujCCSLwKq1XE+
+knlrR84UkkpRz8SacfxtoQL2/T6H0LyOnlJTOGQj3M8w2CaYKKWamnp/2jLZFvUn
+aaPbCdKeKvwPiL99iBIqXWcHXJKk5Ch3fIfcWyAfl48HAB7MFE3TlKk0qUQVXlZP
+7/c4PGaqtbfB7pDuJx6k+Bd2dqG4Xe8RDdvKDEK33HzkAZ72ZPuEL3Zw77eeWZS6
+vyAQTxEkFKERiC1AkmGUdAfTolzYGn1LlTcqb1P59nzs/AZ16JKx6ZITumhaSG6Q
+JvkvodxD99bhOh3pHaLkTkkcLxEEE9OscYEtWvIdIGyfjrpGIFP31g==
+-----END CMS-----
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/dummyPnfv3.csar b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/dummyPnfv3.csar
new file mode 100644 (file)
index 0000000..2c626ed
Binary files /dev/null and b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/dummyPnfv3.csar differ
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.cert b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.cert
new file mode 100644 (file)
index 0000000..d7da41d
--- /dev/null
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDOjCCAiICCQCZNlzqmPytZjANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJJ
+RTESMBAGA1UECAwJV2VzdG1lYXRoMRAwDgYDVQQHDAdBdGhsb25lMQwwCgYDVQQK
+DANFU1kxDzANBgNVBAsMBlRlY2hubzELMAkGA1UEAwwCU1MwHhcNMTkwMzI4MTMw
+NDQ2WhcNMTkwNDI3MTMwNDQ2WjBfMQswCQYDVQQGEwJJRTESMBAGA1UECAwJV2Vz
+dG1lYXRoMRAwDgYDVQQHDAdBdGhsb25lMQwwCgYDVQQKDANFU1kxDzANBgNVBAsM
+BlRlY2hubzELMAkGA1UEAwwCU1MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCrOlz+ZEll7l/GH3KjZmYUKs0LKetu0u6OnYYnBbjQ2HTz2NQFvj3MVHAe
+tRROWYhlEytbxcOilfUsNqMT6nM3G/6yR2llo8eESNhypsUgvUgqJbGjU9MGL/0q
+BIWXNzl57CiWvBX41fvqnb7GQsPC3qudnLxSK5tUftTiZSc+3HJbH9bu5UZpkMqj
+SDY81wVrJFwvmyRubRSdrZOOMC6fAY/cWTEqKDD4u6QsT7DZ+8QLtvyd0iTXRYRH
+2sIh4wJ/XnvVRvxYnNH/zQ9+EnFvGiuhFqIYRIWHeQ01+pqctxJDgj0odZ6KM6FJ
+bSkeSovYo8B57fkW18RSkvlo3Q5zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGWb
+xEyylzpzByS2olcMtktmIdKhqlCpyrdMjd2SFTa4QVOy2fGddrevh5NUXy2t7YGO
+/Em2CYzuoyegNMWj65SOS+4EFqUsBFtAz6AXo8B5EthEcwtKQ3/I5+fJDfKlgBAy
+kQdUbQSvoHn4ptDAWvYbRcFbTMTxq72gbOoFQ2Dt7Q7bYDJepCS6EfNddWHPqxbE
+lW/nWCM+ha2v/VhuwaYk+KYUi7P0a+tkPUwoZDiyi1m9GR+h8fN4+DTLy1oBx1cc
+nB+YB6Il1zRL1KxjEosDPU4H6fihBOyT7fVycp+Wn7BV943JpE+x0V/gouJyW7Nv
+AhEn/HSHav+VOisYZRw=
+-----END CERTIFICATE-----
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.cms b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.cms
new file mode 100644 (file)
index 0000000..eeee6a9
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN CMS-----
+MIICsgYJKoZIhvcNAQcCoIICozCCAp8CAQExDTALBglghkgBZQMEAgEwCwYJKoZI
+hvcNAQcBMYICfDCCAngCAQEwbDBfMQswCQYDVQQGEwJJRTESMBAGA1UECAwJV2Vz
+dG1lYXRoMRAwDgYDVQQHDAdBdGhsb25lMQwwCgYDVQQKDANFU1kxDzANBgNVBAsM
+BlRlY2hubzELMAkGA1UEAwwCU1MCCQCZNlzqmPytZjALBglghkgBZQMEAgGggeQw
+GAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkwMzI4
+MTMxMDI2WjAvBgkqhkiG9w0BCQQxIgQg9ya6QcX9J6hp+zfK1gceoLlpApp92mfx
+GoX3eZ1dMUwweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJYIZIAWUD
+BAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAwDQYI
+KoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZIhvcNAQEB
+BQAEggEAGGYZ4DsMUDzjMVpJU9zwLzTtxO1wCnouTVw8FJT2utGnUds+OexbKQoj
+pCCfuAL1k9UaP3uyNXOjuMx8tzlQY0gZJzaKpYJ7vh0q6P9IZs0hjcvEXPhRTI/y
+vI8mHP3WIXwuh36ehRmqALnGbBcOj46k578gAf/p1hHD3/ceQfB1MSkSVMwvf+yP
+3YwJyvKHYYlGaaAbSjnIK+7g2tuRIvFdXGk30CU2mnldvb3JltfxB5MkZgEM6hPz
+ZhjgNDtmFDZzoblEOCvFJnpXg2IF7bAPjObNaPd20ZRvRSRhQODktT5EHARRT53Y
+p+03N4IUz89hw/roOnq0nlbetQSKvg==
+-----END CMS-----
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.csar b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.csar
new file mode 100644 (file)
index 0000000..2c626ed
Binary files /dev/null and b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/dummyPnfv3.csar differ
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/root.cert b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/root.cert
new file mode 100644 (file)
index 0000000..767804e
--- /dev/null
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIJANxs5zQCT2zPMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
+BAYTAklFMRIwEAYDVQQIDAlXZXN0bWVhdGgxEDAOBgNVBAcMB0F0aGxvbmUxDDAK
+BgNVBAoMA0VTWTEPMA0GA1UECwwGVGVjaG5vMQswCQYDVQQDDAJTUzAeFw0xOTAz
+MjgxMzAyMDVaFw0xOTA0MjcxMzAyMDVaMF8xCzAJBgNVBAYTAklFMRIwEAYDVQQI
+DAlXZXN0bWVhdGgxEDAOBgNVBAcMB0F0aGxvbmUxDDAKBgNVBAoMA0VTWTEPMA0G
+A1UECwwGVGVjaG5vMQswCQYDVQQDDAJTUzCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALwd8mRaVTPIiyJEGuscMulTg7EyQGUcVgRUJDrcEsubK9vgDEqh
+0BTps1xO01LX7RaXSe4KWTcsJG41QsdX9lo94VoYZFfR0tVKCkPjWoaynl0cZEAZ
+r6vADWwQkWWi1Czwr9fTX9NBu68IexLATuS387gafonlzvpa4TLVwi69ogNlVa91
+pKkeZCBWbhgDgYDz5pEbKPJ6TRab/sFxZOx/HBIM9i7INvwNhdnZF77eZVgNUX2z
+XKFcXOklmY9gEr9HQtsFIyTxlOdL2DF7JspgN0Yfb6hqAKE/sfOgQ6h3A+n4AuA1
+gtgC6k0OVps2ZM3jlmpYatKorz22zp3nhzECAwEAAaNTMFEwHQYDVR0OBBYEFGci
+Qjw5QhCSvwl86i6weBl++bQvMB8GA1UdIwQYMBaAFGciQjw5QhCSvwl86i6weBl+
++bQvMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHtMPlNaUJPy
+IXBOjROu0LlRXWJ/u7TVLaLaLnok5Sy/9QAz/FBKzOvMP1cmavsZiZC/9ISEaWFv
+KlTOeZrhUl7WGk8pJPkkfATxt7HtRxO/c0RNrJin1AWWjQnUxjCB+nuqKS2h/itG
+fHyHzzB3kjzxaK73kVuh8fzdxRDkg6QgLyW83BJ8T/U/VOuM3HRNIF86cazgae7E
+7c9SrnXZ67IS7w3gxm/L/k5Rpd4XuuumaDuDz3NhGj1HFh323x11jheMmfl559SK
+qU5NIC2qwKYGhzDojgLUJeL9g52DeS4eZ3DmINFRK2g0UMrHrypKq5aQ2v1kac6X
+Io5o3F3L2DE=
+-----END CERTIFICATE-----
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/tampered-signed-package/dummyPnfv3.cms b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/tampered-signed-package/dummyPnfv3.cms
new file mode 100644 (file)
index 0000000..fca5fac
--- /dev/null
@@ -0,0 +1,34 @@
+-----BEGIN CMS-----
+MIIF9AYJKoZIhvcNAQcCoIIF5TCCBeECAQExDTALBglghkgBZQMEAgEwCwYJKoZI
+hvcNAQcBoIIDPjCCAzowggIiAgkAmTZc6pj8rWYwDQYJKoZIhvcNAQELBQAwXzEL
+MAkGA1UEBhMCSUUxEjAQBgNVBAgMCVdlc3RtZWF0aDEQMA4GA1UEBwwHQXRobG9u
+ZTEMMAoGA1UECgwDRVNZMQ8wDQYDVQQLDAZUZWNobm8xCzAJBgNVBAMMAlNTMB4X
+DTE5MDMyODEzMDQ0NloXDTE5MDQyNzEzMDQ0NlowXzELMAkGA1UEBhMCSUUxEjAQ
+BgNVBAgMCVdlc3RtZWF0aDEQMA4GA1UEBwwHQXRobG9uZTEMMAoGA1UECgwDRVNZ
+MQ8wDQYDVQQLDAZUZWNobm8xCzAJBgNVBAMMAlNTMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAqzpc/mRJZe5fxh9yo2ZmFCrNCynrbtLujp2GJwW40Nh0
+89jUBb49zFRwHrUUTlmIZRMrW8XDopX1LDajE+pzNxv+skdpZaPHhEjYcqbFIL1I
+KiWxo1PTBi/9KgSFlzc5eewolrwV+NX76p2+xkLDwt6rnZy8UiubVH7U4mUnPtxy
+Wx/W7uVGaZDKo0g2PNcFayRcL5skbm0Una2TjjAunwGP3FkxKigw+LukLE+w2fvE
+C7b8ndIk10WER9rCIeMCf1571Ub8WJzR/80PfhJxbxoroRaiGESFh3kNNfqanLcS
+Q4I9KHWeijOhSW0pHkqL2KPAee35FtfEUpL5aN0OcwIDAQABMA0GCSqGSIb3DQEB
+CwUAA4IBAQBlm8RMspc6cwcktqJXDLZLZiHSoapQqcq3TI3dkhU2uEFTstnxnXa3
+r4eTVF8tre2BjvxJtgmM7qMnoDTFo+uUjkvuBBalLARbQM+gF6PAeRLYRHMLSkN/
+yOfnyQ3ypYAQMpEHVG0Er6B5+KbQwFr2G0XBW0zE8au9oGzqBUNg7e0O22AyXqQk
+uhHzXXVhz6sWxJVv51gjPoWtr/1YbsGmJPimFIuz9GvrZD1MKGQ4sotZvRkfofHz
+ePg0y8taAcdXHJwfmAeiJdc0S9SsYxKLAz1OB+n4oQTsk+31cnKflp+wVfeNyaRP
+sdFf4KLicluzbwIRJ/x0h2r/lTorGGUcMYICfDCCAngCAQEwbDBfMQswCQYDVQQG
+EwJJRTESMBAGA1UECAwJV2VzdG1lYXRoMRAwDgYDVQQHDAdBdGhsb25lMQwwCgYD
+VQQKDANFU1kxDzANBgNVBAsMBlRlY2hubzELMAkGA1UEAwwCU1MCCQCZNlzqmPyt
+ZjALBglghkgBZQMEAgGggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkq
+hkiG9w0BCQUxDxcNMTkwMzI4MTMwODUwWjAvBgkqhkiG9w0BCQQxIgQg9ya6QcX9
+J6hp+zfK1gceoLlpApp92mfxGoX3eZ1dMUwweQYJKoZIhvcNAQkPMWwwajALBglg
+hkgBZQMEASowCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAO
+BggqhkiG9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcN
+AwICASgwDQYJKoZIhvcNAQEBBQAEggEAAmmSdu8W5zr8DVrkASlujCCSLwKq1XE+
+knlrR84UkkpRz8SacfxtoQL2/T6H0LyOnlJTOGQj3M8w2CaYKKWamnp/2jLZFvUn
+aaPbCdKeKvwPiL99iBIqXWcHXJKk5Ch3fIfcWyAfl48HAB7MFE3TlKk0qUQVXlZP
+7/c4PGaqtbfB7pDuJx6k+Bd2dqG4Xe8RDdvKDEK33HzkAZ72ZPuEL3Zw77eeWZS6
+vyAQTxEkFKERiC1AkmGUdAfTolzYGn1LlTcqb1P59nzs/AZ16JKx6ZITumhaSG6Q
+JvkvodxD99bhOh3pHaLkTkkcLxEEE9OscYEtWvIdIGyfjrpGIFP31g==
+-----END CMS-----
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/tampered-signed-package/dummyPnfv3.csar b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/tampered-signed-package/dummyPnfv3.csar
new file mode 100644 (file)
index 0000000..81cb1f7
Binary files /dev/null and b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/tampered-signed-package/dummyPnfv3.csar differ
index 2111f6d..7b8fda8 100644 (file)
@@ -188,7 +188,8 @@ public enum Messages {
 
   /* Notifications */
   FAILED_TO_MARK_NOTIFICATION_AS_READ("Failed to mark notifications as read"),
-  FAILED_TO_UPDATE_LAST_SEEN_NOTIFICATION("Failed to update last seen notification for user %s");
+  FAILED_TO_UPDATE_LAST_SEEN_NOTIFICATION("Failed to update last seen notification for user %s"),
+  FAILED_TO_VERIFY_SIGNATURE("Cannot verify signature of signed archive!");
 
   private String errorMessage;