aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main
diff options
context:
space:
mode:
authorandre.schmid <andre.schmid@est.tech>2021-01-28 17:53:22 +0000
committerVasyl Razinkov <vasyl.razinkov@est.tech>2021-02-21 13:07:13 +0000
commit13b39127c1c91d7c05c67ea2c14220c8f992cba5 (patch)
tree755c7ad631c0673c73e28f415cca9682889e729b /catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main
parent8cc03e2c78639be5500ab50f3ebaaf7d64404775 (diff)
ETSI SOL007 3.3.1 package security option 2
Change-Id: I4e021c517449e6ddf11571c02d0b4bdbc93e7c1e Issue-ID: SDC-2614 Signed-off-by: andre.schmid <andre.schmid@est.tech>
Diffstat (limited to 'catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main')
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java19
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/factory/EtsiNfvNsdCsarGeneratorFactory.java10
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java19
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java4
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java132
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/NsdCsar.java110
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/NsdCsarEtsiOption2Signer.java151
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureException.java31
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureExceptionSupplier.java39
9 files changed, 475 insertions, 40 deletions
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java
index 38f03f12f5..73be4a2100 100644
--- a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java
@@ -1,4 +1,3 @@
-
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
@@ -25,6 +24,7 @@ import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
+import org.apache.commons.lang.StringUtils;
/**
* Builder for the manifest (.mf) file in a NSD CSAR
@@ -45,6 +45,7 @@ public class NsdCsarManifestBuilder {
private final MetadataHeader metadataHeader;
private final Set<String> sources;
private final Set<String> compatibleSpecificationVersions;
+ private String signature;
public NsdCsarManifestBuilder() {
metadataHeader = new MetadataHeader();
@@ -122,6 +123,13 @@ public class NsdCsarManifestBuilder {
return this;
}
+ public NsdCsarManifestBuilder withSignature(final String signature) {
+ if (signature != null) {
+ this.signature = signature.trim();
+ }
+ return this;
+ }
+
/**
* Builds a string representing the manifest content based on provided values.
*
@@ -142,7 +150,14 @@ public class NsdCsarManifestBuilder {
.append(String.join(",", compatibleSpecificationVersions)).append(NEW_LINE);
}
final StringBuilder builder = new StringBuilder();
- builder.append(metadataBuilder).append(compatibleSpecificationVersionsBuilder).append(NEW_LINE).append(sourceBuilder);
+
+ builder.append(metadataBuilder)
+ .append(compatibleSpecificationVersionsBuilder)
+ .append(NEW_LINE)
+ .append(sourceBuilder);
+ if (StringUtils.isNotBlank(signature)) {
+ builder.append(signature);
+ }
return builder.toString();
}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/factory/EtsiNfvNsdCsarGeneratorFactory.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/factory/EtsiNfvNsdCsarGeneratorFactory.java
index fb08f56ac2..c51dc51854 100644
--- a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/factory/EtsiNfvNsdCsarGeneratorFactory.java
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/factory/EtsiNfvNsdCsarGeneratorFactory.java
@@ -1,4 +1,3 @@
-
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Nordix Foundation
@@ -25,6 +24,7 @@ import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.EtsiNfvNsdCsarGenerat
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.VnfDescriptorGenerator;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.config.EtsiVersion;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.config.NsDescriptorConfig;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.security.NsdCsarEtsiOption2Signer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Component;
@@ -35,20 +35,24 @@ public class EtsiNfvNsdCsarGeneratorFactory {
private final NsDescriptorGeneratorFactory nsDescriptorGeneratorFactory;
private final ArtifactCassandraDao artifactCassandraDao;
private final ObjectProvider<EtsiNfvNsdCsarGeneratorImpl> etsiNfvNsdCsarGeneratorObjectProvider;
+ private final NsdCsarEtsiOption2Signer nsdCsarEtsiOption2Signer;
public EtsiNfvNsdCsarGeneratorFactory(final VnfDescriptorGenerator vnfDescriptorGenerator,
final NsDescriptorGeneratorFactory nsDescriptorGeneratorFactory,
final ArtifactCassandraDao artifactCassandraDao,
- final ObjectProvider<EtsiNfvNsdCsarGeneratorImpl> etsiNfvNsdCsarGeneratorObjectProvider) {
+ final ObjectProvider<EtsiNfvNsdCsarGeneratorImpl> etsiNfvNsdCsarGeneratorObjectProvider,
+ final NsdCsarEtsiOption2Signer nsdCsarEtsiOption2Signer) {
this.vnfDescriptorGenerator = vnfDescriptorGenerator;
this.nsDescriptorGeneratorFactory = nsDescriptorGeneratorFactory;
this.artifactCassandraDao = artifactCassandraDao;
this.etsiNfvNsdCsarGeneratorObjectProvider = etsiNfvNsdCsarGeneratorObjectProvider;
+ this.nsdCsarEtsiOption2Signer = nsdCsarEtsiOption2Signer;
}
public EtsiNfvNsdCsarGenerator create(final EtsiVersion version) {
final NsDescriptorConfig nsDescriptorConfig = new NsDescriptorConfig(version);
return etsiNfvNsdCsarGeneratorObjectProvider
- .getObject(nsDescriptorConfig, vnfDescriptorGenerator, nsDescriptorGeneratorFactory, artifactCassandraDao);
+ .getObject(nsDescriptorConfig, vnfDescriptorGenerator, nsDescriptorGeneratorFactory, artifactCassandraDao
+ , nsdCsarEtsiOption2Signer);
}
}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java
index 90359a550d..9a7312b0fb 100644
--- a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java
@@ -1,4 +1,3 @@
-
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
@@ -30,6 +29,7 @@ import org.openecomp.sdc.be.plugins.CsarEntryGenerator;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.NsdException;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.factory.EtsiNfvNsdCsarGeneratorFactory;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.config.EtsiVersion;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.NsdCsar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,7 +40,9 @@ import org.slf4j.LoggerFactory;
public class EtsiNfvNsCsarEntryGenerator implements CsarEntryGenerator {
static final String ETSI_NS_COMPONENT_CATEGORY = "ETSI NFV Network Service";
- static final String NSD_FILE_PATH_FORMAT = "Artifacts/%s/%s.csar";
+ static final String NSD_FILE_PATH_FORMAT = "Artifacts/%s/%s.%s";
+ static final String SIGNED_CSAR_EXTENSION = "zip";
+ static final String UNSIGNED_CSAR_EXTENSION = "csar";
static final String ETSI_VERSION_METADATA = "ETSI Version";
private static final Logger LOGGER = LoggerFactory.getLogger(EtsiNfvNsCsarEntryGenerator.class);
private final EtsiNfvNsdCsarGeneratorFactory etsiNfvNsdCsarGeneratorFactory;
@@ -69,7 +71,8 @@ public class EtsiNfvNsCsarEntryGenerator implements CsarEntryGenerator {
ETSI_NS_COMPONENT_CATEGORY);
return Collections.emptyMap();
}
- final byte[] nsdCsar;
+
+ final NsdCsar nsdCsar;
try {
final EtsiVersion etsiVersion = getComponentEtsiVersion(component);
final EtsiNfvNsdCsarGenerator etsiNfvNsdCsarGenerator = etsiNfvNsdCsarGeneratorFactory.create(etsiVersion);
@@ -81,7 +84,8 @@ public class EtsiNfvNsCsarEntryGenerator implements CsarEntryGenerator {
LOGGER.error("Could not create NSD CSAR entry for component '{}'. An unexpected exception occurred", component.getName(), e);
return Collections.emptyMap();
}
- return createEntry(component.getNormalizedName(), nsdCsar);
+
+ return createEntry(nsdCsar);
}
private EtsiVersion getComponentEtsiVersion(Component component) {
@@ -89,10 +93,11 @@ public class EtsiNfvNsCsarEntryGenerator implements CsarEntryGenerator {
return EtsiVersion.convertOrNull(etsiVersion);
}
- private Map<String, byte[]> createEntry(final String csarName, final byte[] nsdCsar) {
+ private Map<String, byte[]> createEntry(final NsdCsar nsdCsar) {
final Map<String, byte[]> entryMap = new HashMap<>();
- final String entryKey = String.format(NSD_FILE_PATH_FORMAT, ETSI_PACKAGE, csarName);
- entryMap.put(entryKey, nsdCsar);
+ final String extension = nsdCsar.isSigned() ? SIGNED_CSAR_EXTENSION : UNSIGNED_CSAR_EXTENSION;
+ final String entryKey = String.format(NSD_FILE_PATH_FORMAT, ETSI_PACKAGE, nsdCsar.getFileName(), extension);
+ entryMap.put(entryKey, nsdCsar.getCsarPackage());
return entryMap;
}
}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java
index 072c4c5a89..1ad6e82481 100644
--- a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java
@@ -1,4 +1,3 @@
-
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
@@ -21,6 +20,7 @@ package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator;
import org.openecomp.sdc.be.model.Component;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.NsdException;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.NsdCsar;
/**
* Generator for a ETSI NFV NSD CSAR
@@ -33,5 +33,5 @@ public interface EtsiNfvNsdCsarGenerator {
* @param component the service component
* @return the CSAR package content
*/
- byte[] generateNsdCsar(Component component) throws NsdException;
+ NsdCsar generateNsdCsar(Component component) throws NsdException;
}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java
index e7d30197d7..f9e0970ba9 100644
--- a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java
@@ -1,4 +1,3 @@
-
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
@@ -23,10 +22,13 @@ import static org.openecomp.sdc.common.api.ArtifactTypeEnum.ETSI_PACKAGE;
import static org.openecomp.sdc.common.api.ArtifactTypeEnum.ONBOARDED_PACKAGE;
import fj.data.Either;
+import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -36,9 +38,11 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
+import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.StringUtils;
+import org.openecomp.sdc.be.csar.security.api.model.CertificateInfo;
import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao;
import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus;
import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
@@ -53,7 +57,9 @@ import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.config.EtsiVersion;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.config.NsDescriptorConfig;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator.config.NsDescriptorVersionComparator;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.Nsd;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.NsdCsar;
import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.VnfDescriptor;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.security.NsdCsarEtsiOption2Signer;
import org.openecomp.sdc.be.resources.data.DAOArtifactData;
import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
import org.slf4j.Logger;
@@ -74,6 +80,8 @@ public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
private static final String MANIFEST_EXT = "mf";
private static final String SLASH = "/";
private static final String DOT = ".";
+ private static final String SIGNATURE_EXTENSION = ".sig.cms";
+ private static final String CSAR_EXTENSION = ".csar";
private static final String DOT_YAML = DOT + "yaml";
private static final String DEFINITION = "Definitions";
private static final String TOSCA_META_PATH = "TOSCA-Metadata/TOSCA.meta";
@@ -81,18 +89,21 @@ public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
private final NsDescriptorGeneratorFactory nsDescriptorGeneratorFactory;
private final ArtifactCassandraDao artifactCassandraDao;
private final NsDescriptorConfig nsDescriptorConfig;
+ private final NsdCsarEtsiOption2Signer nsdCsarEtsiOption2Signer;
public EtsiNfvNsdCsarGeneratorImpl(final NsDescriptorConfig nsDescriptorConfig, final VnfDescriptorGenerator vnfDescriptorGenerator,
final NsDescriptorGeneratorFactory nsDescriptorGeneratorFactory,
- final ArtifactCassandraDao artifactCassandraDao) {
+ final ArtifactCassandraDao artifactCassandraDao,
+ final NsdCsarEtsiOption2Signer nsdCsarEtsiOption2Signer) {
this.nsDescriptorConfig = nsDescriptorConfig;
this.vnfDescriptorGenerator = vnfDescriptorGenerator;
this.nsDescriptorGeneratorFactory = nsDescriptorGeneratorFactory;
this.artifactCassandraDao = artifactCassandraDao;
+ this.nsdCsarEtsiOption2Signer = nsdCsarEtsiOption2Signer;
}
@Override
- public byte[] generateNsdCsar(final Component component) throws NsdException {
+ public NsdCsar generateNsdCsar(final Component component) throws NsdException {
if (component == null) {
throw new NsdException("Could not generate the NSD CSAR, invalid component argument");
}
@@ -101,23 +112,43 @@ public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
final String componentName = component.getName();
try {
LOGGER.debug("Starting NSD CSAR generation for component '{}'", componentName);
- final Map<String, byte[]> nsdCsarFiles = new HashMap<>();
- final List<VnfDescriptor> vnfDescriptorList = generateVnfPackages(component);
- vnfDescriptorList.forEach(vnfPackage -> nsdCsarFiles.putAll(vnfPackage.getDefinitionFiles()));
final String nsdFileName = getNsdFileName(component);
+ final NsdCsar nsdCsar = new NsdCsar(nsdFileName);
+
+ final List<VnfDescriptor> vnfDescriptorList = generateVnfPackages(component);
+ vnfDescriptorList.forEach(vnfPackage -> nsdCsar.addAllFiles(vnfPackage.getDefinitionFiles()));
+
final EtsiVersion etsiVersion = nsDescriptorConfig.getNsVersion();
final Nsd nsd = generateNsd(component, vnfDescriptorList);
- nsdCsarFiles.put(getNsdPath(nsdFileName), nsd.getContents());
- nsdCsarFiles.put(TOSCA_META_PATH, buildToscaMetaContent(nsdFileName).getBytes());
- addEtsiSolNsdTypes(etsiVersion, nsdCsarFiles);
+
+ nsdCsar.addFile(getNsdPath(nsdFileName), nsd.getContents());
+ nsdCsar.addFile(TOSCA_META_PATH, buildToscaMetaContent(nsdFileName).getBytes());
+
+ nsdCsar.addAllFiles(createEtsiSolNsdTypeEntries(etsiVersion));
for (final String referencedFile : nsd.getArtifactReferences()) {
getReferencedArtifact(component, referencedFile)
- .ifPresent(artifactDefinition -> nsdCsarFiles.put(referencedFile, artifactDefinition.getPayloadData()));
+ .ifPresent(artifactDefinition -> nsdCsar.addFile(referencedFile, artifactDefinition.getPayloadData())
+ );
+ }
+ final boolean isCertificateConfigured = nsdCsarEtsiOption2Signer.isCertificateConfigured();
+ final String manifestPath = getManifestPath(nsdFileName);
+ final NsdCsarManifestBuilder manifestBuilder =
+ createManifestBuilder(nsd, etsiVersion, manifestPath, nsdCsar.getFileMap().keySet(), isCertificateConfigured);
+
+ nsdCsar.addManifest(manifestBuilder);
+
+ if (isCertificateConfigured) {
+ nsdCsarEtsiOption2Signer.signArtifacts(nsdCsar);
+ }
+
+ byte[] package1 = buildCsarPackage(nsdCsar.getFileMap());
+ if (isCertificateConfigured) {
+ package1 = buildZipWithCsarAndSignature(nsdCsar.getFileName(), package1);
+ nsdCsar.setSigned(true);
}
- nsdCsarFiles.put(getManifestPath(nsdFileName), getManifestFileContent(nsd, etsiVersion, nsdCsarFiles.keySet()).getBytes());
- final byte[] csar = buildCsarPackage(nsdCsarFiles);
+ nsdCsar.setCsarPackage(package1);
LOGGER.debug("Successfully generated NSD CSAR package");
- return csar;
+ return nsdCsar;
} catch (final Exception exception) {
throw new NsdException("Could not generate the NSD CSAR file", exception);
}
@@ -205,29 +236,41 @@ public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
}).findFirst();
}
- private void addEtsiSolNsdTypes(final EtsiVersion etsiVersion, final Map<String, byte[]> nsdCsarFileMap) {
+ private Map<String, byte[]> createEtsiSolNsdTypeEntries(final EtsiVersion etsiVersion) {
final EtsiVersion currentVersion = etsiVersion == null ? EtsiVersion.getDefaultVersion() : etsiVersion;
+
final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
final Resource[] resources =
resolver.getResources(String.format("classpath:etsi-nfv-types/%s/*.*", currentVersion.getVersion()));
if (resources.length > 0) {
+ final Map<String, byte[]> entryMap = new HashMap<>();
for (final Resource resource : resources) {
- addToCsarFileMap(resource, nsdCsarFileMap);
+ readResource(resource).ifPresent(resourceBytes -> {
+ final String entryName = createDefinitionEntryName(resource.getFilename());
+ entryMap.put(entryName, resourceBytes);
+ });
}
+ return entryMap;
}
} catch (final IOException e) {
LOGGER.error("Could not find types files for the version '{}'", currentVersion.getVersion(), e);
}
+
+ return Collections.emptyMap();
+ }
+
+ private String createDefinitionEntryName(final String fileName) {
+ return DEFINITION + "/" + fileName;
}
- private void addToCsarFileMap(final Resource resource, final Map<String, byte[]> nsdCsarFileMap) {
+ private Optional<byte[]> readResource(final Resource resource) {
try {
- nsdCsarFileMap.put(DEFINITION + "/" + resource.getFilename(),
- IOUtils.toByteArray(resource.getInputStream()));
+ return Optional.ofNullable(IOUtils.toByteArray(resource.getInputStream()));
} catch (final IOException exception) {
LOGGER.error("Error adding '{}' to NSD CSAR", resource.getFilename(), exception);
}
+ return Optional.empty();
}
private Nsd generateNsd(final Component component,
@@ -294,18 +337,24 @@ public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
return toscaMetadata;
}
- private String getManifestFileContent(final Nsd nsd,
- final EtsiVersion nsdVersion,
- final Set<String> files) {
+ private NsdCsarManifestBuilder createManifestBuilder(final Nsd nsd, final EtsiVersion nsdVersion,
+ final String manifestFilePath, final Set<String> filePath,
+ final boolean addSignatureFiles) {
LOGGER.debug("Creating NS manifest file content");
+ final Set<String> filesToAdd = new HashSet<>(filePath);
+ if (addSignatureFiles) {
+ filePath.forEach(file -> filesToAdd.add(file + SIGNATURE_EXTENSION));
+ }
+ filesToAdd.add(manifestFilePath);
+
final NsdCsarManifestBuilder nsdCsarManifestBuilder = new NsdCsarManifestBuilder();
nsdCsarManifestBuilder.withDesigner(nsd.getDesigner())
.withInvariantId(nsd.getInvariantId())
.withName(nsd.getName())
.withNowReleaseDateTime()
.withFileStructureVersion(nsd.getVersion())
- .withSources(files);
+ .withSources(filesToAdd);
final NsDescriptorVersionComparator nsdVersionComparator = new NsDescriptorVersionComparator();
@@ -313,10 +362,10 @@ public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
nsdCsarManifestBuilder.withCompatibleSpecificationVersion(nsdVersion.getVersion());
}
- final String manifest = nsdCsarManifestBuilder.build();
- LOGGER.debug("Successfully created NS CSAR manifest file content:\n {}", manifest);
- return manifest;
-
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Successfully created NS CSAR manifest file content:\n {}", nsdCsarManifestBuilder.build());
+ }
+ return nsdCsarManifestBuilder;
}
private String getManifestPath(final String nsdFileName) {
@@ -358,6 +407,37 @@ public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
}
}
+ private byte[] buildZipWithCsarAndSignature(final String csarFileName, final byte[] csarPackageBytes) throws NsdException {
+ final byte[] signature;
+ try {
+ signature = nsdCsarEtsiOption2Signer.sign(csarPackageBytes);
+ } catch (final Exception e) {
+ throw new NsdException(String.format("Could not sign the CSAR '%s'", csarFileName), e);
+ }
+ final Optional<CertificateInfo> certificateInfoOpt = nsdCsarEtsiOption2Signer.getSigningCertificate();
+ if (certificateInfoOpt.isEmpty()) {
+ throw new NsdException(String.format("Could not sign the CSAR '%s'. No certificate configured.", csarFileName));
+ }
+ final CertificateInfo certificateInfo = certificateInfoOpt.get();
+ try (final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final ZipOutputStream zip = new ZipOutputStream(out)) {
+ zip.putNextEntry(new ZipEntry(csarFileName + CSAR_EXTENSION));
+ zip.write(csarPackageBytes);
+ zip.putNextEntry(new ZipEntry(csarFileName + SIGNATURE_EXTENSION));
+ zip.write(signature);
+ final File certificateFile = certificateInfo.getCertificateFile();
+ zip.putNextEntry(new ZipEntry(csarFileName + "." + FilenameUtils.getExtension(certificateFile.getName())));
+ zip.write(Files.readAllBytes(certificateFile.toPath()));
+ zip.flush();
+ zip.finish();
+ LOGGER.debug("NSD signed CSAR zip file was successfully built");
+
+ return out.toByteArray();
+ } catch (final IOException e) {
+ throw new NsdException("Could not build the NSD signed CSAR zip file", e);
+ }
+ }
+
}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/NsdCsar.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/NsdCsar.java
new file mode 100644
index 0000000000..733604529a
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/NsdCsar.java
@@ -0,0 +1,110 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.builder.NsdCsarManifestBuilder;
+
+/**
+ * Represents a NSD CSAR package
+ */
+public class NsdCsar {
+
+ private static final String MANIFEST_EXTENSION = "mf";
+ private static final String YAML_EXTENSION = "yaml";
+ private static final String DOT = ".";
+ private static final String SLASH = "/";
+ private static final String DEFINITIONS = "Definitions";
+
+ private final Map<String, byte[]> fileMap = new HashMap<>();
+ @Getter
+ private final String fileName;
+ @Getter
+ @Setter
+ private byte[] csarPackage;
+ @Getter
+ @Setter
+ private boolean isSigned;
+ @Getter
+ private NsdCsarManifestBuilder manifestBuilder;
+
+ public NsdCsar(final String fileName) {
+ this.fileName = fileName;
+ manifestBuilder = new NsdCsarManifestBuilder();
+ }
+
+ public void addFile(final String filePath, final byte[] fileBytes) {
+ fileMap.put(filePath, fileBytes);
+ }
+
+ public byte[] getFile(final String filePath) {
+ return fileMap.get(filePath);
+ }
+
+ public byte[] getManifest() {
+ return fileMap.get(getManifestPath());
+ }
+
+ public byte[] getMainDefinition() {
+ return fileMap.get(getMainDefinitionPath());
+ }
+
+ public Map<String, byte[]> getFileMap() {
+ return new HashMap<>(fileMap);
+ }
+
+ public String getManifestPath() {
+ return fileName + DOT + MANIFEST_EXTENSION;
+ }
+
+ public boolean isManifest(final String filePath) {
+ return getManifestPath().equals(filePath);
+ }
+
+ public String getMainDefinitionPath() {
+ return DEFINITIONS + SLASH + fileName + YAML_EXTENSION;
+ }
+
+ public void addAllFiles(final Map<String, byte[]> definitionFiles) {
+ fileMap.putAll(definitionFiles);
+ }
+
+ /**
+ * Sets a manifest builder and build it, adding its content to the to the CSAR files. Ignores {@code null} manifest builders.
+ *
+ * @param manifestBuilder the manifest builder
+ */
+ public void addManifest(final NsdCsarManifestBuilder manifestBuilder) {
+ if (manifestBuilder == null) {
+ return;
+ }
+ this.manifestBuilder = manifestBuilder;
+ final String manifestContent = manifestBuilder.build();
+ addFile(getManifestPath(), manifestContent.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public boolean isEmpty() {
+ return fileMap.isEmpty();
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/NsdCsarEtsiOption2Signer.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/NsdCsarEtsiOption2Signer.java
new file mode 100644
index 0000000000..abba32ad8d
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/NsdCsarEtsiOption2Signer.java
@@ -0,0 +1,151 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.security;
+
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.security.cert.Certificate;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.openecomp.sdc.be.csar.security.api.CertificateManager;
+import org.openecomp.sdc.be.csar.security.api.CmsContentSigner;
+import org.openecomp.sdc.be.csar.security.api.model.CertificateInfo;
+import org.openecomp.sdc.be.csar.security.exception.CmsSignatureException;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.builder.NsdCsarManifestBuilder;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.NsdCsar;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.security.exception.NsdSignatureException;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.security.exception.NsdSignatureExceptionSupplier;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+/**
+ * Handles NSD CSAR file and package signature, following the ETSI SOL007 v3.3.1, section 5.1, signing option 2.
+ *
+ * @see <a href="https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/007/03.03.01_60/gs_NFV-SOL007v030301p.pdf">ETSI SOL007 v3.3.1 documentation</a>
+ */
+@Component
+public class NsdCsarEtsiOption2Signer {
+
+ public static final String SDC_NSD_CERT_NAME = "SDC_NSD_CERT_NAME";
+ public static final String SIGNATURE_EXTENSION = ".sig.cms";
+
+ private final CertificateManager certificateManager;
+ private final CmsContentSigner cmsContentSigner;
+ private final Environment environment;
+
+ public NsdCsarEtsiOption2Signer(final CertificateManager certificateManager,
+ final CmsContentSigner cmsContentSigner,
+ final Environment environment) {
+ this.certificateManager = certificateManager;
+ this.cmsContentSigner = cmsContentSigner;
+ this.environment = environment;
+ }
+
+ /**
+ * Sign each NSD CSAR artifact (files), generating a cms file for each. The manifest, though, have its signature added in its body instead of a separate
+ * CMS file. Modifies the given NSD CSAR by adding the file signatures and the modified manifest.
+ *
+ * @param nsdCsar the NSD CSAR
+ * @throws NsdSignatureException when there was a problem while creating a file signature
+ */
+ public void signArtifacts(final NsdCsar nsdCsar) throws NsdSignatureException {
+ if (nsdCsar == null) {
+ return;
+ }
+ //ignore the manifest, the signature of the manifest goes inside the manifest itself ETSI 3.3.1 section 5.3
+ final Map<String, byte[]> fileMap = nsdCsar.getFileMap().entrySet().stream()
+ .filter(entry -> !nsdCsar.isManifest(entry.getKey()))
+ .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+
+ for (final Entry<String, byte[]> fileEntry : fileMap.entrySet()) {
+ final byte[] signatureBytes = sign(fileEntry.getValue());
+ final String filePath = fileEntry.getKey();
+ nsdCsar.addFile(filePath + SIGNATURE_EXTENSION, signatureBytes);
+ }
+
+ signManifest(nsdCsar);
+ }
+
+ private void signManifest(final NsdCsar nsdCsar) throws NsdSignatureException {
+ final Optional<Entry<String, byte[]>> manifestEntryOpt = nsdCsar.getFileMap().entrySet().stream()
+ .filter(entry -> nsdCsar.isManifest(entry.getKey())).findFirst();
+ if (manifestEntryOpt.isEmpty()) {
+ return;
+ }
+ final CertificateInfo certificateInfo = getValidCertificate();
+
+ final Entry<String, byte[]> manifestEntry = manifestEntryOpt.get();
+ final String pemSignature = createFileSignature(certificateInfo.getCertificate(),
+ certificateInfo.getPrivateKey(), manifestEntry.getValue());
+ final NsdCsarManifestBuilder manifestBuilder = nsdCsar.getManifestBuilder();
+ manifestBuilder.withSignature(pemSignature);
+ nsdCsar.addManifest(manifestBuilder);
+ }
+
+ /**
+ * Sign a file, creating the PEM format signature and returning its bytes.
+ *
+ * @param fileBytes the file to sign
+ * @return the bytes of the PEM format signature created from the given file and the NSD certificate
+ * @throws NsdSignatureException when it was not possible to retrieve the NSD certificate
+ * @throws NsdSignatureException when the NSD certificate is invalid
+ * @throws NsdSignatureException it was not possible to sign the file
+ */
+ public byte[] sign(final byte[] fileBytes) throws NsdSignatureException {
+ final CertificateInfo certificateInfo = getValidCertificate();
+ final String pemSignature =
+ createFileSignature(certificateInfo.getCertificate(), certificateInfo.getPrivateKey(), fileBytes);
+ return pemSignature.getBytes(StandardCharsets.UTF_8);
+ }
+
+ public Optional<CertificateInfo> getSigningCertificate() {
+ final String sdcNsdCertName = environment.getProperty(SDC_NSD_CERT_NAME);
+ return certificateManager.getCertificate(sdcNsdCertName);
+ }
+
+ public boolean isCertificateConfigured() {
+ return getSigningCertificate().isPresent();
+ }
+
+ private CertificateInfo getValidCertificate() throws NsdSignatureException {
+ final Optional<CertificateInfo> certificateInfoOpt = getSigningCertificate();
+ if (certificateInfoOpt.isEmpty()) {
+ throw NsdSignatureExceptionSupplier.certificateNotConfigured();
+ }
+ final CertificateInfo certificateInfo = certificateInfoOpt.get();
+ if (!certificateInfo.isValid()) {
+ throw NsdSignatureExceptionSupplier.invalidCertificate(certificateInfo.getName());
+ }
+
+ return certificateInfo;
+ }
+
+ private String createFileSignature(final Certificate certificate, final Key privateKey,
+ final byte[] fileBytes) throws NsdSignatureException {
+ try {
+ final byte[] dataSignature = cmsContentSigner.signData(fileBytes, certificate, privateKey);
+ return cmsContentSigner.formatToPemSignature(dataSignature);
+ } catch (final CmsSignatureException e) {
+ throw NsdSignatureExceptionSupplier.unableToCreateSignature(e);
+ }
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureException.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureException.java
new file mode 100644
index 0000000000..1591a5e294
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureException.java
@@ -0,0 +1,31 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.security.exception;
+
+public class NsdSignatureException extends Exception {
+
+ public NsdSignatureException(final String message) {
+ super(message);
+ }
+
+ public NsdSignatureException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureExceptionSupplier.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureExceptionSupplier.java
new file mode 100644
index 0000000000..696a8d8626
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/security/exception/NsdSignatureExceptionSupplier.java
@@ -0,0 +1,39 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.security.exception;
+
+public final class NsdSignatureExceptionSupplier {
+
+ private NsdSignatureExceptionSupplier() {
+ }
+
+ public static NsdSignatureException invalidCertificate(final String certificateName) {
+ return new NsdSignatureException(String.format("The certificate '%s' is invalid", certificateName));
+ }
+
+ public static NsdSignatureException certificateNotConfigured() {
+ return new NsdSignatureException("No certificate configured");
+ }
+
+ public static NsdSignatureException unableToCreateSignature(final Exception e) {
+ return new NsdSignatureException("Could create file signature", e);
+ }
+
+} \ No newline at end of file