bf029fb29ef318eed64d3c6fa9d18e544efb6b3f
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019, Nordix Foundation. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdcrests.vsp.rest.data;
21
22 import org.apache.commons.io.FilenameUtils;
23 import org.apache.commons.lang3.tuple.Pair;
24 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
25 import org.openecomp.core.utilities.file.FileContentHandler;
26 import org.openecomp.sdc.common.utils.CommonUtil;
27 import org.openecomp.sdc.logging.api.Logger;
28 import org.openecomp.sdc.logging.api.LoggerFactory;
29 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
30 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
31
32 import java.io.IOException;
33 import java.security.cert.CertificateException;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Optional;
37
38 /**
39  * Class responsible for processing zip archive and verify if this package corresponds
40  * SOL004 option 2 signed package format, verifies the cms signature if package is signed
41  */
42 public class PackageArchive {
43     private static final Logger LOG = LoggerFactory.getLogger(PackageArchive.class);
44     private static final String[] ALLOWED_ARCHIVE_EXTENSIONS = {"csar", "zip"};
45     private static final String[] ALLOWED_SIGNATURE_EXTENSIONS = {"cms"};
46     private static final String[] ALLOWED_CERTIFICATE_EXTENSIONS = {"cert"};
47     private static final int NUMBER_OF_FILES_FOR_SIGNATURE_WITH_CERT_INSIDE = 2;
48     private static final int NUMBER_OF_FILES_FOR_SIGNATURE_WITHOUT_CERT_INSIDE = 3;
49     private final SecurityManager securityManager;
50     private final byte[] outerPackageFileBytes;
51     private Pair<FileContentHandler, List<String>> handlerPair;
52
53     public PackageArchive(Attachment uploadedFile) {
54         this(uploadedFile.getObject(byte[].class));
55     }
56
57     public PackageArchive(byte[] outerPackageFileBytes) {
58         this.outerPackageFileBytes = outerPackageFileBytes;
59         this.securityManager = SecurityManager.getInstance();
60         try {
61             handlerPair = CommonUtil.getFileContentMapFromOrchestrationCandidateZip(
62                     outerPackageFileBytes);
63         } catch (IOException exception) {
64             LOG.error("Error reading files inside archive", exception);
65         }
66     }
67
68     /**
69      * Checks if package matches required format {package.csar/zip, package.cms, package.cert(optional)}
70      *
71      * @return true if structure matches sol004 option 2 structure
72      */
73     public boolean isSigned() {
74         return isPackageSizeMatches() && getSignatureFileName().isPresent();
75     }
76
77     /**
78      * Gets csar/zip package name with extension only if package is signed
79      *
80      * @return csar package name
81      */
82     public Optional<String> getArchiveFileName() {
83         if (isSigned()) {
84             return getFileByExtension(ALLOWED_ARCHIVE_EXTENSIONS);
85         }
86         return Optional.empty();
87     }
88
89     /**
90      * Gets csar/zip package content from zip archive
91      * @return csar package content
92      * @throws SecurityManagerException
93      */
94     public byte[] getPackageFileContents() throws SecurityManagerException {
95         try {
96             if (isSignatureValid()) {
97                 return handlerPair.getKey().getFiles().get(getArchiveFileName().orElseThrow(CertificateException::new));
98             }
99         } catch (CertificateException exception) {
100             LOG.info("Error verifying signature " + exception);
101         }
102         return outerPackageFileBytes;
103     }
104
105     /**
106      * Validates package signature against trusted certificates
107      * @return true if signature verified
108      * @throws SecurityManagerException
109      */
110     public boolean isSignatureValid() throws SecurityManagerException {
111         Map<String, byte[]> files = handlerPair.getLeft().getFiles();
112         Optional<String> signatureFileName = getSignatureFileName();
113         Optional<String> archiveFileName = getArchiveFileName();
114         if (files.isEmpty() || !signatureFileName.isPresent() || !archiveFileName.isPresent()) {
115             return false;
116         }
117         Optional<String> certificateFile = getCertificateFileName();
118         if(certificateFile.isPresent()){
119             return securityManager.verifySignedData(files.get(signatureFileName.get()),
120                     files.get(certificateFile.get()), files.get(archiveFileName.get()));
121         }else {
122             return securityManager.verifySignedData(files.get(signatureFileName.get()),
123                     null, files.get(archiveFileName.get()));
124         }
125     }
126
127     private boolean isPackageSizeMatches() {
128         return handlerPair.getRight().isEmpty()
129                 && (handlerPair.getLeft().getFiles().size() == NUMBER_OF_FILES_FOR_SIGNATURE_WITH_CERT_INSIDE
130                 || handlerPair.getLeft().getFiles().size() == NUMBER_OF_FILES_FOR_SIGNATURE_WITHOUT_CERT_INSIDE);
131     }
132
133     private Optional<String> getSignatureFileName() {
134         return getFileByExtension(ALLOWED_SIGNATURE_EXTENSIONS);
135     }
136
137     private Optional<String> getFileByExtension(String[] extensions) {
138         for (String fileName : handlerPair.getLeft().getFileList()) {
139             for (String extension : extensions) {
140                 if (extension.equalsIgnoreCase(FilenameUtils.getExtension(fileName))) {
141                     return Optional.of(fileName);
142                 }
143             }
144         }
145         return Optional.empty();
146     }
147
148     private Optional<String> getCertificateFileName() {
149         Optional<String> certFileName = getFileByExtension(ALLOWED_CERTIFICATE_EXTENSIONS);
150         if(!certFileName.isPresent()){
151             return Optional.empty();
152         }
153         String certNameWithoutExtension = FilenameUtils.removeExtension(certFileName.get());
154         if (certNameWithoutExtension.equals(FilenameUtils.removeExtension(getArchiveFileName().orElse("")))) {
155             return certFileName;
156         }
157         //cert file name should be the same as package name, e.g. vnfpackage.scar-->vnfpackage.cert
158         return Optional.empty();
159     }
160 }